android8.0之SystemUI分析(一)

本文将比较全面的介绍SystemUI的组成,实现,布局以及客制化方案等等。本博文基于android8.0源码进行分析,因为android8.0相比之前的版本SystemUI部分改动是很是大的。java

1、SystemUI组成
SystemUI包含的功能很是丰富,组成元素主要包含常见的System Bars,以及ScreenShot截屏、壁纸、最近运行的应用程序等。SystemUI也是各大安卓版本中变化比较大的一个部分。android

Status Bar
Navigation Bar
Combined Bar (主要为Tablet设备使用)
Notifications
LockScreen
Recent (最近任务)
QuickSettings
等等
2、SystemUI实现
了解了SystemUI后,本文先来大概讲解下StatusBar的实现流程。ide

一、应用启动相关代码
相关代码主要分为两个部分 
1)、Service部分 
代码路径:framework/base/services/java/com/android/server 
2) 、应用部分 
代码路径:framework/base/packages/SystemUI布局

SystemUI中SystemUIService是整个系统UI比较重要的载体,因此咱们的分析将从SystemUIService开始,而SystemUIService是从SystemServer中启动的。关于这部分这里不作多的分析,详见SystemServer.java中的startSystemUi()方法。下面来看一下SystemUIServer中的onCreate()方法。ui

/*framework/base/packages/systemui/src/com/android/systemui/SystemUIService.java*/
    @Override
    public void onCreate() {
        super.onCreate();
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();this

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

上面的代码能够看出SystemUIService中实际有效代码只是实例化了一个SystemUIApplication对象,而且调用了startServiceIfNeeded()方法。下面来看SystemUIApplication中的具体实现逻辑。spa

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

其中SERVICES是一组全部用户共用的SystemUI服务,以下:.net

    /**
     * The classes of the stuff to start.
     */
    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,    //主要处理和Power相关的事件,好比省电模式切换,电池电量变化和开关屏幕等事件
            RingtonePlayer.class,     //铃声播放
            KeyboardUI.class,
            PipUI.class,     //提供对画中画模式的管理
            ShortcutKeyDispatcher.class,    //
            VendorServices.class,
            GarbageMonitor.Service.class,
            LatencyTester.class,
            GlobalActionsComponent.class,
            RoundedCorners.class,
    };debug

    /**
     * The classes of the stuff to start for each user.  This is a subset of the services listed
     * above.
     */
    private final Class<?>[] SERVICES_PER_USER = new Class[] {
            Dependency.class,
            NotificationChannels.class,
            Recents.class
    };

上面对SystemUI要启动的一系列服务有了个基本的介绍,下面来看SystemUIApplication中是怎么启动这一些列服务的component

private void startServicesIfNeeded(Class<?>[] services) {
    ...
    log.traceBegin("StartServices");
    final int N = services.length;  //获取要启动的服务列表的长度
    for (int i = 0; i < N; i++) {
        Class<?> cl = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + cl);
        log.traceBegin("StartServices" + cl.getSimpleName());
        long ti = System.currentTimeMillis();
        try {
             /* 经过SystemUIFactory来建立相应的单例 */
            Object newService = SystemUIFactory.getInstance().createInstance(cl);
            mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
        }...
        mServices[i].mContext = this;
        mServices[i].mComponents = mComponents;
        if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
        mServices[i].start();   //服务启动的地方
        log.traceEnd();

        // Warn if initialization of component takes too long
        ti = System.currentTimeMillis() - ti;
        if (ti > 1000) {
            Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
        }
        if (mBootCompleted) {
            mServices[i].onBootCompleted();
        }
    }
    log .traceEnd();    ...
}

能够看到SystemBar这个服务只是做为了一个中间过程,启动了StatusBar,如今咱们开看一下StatusBar的start()方法:

@Override
public void start() {   
... //这里面进行了StatusBar中各个组件的初始化
    mBarService = IStatusBarService.Stub.asInterface(
            ServiceManager.getService(Context.STATUS_BAR_SERVICE));
    ...
    try {
        /* 通过一系列对象的建立与初始化后,开始向StatusBarService进行注册。这里涉及跨进程操做,
                  于是传递的参数都是继承自Parcelable的 */
        mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
                fullscreenStackBounds, dockedStackBounds);
    } ...

    createAndAddWindows();  //这里才是真正将Status Bar显示出来的地方
}

这里你们就会有疑问了,既然已经有了StatusBar了,那么这里忽然杀出来个StatusBarService,究竟是为何呢? 
先来看看StatusBarService,经过Context.STATUS_BAR_SERVICE,直觉告诉咱们这个应用程序应该是在SystemServer中。咱们能够看看是谁向SystemServer中注册的这个服务,下面来看一下SystemUI中的代码。

if (!disableSystemUI) {
   traceBeginAndSlog("StartStatusBarManagerService");
   try {
       statusBar = new StatusBarManagerService(context, wm);
       ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
   } catch (Throwable e) {
       reportWtf("starting StatusBarManagerService", e);  //原来StatusBarManagerService这个家伙注册的
   }
   traceEnd();
}

接下来进一步分析StatusBarManagerService的实现,首先来看下其中的registerStatusBar中的代码:

    @Override
    public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
            List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
            Rect fullscreenStackBounds, Rect dockedStackBounds) {
        enforceStatusBarService();

        Slog.i(TAG, "registerStatusBar bar=" + bar);
        mBar = bar;
        try {
            mBar.asBinder().linkToDeath(new DeathRecipient() {
                @Override
                public void binderDied() {
                    mBar = null;
                    notifyBarAttachChanged();
                }
            }, 0);
        } catch (RemoteException e) {
        }
        notifyBarAttachChanged();
        synchronized (mIcons) {    //复制icon列表
            for (String slot : mIcons.keySet()) {
                iconSlots.add(slot);
                iconList.add(mIcons.get(slot));
            }
        }
        synchronized (mLock) {
            switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
            switches[1] = mSystemUiVisibility;
            switches[2] = mMenuVisible ? 1 : 0;
            switches[3] = mImeWindowVis;
            switches[4] = mImeBackDisposition;
            switches[5] = mShowImeSwitcher ? 1 : 0;
            switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
            switches[7] = mFullscreenStackSysUiVisibility;
            switches[8] = mDockedStackSysUiVisibility;
            binders.add(mImeToken);
            fullscreenStackBounds.set(mFullscreenStackBounds);
            dockedStackBounds.set(mDockedStackBounds);
        }
    }

从上面的代码看,registerStatusBar的做用主要是:1、为新启动的SystemUI应用赋予当前系统的真实值(好比有多少须要显示的图标);2、经过成员变量mBar记录IstatusBar对象,它在SystemUI中对应的是CommandQueue。 
下面经过本身整理的调用流程图,你们能够参考一下: 

相关文章
相关标签/搜索