Android11 SystemUI解析

       在上篇文章Android11 最近任务Recents功能分析过程中,针对SystemUI内部功能逻辑变化,发现在进程启动过程中有新的变化,比如AppComponentFactory的引入,在Android系统中,有些核心应用需要开机就启动,就像SystemUI;
       SystemUI进程是Android系统中一个核心进程,StatusBar和NavigationBar等逻辑都是来SystemUI进程里面处理的,本文针对Android11版本对SystemUI启动过程进行分析:

一.启动入口

       Android系统在启动时,会启动system_server进程,接着会调用到SystemServer.java中的main()方法,简单回忆一下:

public static void main(String[] args) {
    new SystemServer().run();
}

       接下来会调用到run()方法:

private void run() {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    // Start services.
    try {
        startBootstrapServices(t);
        startCoreServices(t);
        startOtherServices(t);
     } 
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
}

       在run()内部会start services(),包括启动一些核心的服务包括AMS、WMS、PMS等,在startOtherServices()里面会调用到startSystemUi(),看一下该方法的具体实现:

private static void startSystemUi(Context context, WindowManagerService windowManager) {
    PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
    Intent intent = new Intent();
    intent.setComponent(pm.getSystemUiServiceComponent());
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    context.startServiceAsUser(intent, UserHandle.SYSTEM);
    windowManager.onSystemUiStarted();
}

       可以看到,在startSystemUi()内部启动了一个service,该service对应的详细参数是通过getSystemUiServiceComponent()来获取的,该方法具体实现是在PackageManagerService.java里面:

@Override
public ComponentName getSystemUiServiceComponent() {
    return ComponentName.unflattenFromString(mContext.getResources().getString(
                com.android.internal.R.string.config_systemUIServiceComponent));
}
<!-- SystemUi service component -->
<string name="config_systemUIServiceComponent" translatable="false"
        >com.android.systemui/com.android.systemui.SystemUIService</string>

       可以看到,getSystemUiServiceComponent()获取的ComponentName对应的service Intent是SystemUIService,即启动了SystemUIService;
       通过以上可以看到:在system_server进程启动后,会调用startServiceAsUser()来启动SystemUIService,即启动了SystemUI进程。

二.进程启动

       前面分析了是通过startService()来启动进程,关于startService()是如何启动进程的,startService()跟bindService()启动方式是类似的,可以参考之前分析过的文章Android 进程通信bindService详解,本文直接从ActivityThread来进行分析:

1.ActivityThread.java

       在进行启动时,会调用到main()方法,然后通过attachApplication()与AMS进行一系列交互后,会调用到handBindApplication()方法:

private void handleBindApplication(AppBindData data) {
    ;;;;;;;;;;;;;;;;;;;;;;;;
    Application app;
    app = data.info.makeApplication(data.restrictedBackupMode, null);
    ;;;;;;;;;;;;;;;;;;;;
    try {
        mInstrumentation.callApplicationOnCreate(app);
    } catch (Exception e) {

   }
}

       data.info对应的是LoadedApk,通过LoadedApk的makeApplication()来创建Application实例,然后通过Instrumentation的callApplicationOnCreate(app)来回调Application的onCreate()方法,先看一下makeApplication()方法:

2.LoadedApk.java

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
    ;;;;;;;;;;;;;;
    Application app = null;
    String appClass = mApplicationInfo.className;
    try {
        ;;;;;;;;;;;;;;;;;;;;;;;;;
        app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;

    return app;
}

public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
            CompatibilityInfo compatInfo, ClassLoader baseLoader,
            boolean securityViolation, boolean includeCode, boolean registerPackage) {

    mActivityThread = activityThread;
    ;;;;;;;;;;;;;;;;;;;;;;
    mAppComponentFactory = createAppFactory(mApplicationInfo, mBaseClassLoader);
}

       可以看到,makeApplication()内部还是通过Instrucmentation的newApplication()来创建的Application实例,看一下Instrucmentation内部的实现:

3.Instrumentation.java

public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
    app.attach(context);
    return app;
}

       可以看到,在newApplication()内部获取Application实例经过了两步操作:
       1.先执行getFactory()获取AppComponentFactory实例;
       2.执行instantiateApplication()来获取Application实例;
       对比Android8.1发现,Android8.1直接调用Application app = (Application)clazz.newInstance(),接下来先看一下getFactory()实现:

private AppComponentFactory getFactory(String pkg) {
    ;;;;;;;;;;;;;;;;;;;;;;;;;
    LoadedApk apk = mThread.peekPackageInfo(pkg, true);
    ;;;;;;;;;;;;;;;;;;;;
    return apk.getAppFactory();
}

       可以看到,getFactory()是通过LoadedApk来获取,根据调用关系看一下对应实现:

//LoadedApk.java
private AppComponentFactory mAppComponentFactory;
public AppComponentFactory getAppFactory() {
    return mAppComponentFactory;
}

       getAppFactory()返回的是AppComponentFactory实例,该实例是在LoadedApk的构造方法内部就执行了createAppFactory()进行创建,关于AppComponentFactory,后面再进行分析,先看一下createAppFactory():

//LoadedApk.java
private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
    if (mIncludeCode && appInfo.appComponentFactory != null && cl != null) {
        try {
            return (AppComponentFactory)
                        cl.loadClass(appInfo.appComponentFactory).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            Slog.e(TAG, "Unable to instantiate appComponentFactory", e);
        }
    }
    return AppComponentFactory.DEFAULT;
}

       在方法内部会先进行判断,mIncludeCode是true,classloader不为null,最后决定条件就是appInfo.appComponentFactory是否为null,如果不为null,则会通过ClassLoader去加载对应的类进行创建实例,如果为null,则直接返回AppComponentFactory DEFAULT实例;接下来需要知道的有两点:
       1.AppComponentFactory是什么?
       2.appInfo.appComponentFactory获取的什么内容?

4.AppComponentFactory.java

/**
 * Interface used to control the instantiation of manifest elements.
 *
 * @see #instantiateApplication
 * @see #instantiateActivity
 * @see #instantiateClassLoader
 * @see #instantiateService
 * @see #instantiateReceiver
 * @see #instantiateProvider
 */
public class AppComponentFactory {
    /**
     * Allows application to override the creation of the application object. This can be used to
     * perform things such as dependency injection or class loader changes to these
     * classes.
     * <p>
     * This method is only intended to provide a hook for instantiation. It does not provide
     * earlier access to the Application object. The returned object will not be initialized
     * as a Context yet and should not be used to interact with other android APIs.
     *
     * @param cl        The default classloader to use for instantiation.
     * @param className The class to be instantiated.
     */
    public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Application) cl.loadClass(className).newInstance();
    }
    ;;;;;;;;;;;;;;;;;;;;;;
}

       通过类注释可以看到:用来控制清单文件元素实例话的接口
       本文只看instantiateApplication(),方法注释:允许应用程序重写应用程序对象的创建,可以用来对这些类执行依赖项注入或类装入器更改等操作此方法仅用于提供用于实例化的hook。它不提供对应用程序对象的早期访问。返回的对象尚未初始化为上下文,不应用于与其他android API交互;instantiateApplication()最终返回的是Application实例;
       简单总结一下:允许应用内部创建AppComponentFactory的实现类,重写instantiateApplication()在内部做一下inject工作,由于在实例化时还未attach(context),所以不能执行上下文操作等交互逻辑;
       接下来就是看SystemUI内部的具体实现,appComponentFactory是如何在AndroidManifest.xml中使用的?是如何实现的AppComponentFactory类?

三.具体实现

       先看一下SystemUI的AndroidManifest.xml文件:

1.AndroidManifest.xml

<application
    android:name=".SystemUIApplication"
    android:persistent="true"
    ;;;;;;;;;;;;;;;;;;;;
    android:appComponentFactory=".SystemUIAppComponentFactory">
        
    <service android:name="SystemUIService"android:exported="true"/>
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>

       可以看到,在application标签下加入了 android:appComponentFactory=".SystemUIAppComponentFactory",PMS会将android:appComponentFactory解析到appInfo.appComponentFactory,所以前面在newApplication()内部getFactory()返回的是SystemUIAppComponentFactory实例,一起看一下SystemUIAppComponentFactory的具体实现:

2.SystemUIAppComponentFactory.java

import androidx.core.app.AppComponentFactory;
public class SystemUIAppComponentFactory extends AppComponentFactory {
    @Inject
    public ContextComponentHelper mComponentHelper;
    public SystemUIAppComponentFactory() {
        super();
    }

    @NonNull
    @Override
    public Application instantiateApplicationCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = super.instantiateApplicationCompat(cl, className);
        if (app instanceof ContextInitializer) {
            ((ContextInitializer) app).setContextAvailableCallback(
                    context -> {
                        SystemUIFactory.createFromConfig(context);
                        SystemUIFactory.getInstance().getRootComponent().inject(
                                SystemUIAppComponentFactory.this);
                    }
            );
        }

        return app;
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
}

       可以看到,SystemUIAppComponentFactory继承了AppComponentFactory,但是重写的是instantiateApplicationCompat(),而不是instantiateApplication()方法,注意一下:AppComponentFactory对应的是androidx.core.app.AppComponentFactory,而不是android.app.AppComponentFactory,前者继承了后者,对其进行了实现后暴露了instantiateApplicationCompat()方法,看一下androidx.core.app.AppComponentFactory实现:

@RequiresApi(28)
public class AppComponentFactory extends android.app.AppComponentFactory {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    /**
     * @see #instantiateApplicationCompat
     */
    @Override
    public final Application instantiateApplication(ClassLoader cl, String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return checkCompatWrapper(instantiateApplicationCompat(cl, className));
    }

    public @NonNull Application instantiateApplicationCompat(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        try {
            return (Application) cl.loadClass(className).getDeclaredConstructor().newInstance();
        } catch (InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException("Couldn't call constructor", e);
        }
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
}

       在instantiateApplication()内部会调用instantiateApplicationCompat(),然后创建Application实例;接着上面分析,在SystemUIAppComponentFactory的instantiateApplicationCompat()内部会执行三项工作:
       1.调用父类方法来实例化Application;
       2.调用app的setContextAvailableCallback()方法,里面会有回调方法,SystemUIApplication实现了ContextInitializer接口;
       3.返回Application实例;

 /**
  * A callback that receives a Context when one is ready.
  */
    public interface ContextAvailableCallback {
        void onContextAvailable(Context context);
    }

    /**
     * Implemented in classes that get started by the system before a context is available.
     */
    public interface ContextInitializer {
        void setContextAvailableCallback(ContextAvailableCallback callback);
    }

       关于方法回调,一会再讲,先看一下SystemUIApplication的实现:

3.SystemUIApplication.java

public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {

    private ContextComponentHelper mComponentHelper;
    ;;;;;;;;;;;;;;;;;;;;;;
    private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
    private SystemUIRootComponent mRootComponent;
    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG, "SystemUIApplication created.");
        mContextAvailableCallback.onContextAvailable(this);
        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
        mComponentHelper = mRootComponent.getContextComponentHelper();
        mBootCompleteCache = mRootComponent.provideBootCacheImpl();
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    }

    @Override
    public void setContextAvailableCallback(
            SystemUIAppComponentFactory.ContextAvailableCallback callback) {
        mContextAvailableCallback = callback;
    }

       前面在分析ActivityThread相关的逻辑时讲到,在handlebindApplication()时,先创建application实例,然后attach(context),最后执行onCreate(),根据SystemUIAppComponentFactory内部的执行逻辑可以看到,在instantiateApplicationCompat()内部先创建application对象,然后执行setContextAvailableCallback()赋值给SystemUIApplication,当SystemUIApplication执行到onCreate()时,执行onContextAvailable()回调,然后SystemUIAppComponentFactory内部执行初始化逻辑:

//SystemUIAppComponentFactory.java
if (app instanceof ContextInitializer) {
    ((ContextInitializer) app).setContextAvailableCallback(
            context -> {
                SystemUIFactory.createFromConfig(context);
                SystemUIFactory.getInstance().getRootComponent().inject(
                                SystemUIAppComponentFactory.this);
            }
    );
}

       在回调中主要执行了两项工作,都与SystemUIFactory有关,一起来看一下SystemUIFactory实现:

4.SystemUIFactory.java

public class SystemUIFactory {
     public static void createFromConfig(Context context) {
        if (mFactory != null) {
            return;
        }

        final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
        if (clsName == null || clsName.length() == 0) {
            throw new RuntimeException("No SystemUIFactory component configured");
        }

        try {
            Class<?> cls = null;
            cls = context.getClassLoader().loadClass(clsName);
            mFactory = (SystemUIFactory) cls.newInstance();
            mFactory.init(context);
        } catch (Throwable t) {
            Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);
            throw new RuntimeException(t);
        }
    }

       在createFromConfig()内部,会创建SystemUIFactory实例,然后执行init()方法,context对应的是SystemUIApplication this对象;

private void init(Context context) {
    mRootComponent = buildSystemUIRootComponent(context);

    // Every other part of our codebase currently relies on Dependency, so we
    // really need to ensure the Dependency gets initialized early on.

    Dependency dependency = new Dependency();
    mRootComponent.createDependency().createSystemUI(dependency);
    dependency.start();
}

       在init()内部主要执行了四项工作:
       1.通过buildSystemUIRootComponent()获取SystemUIRootComponent对象;
       2.创建Dependency实例;
       3.执行createSystemUI():初始化Dependency内部含@Inject的变量;
       4.执行Dependency的start()方法;
       接着上面SystemUIAppComponentFactory回调方法分析,在执行完SystemUIFactory.createFromConfig(),会执行
SystemUIFactory.getInstance().getRootComponent().inject(SystemUIAppComponentFactory.this):初始化SystemUIAppComponentFactory内部含@Inject的变量;
       以上涉及到dagger2知识,主要是为了解耦,用了APT(注解处理器),在编译时帮忙生成许多类来简化代码,加上注解后,会自动帮忙创建类对象等,这里就不展开讲了,主要是完成了一些初始化工作
       前面讲到,system_server是通过startServiceAsUser()来启动的SystemUI进程,在SystemUIApplication初始化后完成后,会执行到SystemUISerivice里面的逻辑:

5.SystemUIService.java

public class SystemUIService extends Service {
    ;;;;;;;;;;;;;;;;;;;;;;
    @Override
    public void onCreate() {
        super.onCreate();

        // Start all of SystemUI
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();

        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    }
}

       可以看到,在SystemUIService的onCreate()内部,会获取到SystemUIApplication实例,然后执行startServicesIfNeeded():

//SystemUIApplication
public void startServicesIfNeeded() {
    String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
    startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}

//SystemUIFactory.java
public String[] getSystemUIServiceComponents(Resources resources) {
    return resources.getStringArray(R.array.config_systemUIServiceComponents);
}

<!-- SystemUI Services: The classes of the stuff to start. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    <item>com.android.systemui.recents.Recents</item>
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    <item>com.android.systemui.statusbar.phone.StatusBar</item>
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
</string-array>

       获取到的systemUIServiceComponents是一些实现了SystemUI的类,然后调用startServicesIfNeeded():

//SystemUIApplication.java
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
    if (mServicesStarted) {
        return;
    }
    mServices = new SystemUI[services.length];

    ;;;;;;;;;;;;;;;;;;;;;;;;;
    final int N = services.length;
    for (int i = 0; i < N; i++) {
        String clsName = services[i];
        try {
            SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
            if (obj == null) {
                Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                obj = (SystemUI) constructor.newInstance(this);
            }
            mServices[i] = obj;
        }

        mServices[i].start();
        if (mBootCompleteCache.isBootComplete()) {
            mServices[i].onBootCompleted();
        }
    }

    mServicesStarted = true;
}

       可以看到,在startServicesIfNeeded()会进行遍历来创建SystemUI子类对象,然后将实例赋值给mServices数组,接着执行start()方法,最后执行onBootCompleted();
       用一张流程图总结一下:


image.png

       以上就是SystemUI进程启动的主要流程,SystemUI相关的子类进行各种逻辑初始化处理都是在start()及onBootCompleted()里面进行。

四.CarSystemUI

       CarSystemUI是针对Car独立定制的SystemUI,即继承了SystemUI的属性,又有自己独特的属性,接下来一起看一下:

1.与SystemUI的关系

       先看一下framework/base/packages/CarSystemUI/Android.bp:

android_app {
    name: "CarSystemUI",

    static_libs: [
        "CarSystemUI-core",
    ],

     overrides: [
        "SystemUI",
    ],

    platform_apis: true,
    system_ext_specific: true,
    certificate: "platform",
    privileged: true,
    ..................
    ..................
}

       可以看到,是对SystemUI进行了覆盖,再看一下依赖库CarSystemUI-core的编译实现:

android_library {
    name: "CarSystemUI-core",

    srcs: [
        "src/**/*.java",
        "src/**/I*.aidl",
    ],

    resource_dirs: [
        "res-keyguard",
        "res",
    ],

    static_libs: [
        "SystemUI-core",
        "CarNotificationLib",
        "SystemUIPluginLib",
        "SystemUISharedLib",
        "SettingsLib",
        "car-ui-lib",
        ........................
   ],

    libs: [
        "android.car",
    ],

    manifest: "AndroidManifest.xml",
    plugins: ["dagger2-compiler-2.19"],
}

       CarSystemUI-core包含当前src和res,并且依赖SystemUI-core库,所以CarSystemUI包含了SystemUI所有的资源。

2.独特属性

       前面分析到,在SystemUIService会通过SystemUIApplication的startServicesIfNeeded()来启动一些SystemUI的子类,再回忆一下这个方法:

public void startServicesIfNeeded() {
    String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
    startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}

       此处通过createFromConfig()来创建SystemUIFactory对象时,返回的是CarSystemUIFactory实例,对应的实现如下:

<string name="config_systemUIFactoryComponent" translatable="false">
        com.android.systemui.CarSystemUIFactory
</string>

       那么看一下CarSystemUIFactory对应的getSystemUIServiceComponents()实现:

public String[] getSystemUIServiceComponents(Resources resources) {
    Set<String> names = new HashSet<>();
    for (String s : super.getSystemUIServiceComponents(resources)) {
        names.add(s);
    }

    for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsExclude)) {
        names.remove(s);
    }

    for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsInclude)) {
        names.add(s);
    }

    String[] finalNames = new String[names.size()];
    names.toArray(finalNames);

    return finalNames;
}

       可以看到,在该方法内部,会先调用SystemUI的对应方法来获取names,接着移除了一些names,然后又加入了一些names,最后封装成自己需要启动的SystemUI子类集合,看一下Exclue及Include的定义:

<string-array name="config_systemUIServiceComponentsExclude" translatable="false">
    <item>com.android.systemui.recents.Recents</item>
    ......................
    <item>com.android.systemui.statusbar.phone.StatusBar</item>
    .......................
</string-array>

<string-array name="config_systemUIServiceComponentsInclude" translatable="false">
    <item>com.android.systemui.car.navigationbar.CarNavigationBar</item>
    .............
<item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
    ..................
</string-array>

       可以看到,在CarSystemUI内部将Recents及StatusBar等元素都禁用了,增加了CarNavigationBar及SystemUIOverlayWindowManager等元素,接下来分析一下:

2.1.StatusBar和Recents

       禁用状态栏,相关实现由CarNavigationBar来实现,禁用Recents;

2.2.CarNavigationBar

public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
    .................
    .................
    // Nav bar views.
    private ViewGroup mTopNavigationBarWindow;
    private ViewGroup mBottomNavigationBarWindow;
    private ViewGroup mLeftNavigationBarWindow;
    private ViewGroup mRightNavigationBarWindow;
    private CarNavigationBarView mTopNavigationBarView;
    private CarNavigationBarView mBottomNavigationBarView;
    private CarNavigationBarView mLeftNavigationBarView;
    private CarNavigationBarView mRightNavigationBarView;
    ...............
    private void createNavigationBar(RegisterStatusBarResult result) {
        buildNavBarWindows();
        buildNavBarContent();
        attachNavBarWindows();

        // Try setting up the initial state of the nav bar if applicable.
        if (result != null) {
            setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken,
                    result.mImeWindowVis, result.mImeBackDisposition,
                    result.mShowImeSwitcher);
        }
    }

    private void buildNavBarContent() {
        mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
        if (mTopNavigationBarView != null) {
            mTopNavigationBarWindow.addView(mTopNavigationBarView);
        }

        mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
        if (mBottomNavigationBarView != null) {
            mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
        }

        mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
        if (mLeftNavigationBarView != null) {
            mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
        }

        mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
        if (mRightNavigationBarView != null) {
            mRightNavigationBarWindow.addView(mRightNavigationBarView);
        }
    }
    ....................
}

       可以看到,在CarNavigationBar内部可以显示4个NavigationBarWindow,可以对其进行配置,默认配置如下:

<bool name="config_enableTopNavigationBar">true</bool>
<bool name="config_enableLeftNavigationBar">false</bool>
<bool name="config_enableRightNavigationBar">false</bool>
<bool name="config_enableBottomNavigationBar">true</bool>

       默认是顶部和底部NavigationBar是显示的,顶部NavigationBar包含左右两边两个空调温度的按钮,点击后通知 com.android.car.hvac显示相关窗口,中间的时间按钮点击后展开设置中的快速设置,下拉显示通知;底部NavigationBar包含了7个CarNavigationButton,点击会进入对应的实现。

2.3.SystemUIOverlayWindowManager

public class SystemUIOverlayWindowManager extends SystemUI {
    ..................
    private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
    ...................
    @Inject
    public SystemUIOverlayWindowManager(
            Context context,
            Map<Class<?>, Provider<OverlayViewMediator>> contentMediatorCreators,
            OverlayViewGlobalStateController overlayViewGlobalStateController) {
        super(context);
        mContentMediatorCreators = contentMediatorCreators;
        mOverlayViewGlobalStateController = overlayViewGlobalStateController;
    }

    @Override
    public void start() {
        String[] names = mContext.getResources().getStringArray(
                R.array.config_carSystemUIOverlayViewsMediators);
        startServices(names);
    }
    
    private void startServices(String[] services) {
        for (String clsName : services) {
            long ti = System.currentTimeMillis();
            try {
                OverlayViewMediator obj = resolveContentMediator(clsName);
                if (obj == null) {
                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                    obj = (OverlayViewMediator) constructor.newInstance(this);
                }
                mOverlayViewGlobalStateController.registerMediator(obj);
            } 
            ..................
        }
    }

       在构造方法内,会实例化OverlayViewGlobalStateController,在start()内部会获取config_carSystemUIOverlayViewsMediators,看一下实现:

    <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
        <item>@string/config_notificationPanelViewMediator</item>
        <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
       <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
        <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
    </string-array>

<string name="config_notificationPanelViewMediator" translatable="false">
com.android.systemui.car.notification.TopNotificationPanelViewMediator</string>

       实例化了OverlayViewMediator子类,并通过OverlayViewGlobalStateController的registerMediator进行注册,TopNotificationPanelViewMediator主要用来下拉显示通知;

2.4.OverlayViewGlobalStateController

       管理SystemUIOverlayWindow,比如下拉通知就是通过该类来进行相关显示或隐藏的;

2.5.NotificationPanelViewController

       控制通知中心

2.6.CarNavigationBarView

       NavigationBar对应的View

2.7.CarNavigationBarController

       控制NavigationBar的显示及隐藏等;

2.8.CarNavigationButton

       NavigationBar上显示的按钮;
       以上大概介绍了CarSystemUI的相关属性,详细了解需要进一步阅读源码!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容