Android笔记 SystemUI

 1.SystemUI的启动

从SystemServer开始

 frameworks/base/services/java/com/android/server/SystemServer.java

    private void startOtherServices() {
		...
        mActivityManagerService.systemReady(() -> {
			...
            traceBeginAndSlog("StartSystemUI");
            try {
                startSystemUi(context, windowManagerF);//启动SystemUIService
            } catch (Throwable e) {
                reportWtf("starting System UI", e);
            }
            traceEnd();
			...
    }

    ...

    static final void startSystemUi(Context context, WindowManagerService windowManager) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",
                    "com.android.systemui.SystemUIService"));
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        //Slog.d(TAG, "Starting service: " + intent);
        context.startServiceAsUser(intent, UserHandle.SYSTEM);
        windowManager.onSystemUiStarted();
    }

在startOtherServices()中,代码7行调startSystemUi方法,在该方法中,启动了SystemUIService,接着往下看SystemUIService.java

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

    @Override
    public void onCreate() {
        super.onCreate();
        ((SystemUIApplication) getApplication()).startServicesIfNeeded(); //关注这里

        // For debugging RescueParty
        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
            throw new RuntimeException();
        }
    }

SystemUIService服务起来后,onCreate()调用了SystemUIApplication的startServicesIfNeeded()方法 

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

    private final Class[] SERVICES = new Class[] {
            Dependency.class,
            NotificationChannels.class,
            CommandQueue.CommandQueueStart.class,
            KeyguardViewMediator.class,//锁屏
            Recents.class,//近期应用
            VolumeUI.class,//声音调节窗口
            Divider.class,//分屏
            SystemBars.class,//状态栏,导航栏
            StorageNotification.class,
            PowerUI.class,
            RingtonePlayer.class,
            KeyboardUI.class,
            PipUI.class,//提供对于画中画模式的管理
            ShortcutKeyDispatcher.class,
            VendorServices.class,
            GarbageMonitor.Service.class,
            LatencyTester.class,
            GlobalActionsComponent.class,
            RoundedCorners.class,
    };

    ...

    public void startServicesIfNeeded() {
        startServicesIfNeeded(SERVICES);
    }

    ...

    private void startServicesIfNeeded(Class[] services) {
        ...
        final int N = services.length;
        for (int i = 0; i < N; i++) {//遍历SERVICES
            Class cl = services[i];
            if (DEBUG) Log.d(TAG, "loading: " + cl);
            log.traceBegin("StartServices" + cl.getSimpleName());
            long ti = System.currentTimeMillis();
            try {

                Object newService = SystemUIFactory.getInstance().createInstance(cl);
                mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);//实例化SERVICES中的类并存于mServices中
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InstantiationException ex) {
                throw new RuntimeException(ex);
            }

            mServices[i].mContext = this;
            mServices[i].mComponents = mComponents;
            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            mServices[i].start();//并调用他们的start()方法
            ...

        }
        ...
    }

startServicesIfNeeded(SERVICES)主要做了遍历SERVICES中的类,实例化SERVICES中的类并存于mServices中,从实例化的过程可以看得出来SERVICES中的类都属于SystemUI,一一打开他们,确实也发现他们都继承自SystemUI.然后所有实例化的的对象都调用了start(),SERVICES中的类其实就是SystemUI所有的功能模块了,每一个模块从这里开始展开

到了这里,每个模块的start()方法被掉用以后,SystemUI的各个模块又是如何的完成初始化,开始工作的呢?这里从最熟悉的状态栏导航栏先开始分析

2.状态栏导航栏

状态栏导航栏的所属模块在android8.1是SystemBars,前面说到过所有的模块被实例化然后调用了start()方法,那么先来看看SystemBars的start()

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

    @Override
    public void start() {
        if (DEBUG) Log.d(TAG, "start");
        createStatusBarFromConfig();
    }

    ...

    private void createStatusBarFromConfig() {
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
        final String clsName = mContext.getString(R.string.config_statusBarComponent);//获取类名
        if (clsName == null || clsName.length() == 0) {
            throw andLog("No status bar component configured", null);
        }
        Class cls = null;
        try {
            cls = mContext.getClassLoader().loadClass(clsName);//反射
        } catch (Throwable t) {
            throw andLog("Error loading status bar component: " + clsName, t);
        }
        try {
            mStatusBar = (SystemUI) cls.newInstance();//得到StatusBar对象
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        mStatusBar.start();//把mContext和mComponents传给StatusBar对象,并调用start()方法
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    }

在SystemBar中的start()方法调用了createStatusBarFromConfig(),在createStatusBarFromConfig()中通过反射得到mStatusBar对象,先查查看mStatusBar是什么类型的,就是通过R.string.config_statusBarComponent去找

 发现mStatusBar是StatusBar类,那么继续追踪StatusBar的start()方法,在这里之前有个疑问R.string.config_statusBarComponent可以配置成其他的类吗,答案是可以的

除了StatusBar还可以配置成TvStatusBar,CarStatusBar,这两个本质上跟跟StatusBar是一样的,只是为了适配电视跟车载做出来的,如果你的产品是电视就配置成com.android.systemui.statusbar.tv.TvStatusBar

在看看StatusBar的start()主要做了什么事情

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

    public void start() {
        ...
        // Connect in to the status bar manager service
        mCommandQueue = getComponent(CommandQueue.class);//实例化mCommandQueue
        mCommandQueue.addCallbacks(this);//把自己注册到mCommandQueue
		...
        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));//获取IStatusBarService实例

		...
        try {
            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
                    fullscreenStackBounds, dockedStackBounds);//向IStatusBarServie进行注册
        } catch (RemoteException ex) {
            // If the system process isn't there we're doomed anyway.
        }

        createAndAddWindows();//创建状态栏与导航栏的窗口
		...
    }

第一步,在StatusBar的start()中首先实例化了StatusBarManagerService访问StatusBar的桥梁CommandQueue(4行),并且把StatusBar自己注册到CommandQueue(5行),第二步,然后把实例化的CommandQueue传给StatusBarManagerService(7、8行),第三步,最后创建创建状态栏与导航栏的窗口(18行),先分析第一第二步,StatusBarManagerService访问StatusBar的桥梁搭建

frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java

public class StatusBarManagerService extends IStatusBarService.Stub {

	...
    // ================================================================================
    // Callbacks from the status bar service.
    // ================================================================================
    @Override
    public void registerStatusBar(IStatusBar bar, List iconSlots,
            List iconList, int switches[], List binders,
            Rect fullscreenStackBounds, Rect dockedStackBounds) {
        ...
        mBar = bar;
        ...
    }

    ...

    @Override
    public void expandNotificationsPanel() {
        enforceExpandStatusBar();

        if (mBar != null) {
            try {
                mBar.animateExpandNotificationsPanel();
            } catch (RemoteException ex) {
            }
        }
    }
    ...
}

StatusBarManagerService的创建是在SystemServer中完成的,他是一个系统服务,他的作用是跟StatusBar关联起来,外界想要调用StatusBar方法可以通过它来完成,那么StatusBarManagerService跟StatusBar又是怎么关联起来的呢?,前面StatusBar的start()中,上述提及到的第二步,传入了一个mCommandQueue参数到StatusBarManagerService,而这个参数传到StatusBarManagerService被保存到了mBar中,比如其他地方通过StatusBarManagerService调用expandNotificationsPanel(),实际上是调用了mCommandQueue的animateExpandNotificationsPanel(),在看看mCommandQueue的代码

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java

public class CommandQueue extends IStatusBar.Stub {
	...

    public void addCallbacks(Callbacks callbacks) {
        mCallbacks.add(callbacks);
        callbacks.disable(mDisable1, mDisable2, false /* animate */);
    }
    ...

    public void animateExpandNotificationsPanel() {
        synchronized (mLock) {
            mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS);
            mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS);//发MSG_EXPAND_NOTIFICATIONS消息到Handler 去处理
        }
    }

    private final class H extends Handler {
        private H(Looper l) {
            super(l);
        }

        public void handleMessage(Message msg) {
            final int what = msg.what & MSG_MASK;
            switch (what) {
                ...
                case MSG_EXPAND_NOTIFICATIONS:
                    for (int i = 0; i < mCallbacks.size(); i++) {
                        mCallbacks.get(i).animateExpandNotificationsPanel();
                    }
                    break;
                ...
            }
        }
    }
    ...
}

可以看到CommandQueue是通过mCallbacks继续下一步的调用(28行),而这里的mCallbacks正是StatusBar,因为前面在StatusBar的start()方法中正式把自己注册了进来,28行中实际就是StatusBar调用自己的animateExpandNotificationsPanel(),这样一来StatusBar跟StatusBarManagerService的桥梁旧通过CommandQueue建立起来了。

分析StatusBar的start()的第一第二步,接着分析第三步createAndAddWindows()

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

    public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        makeStatusBarView();
        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
        mRemoteInputController = new RemoteInputController(mHeadsUpManager);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
    }

    protected void makeStatusBarView() {
        final Context context = mContext;
        updateDisplaySize(); // populates mDisplayMetrics
        updateResources();
        updateTheme();

        inflateStatusBarWindow(context);//加载状态栏布局
		...
		FragmentHostManager.get(mStatusBarWindow)
		.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
			CollapsedStatusBarFragment statusBarFragment =
					(CollapsedStatusBarFragment) fragment;
			statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
			mStatusBarView = (PhoneStatusBarView) fragment.getView();
			mStatusBarView.setBar(this);
			mStatusBarView.setPanel(mNotificationPanel);
			mStatusBarView.setScrimController(mScrimController);
			mStatusBarView.setBouncerShowing(mBouncerShowing);
			setAreThereNotifications();
			checkBarModes();
		}).getFragmentManager()
		.beginTransaction()
		.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
				CollapsedStatusBarFragment.TAG)//把super_status_bar中的status_bar_container替换成CollapsedStatusBarFragment
		.commit();
		...

        try {
            boolean showNav = mWindowManagerService.hasNavigationBar();
            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
            if (showNav) {
                createNavigationBar();//创建导航栏
            }
        } catch (RemoteException ex) {
            // no window manager? good luck with that
        }
		...
    }

    protected void inflateStatusBarWindow(Context context) {
        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);
    }

    protected void createNavigationBar() {
        mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
            mNavigationBar = (NavigationBarFragment) fragment;
            if (mLightBarController != null) {
                mNavigationBar.setLightBarController(mLightBarController);
            }
            mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
        });
    }

创建于调用顺序createAndAddWindows()->addStatusBarWindow()->makeStatusBarView(),在makeStatusBarView()加载了R.layout.super_status_bar然后再把super_status_bar中的status_bar_container替换成CollapsedStatusBarFragment,CollapsedStatusBarFragment加载的是R.layout.status_bar,至此状态栏旧加载好了,然后makeStatusBarView()中继续调用createNavigationBar(),然后创建mNavigationBarView实例,mNavigationBarView实例加载R.layout.navigation_bar,至此导航栏也加载好了。

你可能感兴趣的:(android)