Android 12系统源码_SystemUI(五)自定义状态栏和导航栏视图

羊禄
2023-12-01

前言

前面几篇文章我们具体分析了Android12系统原生的StatusBar和CarStatusBar的启动流程以及视图构建流程,本篇文章我们来自定义实现状态栏和导航栏视图。

一、为系统添加自定义状态栏类

1、修改CarSystemUI项目中的config.xml配置文件的config_systemUIServiceComponentsInclude字段,让CarSystemUI模块默认不是启动CarSystemBar,而是启动我们新建的LPCarSystemBar。

packages/apps/Car/SystemUI/res/values/config.xml

    <string-array name="config_systemUIServiceComponentsInclude" translatable="false">
        <!--<item>com.android.systemui.car.systembar.CarSystemBar</item>-->
        <item>com.lp.systemui.LPCarSystemBar</item>
        <item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
        <item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
        <item>com.android.systemui.car.toast.CarToastUI</item>
        <item>com.android.systemui.car.volume.VolumeUI</item>
        <item>com.android.systemui.car.cluster.ClusterDisplayController</item>
    </string-array>

2、在CarSystemUI项目里面新建一个类,并在该类中构建状态栏和导航栏视图。

package/app/Car/SystemUI/src/com/lp/systemui/LPCarSystemBar.java

public class LPCarSystemBar extends SystemUI{

    private final WindowManager mWindowManager;
    //顶部状态栏
    private StatusBarViewHelper mStatusBarViewHelper;
    //底部Dock栏
    private DockBarViewHelper mDockBarViewHelper;

	//添加dagger2注解
    @Inject
    public LPCarSystemBar(Context context
            , WindowManager windowManager
            , StatusBarViewHelper statusBarViewHelper
            , DockBarViewHelper dockBarViewHelper
    ) {
        super(context);
        mWindowManager = windowManager;
        //状态栏
        mStatusBarViewHelper = statusBarViewHelper;
        //底部栏
        mDockBarViewHelper = dockBarViewHelper;
    }

    @Override
    public void start() {
        createSystemBar();
    }

    private void createSystemBar() {
        createTopCarSystemBar();//创建顶部栏
        createBottomCarSystemBar();//创建底部栏
    }

}

3、在修改完config.xml配置之后,SystemUIApplication的startServicesIfNeeded方法便会调用ContextComponentResolver的resolveSystemUI方法,尝试创建LPCarSystemBar对象实例,并调用该对象的start方法。

frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {
     private ContextComponentHelper mComponentHelper;
 	private void startServicesIfNeeded(String metricsPrefix, String[] services) {
    	...代码省略...     
        final int N = services.length;
        for (int i = 0; i < N; i++) {
            String clsName = services[i];//具体SystemUI组件类的完整路径
            ...代码省略...     
            SystemUI obj = mComponentHelper.resolveSystemUI(clsName);//ComponentHelper的resolveSystemUI方法可以通过类名拿到具体的SystemUI实例对象
            ...代码省略...     
            mServices[i].start();
    		...代码省略...      
        }
    }
}

为了让ContextComponentHelper可以成功获得LPCarSystemBar对象实例,我们还需修改Dagger2组件中的代码。

4、修改CarSystemUIBinder类代码,为Dagger2框架提供LPCarSystemBar对象实例。

packages/apps/Car/SystemUI/src/com/android/systemui/CarSystemUIBinder.java

@Module(includes = {RecentsModule.class, StatusBarModule.class, NotificationsModule.class,
        KeyguardModule.class, OverlayWindowModule.class, CarNotificationModule.class,
        QuickControlsEntryPointsModule.class})
public abstract class CarSystemUIBinder {

//    /** Inject Car Navigation Bar. */
//    @Binds
//    @IntoMap
//    @ClassKey(CarSystemBar.class)
//    public abstract SystemUI bindCarSystemBar(CarSystemBar sysui);

    /** Inject LPCar Navigation Bar. */
    @Binds
    @IntoMap
    @ClassKey(LPCarSystemBar.class)
    public abstract SystemUI bindLPCarSystemBar(LPCarSystemBar sysui);
}

二、构建自定义系统状态栏

1、新建一个状态栏视图管理类StatusBarViewHelper。

packages/apps/Car/SystemUI/src/com/lp/systemui/StatusBarViewHelper.java

public class StatusBarViewHelper{

    protected Context mContext;
    protected View mRootView;

	//为构造方法添加@Inject注解
    @Inject
    public StatusBarViewHelper(Context mContext) {
        this.mContext = mContext;
        mRootView = LayoutInflater.from(mContext).inflate(R.layout.lp_layout_status_bar_view, null, false);
    }

    public View getRootView() {
        return mRootView;
    }
    
    public void initView() {
    	//初始化视图内容
    }
}

自定义状态栏相关的交互逻辑基本都可以写在StatusBarViewHelper这个类里面,lp_layout_status_bar_view.xml则是自定义状态栏所对应的布局文件,通过修改StatusBarViewHelper和lp_layout_status_bar_view.xml的布局内容,基本就能实现自定义状态栏视图的功能了。另外还需为StatusBarViewHelper的构造方法添加@Inject注解,这样Dagger2在构建LPCarSystemBar对象实例的时候,会通过构造方法为mStatusBarViewHelper属性赋值。

2、LPCarSystemBar和构建状态栏视图相关的代码如下所示。

public class LPCarSystemBar extends SystemUI{

    private final WindowManager mWindowManager;
    //顶部状态栏
    private StatusBarViewHelper mStatusBarViewHelper;
    private boolean mIsAddStatusBarViewToWindow = false;
    
	//添加dagger2注解
    @Inject
    public LPCarSystemBar(Context context
            , WindowManager windowManager
            , StatusBarViewHelper statusBarViewHelper
            , DockBarViewHelper dockBarViewHelper
    ) {
        super(context);
        mWindowManager = windowManager;
        //状态栏
        mStatusBarViewHelper = statusBarViewHelper;
        ...代码省略...
    }

    @Override
    public void start() {
        createSystemBar();
    }

    private void createSystemBar() {
        createTopCarSystemBar();
        ...代码省略...
    }
    
    private void createTopCarSystemBar() {
        //初始化顶部栏视图内容
        mStatusBarViewHelper.initView();
        //把顶部栏添加到窗口上
        addTopCarSystemBarToWindow();
    }

    /**
     * 把顶部栏添加到窗口上
     */
    private void addTopCarSystemBarToWindow() {
        if (mIsAddStatusBarViewToWindow) {
            return;
        }
        if (mStatusBarViewHelper != null) {
            //将顶部栏添加到Window中
            int statusBarHeight = 88;
            WindowManager.LayoutParams lpTopSystemBar = new WindowManager.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight,
                    WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
//                    WindowManager.LayoutParams.TYPE_STATUS_BAR,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
//                    PixelFormat.TRANSLUCENT);//半透明
                    PixelFormat.TRANSPARENT);//全透明
            lpTopSystemBar.setTitle("LPCarSystemBar");
            lpTopSystemBar.providesInsetsTypes = new int[]{InsetsState.ITYPE_STATUS_BAR, InsetsState.ITYPE_TOP_MANDATORY_GESTURES};
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                lpTopSystemBar.setFitInsetsTypes(0);
            }
            lpTopSystemBar.windowAnimations = 0;
            lpTopSystemBar.gravity = Gravity.TOP;
            mWindowManager.addView(mStatusBarViewHelper.getRootView(), lpTopSystemBar);
            mIsAddStatusBarViewToWindow = true;
        }
    }
}

在通过构造方法拿到StatusBarViewHelper对象并赋值给mStatusBarViewHelper之后,LPCarSystemBar的start方法会被调用,我们在该方法中调用createSystemBar方法,该方法会调用createTopCarSystemBar方法来创建状态栏视图,并调用addTopCarSystemBarToWindow方法将构建完成的视图添加到窗口中。

三、构建自定义系统底部栏

1、新建一个底部栏视图管理类DockBarViewHelper。

packages/apps/Car/SystemUI/src/com/lp/systemui/DockBarViewHelper.java

public class DockBarViewHelper{

    protected Context mContext;
    protected View mRootView;

	//为构造方法添加@Inject注解
    @Inject
    public DockBarViewHelper(Context mContext) {
        this.mContext = mContext;
        mRootView = LayoutInflater.from(mContext).inflate(R.layout.lp_layout_dock_bar_view, null, false);
    }

    public View getRootView() {
        return mRootView;
    }
    
    public void initView() {
    	//初始化视图内容
    }
}

自定义底部栏相关的交互逻辑基本都可以写在DockBarViewHelper这个类里面,lp_layout_dock_bar_view.xml则是自定义底部栏所对应的布局文件,通过修改StatusBarViewHelper和lp_layout_status_bar_view.xml的布局内容,基本就能实现自定义状态栏视图的功能了。另外还需为DockBarViewHelper的构造方法添加@Inject注解,这样Dagger2在构建LPCarSystemBar对象实例的时候,会通过构造方法为mDockBarViewHelper属性赋值。

2、LPCarSystemBar和构建底部栏视图相关的代码如下所示。

public class LPCarSystemBar extends SystemUI{

    private final WindowManager mWindowManager;
    //底部Dock栏
    private DockBarViewHelper mDockBarViewHelper;
    private boolean mIsAddDockBarViewToWindow = false;
	//添加dagger2注解
    @Inject
    public LPCarSystemBar(Context context
            , WindowManager windowManager
            , StatusBarViewHelper statusBarViewHelper
            , DockBarViewHelper dockBarViewHelper
    ) {
        super(context);
        mWindowManager = windowManager;
        ...代码省略...
        //底部栏
        mDockBarViewHelper = dockBarViewHelper;
    }

    @Override
    public void start() {
        createSystemBar();
    }

    private void createSystemBar() {
        ...代码省略...
        createBottomCarSystemBar();
    }
    
    /**
     * 创建底部栏
     */
    private void createBottomCarSystemBar() {
        //添加底部栏视图内容
        mDockBarViewHelper.initView();
        //把底部栏添加到窗口上
        addBottomCarSystemBarToWindow();
    }

    /**
     * 把底部栏添加到窗口上
     */
    private void addBottomCarSystemBarToWindow() {
        if (mIsAddDockBarViewToWindow) {
            return;
        }
        if (mDockBarViewHelper != null) {
            //将底部栏添加到Window中
            int navigationBarHeight = 112;//底部栏高度
            WindowManager.LayoutParams lpBottomSystemBar = new WindowManager.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, navigationBarHeight,
                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
//                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
//                    PixelFormat.TRANSLUCENT);//半透明
                    PixelFormat.TRANSPARENT);//全透明
            lpBottomSystemBar.setTitle("LPBottomCarSystemBar");
            lpBottomSystemBar.providesInsetsTypes = new int[]{InsetsState.ITYPE_NAVIGATION_BAR, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES};
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                lpBottomSystemBar.setFitInsetsTypes(0);
            }
            lpBottomSystemBar.windowAnimations = 0;
            lpBottomSystemBar.gravity = Gravity.BOTTOM;
            mWindowManager.addView(mDockBarViewHelper.getRootView(), lpBottomSystemBar);
            mIsAddDockBarViewToWindow = true;
        }
    }
}

在通过构造方法拿到StatusBarViewHelper对象并赋值给mStatusBarViewHelper之后,LPCarSystemBar的start方法会被调用,我们在该方法中调用createSystemBar方法,该方法会调用createBottomCarSystemBar方法来创建状态栏视图,并调用addBottomCarSystemBarToWindow方法将构建完成的视图添加到窗口中。

 类似资料: