• Android 12 源码分析 —— 应用层 五(SystemUI的StatusBar类的启动过程和三个窗口的创建)


    Android 12 源码分析 —— 应用层 五(SystemUI的StatusBar类的启动过程和三个窗口的创建)

    更新历史日期内容
    12023-9-18修改关于mLightsOutNotifController的错误注释

    在前面的文章中,我们介绍了SystemUI App的基本布局和基本概念。接下来,我们进入SystemUI应用的各个UI是如何被加入屏幕的。那么我们就先从三个窗口的创建开始

    注意:三个窗口,即StatusBar窗口,NavigationBar窗口,NotificationShade窗口

    而这三个窗口都是从StatusBar.java中创建的,因此从这个类开始介绍。

    本篇文章需要结合上一篇博文一起查看,上一篇博文是整个Layout的整体概览。本篇文章可以认为是整个关键类的概览。

    上一篇博文的地址:“Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)http://t.csdn.cn/Q1XSM

    太长不想看版:
    1. StatusBar的Dagger2配置 
    2. StatusBar的start()函数开始初始化
    3. StatusBar的start()函数调用createAndAddWindow()函数创建三大窗口
    4. createAndAddWindow()函数调用makeStatusBarView()创立各个Window和View,并将其添加到屏幕上
    5. makeStatusBarView()函数调用inflateStatusBarWindow()创建StatusBar和NotificationShade两个窗口
    6. makeStatusBarView()函数调用createNavigationBar()创建NavigationBar窗口
    7. makeStatusBarView()函数创建用在StatusBar窗口中的CollapsedStatusBarFragment它代表了StatusBar中的具体内容
    8. makeStatusBarView()函数创建用在NotificationShade窗口中的QSFragment它代表了整个下拉状态栏中QS的内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1.StatusBar的Dagger2配置

    仔细阅读StatusBar源码,会发现,StatusBar的构造函数,并没有被@Inject注解标记。那么StatusBar就不会被自动的创建。但是为了能够更好的加入Dagger2图中,我们通过@Provides来提供StatusBar对象。如下:

    @Module(includes = {StatusBarPhoneDependenciesModule.class})
    public interface StatusBarPhoneModule {
        //提供StatusBard对象实例
        @Provides
        @SysUISingleton
        static StatusBar provideStatusBar(
                Context context,
                /*省略超级长的参数定义*/) {
            return new StatusBar(
                    context,
                    /*省略超级长的参数传入*/);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    由上面的代码可得:StatusBarPhoneModule模块提供了,创建StatusBar的方法。也即,当SystemUI需要StatusBar时,将会由provideStatusBar方法来提供

    而在StatusBar的构造函数中,只是简单的对象赋值,无需赘述。至于这些对象对应的逻辑抽象是什么,在使用他们的时候,会进一步提及。

    注意:关于@Provides的解释,以及Dagger2如何实现provideStatusBar,和StatusBarPhoneModule,见“Android 12 源码分析 —— 应用层 三(SystemUIFactory及其Dependency解析)http://t.csdn.cn/1o4P3

    那么StatusBarPhoneModule肯定会被包含在SysUIComponent中,我们来理一下他们之间的关系。

    查找SystemUI整个源码,可以看到如下的代码:

    //可见StatusBarModule模块包含了 StatusBarPhoneModule模块
    @Module(includes = {StatusBarPhoneModule.class, StatusBarDependenciesModule.class,
            NotificationsModule.class, NotificationRowModule.class})
    public interface StatusBarModule {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    而StatusBarModule模块,被SystemUIBinder模块所包含,如下:

    //包含StatusBarModule模块
    @Module(includes = {RecentsModule.class, StatusBarModule.class, KeyguardModule.class})
    public abstract class SystemUIBinder {}
    
    • 1
    • 2
    • 3

    而SystemUIBinder模块则被SystemUIComponent包含如下:

    //包含SystemUIBinder模块
    @SysUISingleton
    @Subcomponent(modules = {
            DefaultComponentBinder.class,
            DependencyProvider.class,
            SystemUIBinder.class,
            SystemUIModule.class,
            SystemUIDefaultModule.class})
    public interface SysUIComponent {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们总结一下,其包含关系:

    SysUIComponent > SystemUIBinder > StatusBarModule > StatusBarPhoneModule:提供创建StatusBar实例的方法 
    
    • 1

    2.StatusBar的第一次创立时机

    当system_server启动SystemUIService时,会去启用SystemUIApplication的startServicesIfNeeded()函数。

    而在这个函数中,会根据配置参数,启动对应的服务。其中StatusBar就在配置之中。一旦读取到配置,则调用ContextComponentHelper的resolveSystemUI来查询,是否Dagger2中可以提供对应的对象。此处正是StatusBar的第一次创立时间。

    这部分的具体流程,见:“Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)http://t.csdn.cn/Gk418” 的startServicesIfNeeded()函数

    为了能够有直观的感受,此处提供其第一次创建的调用栈图片。如下

    在这里插入图片描述

    注意:关于调用栈的获取,详见:“Android 12 源码分析 —— 应用层 一(SystemUI准备篇) http://t.csdn.cn/FrjAh” (这是一篇必读文章,请务必掌握其中的技巧和方法)

    3. StatusBar的初始化

    在SystemUIApplication的startServicesIfNeeded()函数中被创建之后,会马上调用SystemUI的两个方法,而StatusBar继承了SystemUI,因此也会调用这两个方法:

    1. 先调用start()方法
    2. 再调用onBootCompleted()方法

    查看StatusBar,将会发现其没有覆写onBootCompleted()方法。那么StatusBar的初始化,将只会有start()方法

    4. StatusBar.start()函数

    StatusBar.start()函数特别长,源码如下:

    注意:本文关注其启动过程,而不会过多的介绍各个类的具体细节,如,不会介绍关于ScreenLifeCycle的详细设计逻辑。这些详细设计逻辑将会在整个启动过程介绍完成之后,分篇进行介绍

    @Override
        public void start() {
            //监听屏幕的生命周期,屏幕的生命周期有:正在打开,打开完成,正在关闭,关闭完成
            mScreenLifecycle.addObserver(mScreenObserver);
            //监听设备的唤醒和睡眠,注意它和Doze模式的区别
            mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
            //赋值UIModeManager,它提供,disable car mode等功能
            mUiModeManager = mContext.getSystemService(UiModeManager.class);
            //对BypassHeadsUpNotifier进行初始化,它可以绕过heads up。
            //heads up的解释见后文补充内容
            mBypassHeadsUpNotifier.setUp();
            //如果当前存在气泡通知,则监听taskbar的改变
            //气泡通知。见后文补充内容
            if (mBubblesOptional.isPresent()) {
                mBubblesOptional.get().setExpandListener(mBubbleExpandListener);
                IntentFilter filter = new IntentFilter(TASKBAR_CHANGED_BROADCAST);
                mBroadcastDispatcher.registerReceiver(mTaskbarChangeReceiver, filter);
            }
    
            //初始化KeyguardIndicationController,它控制锁屏底部消息的提示,如对充电的提示
            mKeyguardIndicationController.init();
    
            //颜色提取器,增加监听,一旦颜色改变SystemUI会进行相应的主题切换
            mColorExtractor.addOnColorsChangedListener(this);
            //监听StatusBarState的改变,当StatusBarSate改变时,将会收到通知。
            //注意监听器,有优先级
            //StatusBarState在当前版本有4中状态:1. SHADE(也就是正常状态,卷帘(也即下拉状态栏)被收起的状态)
            //2. KEYGUARD(StatusBar当前处在锁屏状态)
            //3. SHADE_LOCKED(StatusBar当前在锁屏装来下,被下拉出来了)
            //4. FULLSCREEN_USER_SWITCHER(statusbar被锁住,同时展示一个全屏的多用户切换)
            mStatusBarStateController.addCallback(this,
                    SysuiStatusBarStateController.RANK_STATUS_BAR);
    
            //赋值WindwManager
            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            //赋值DreamManager,它和屏保有关,注意它和后面Ambient mode的区别
            mDreamManager = IDreamManager.Stub.asInterface(
                    ServiceManager.checkService(DreamService.DREAM_SERVICE));
    
            //赋值,mDisplay对象,Display对象代表了一种逻辑屏幕,而非实体屏幕
            mDisplay = mWindowManager.getDefaultDisplay();
            mDisplayId = mDisplay.getDisplayId();
            //更新需要的DisplaySize相关信息
            updateDisplaySize();
    
            //读取配置,查看是否打开震动
            mVibrateOnOpening = mContext.getResources().getBoolean(
                    R.bool.config_vibrateOnIconAnimation);
    
            //赋值WindowManagerService,注意前面已经获取到了WindowManager。
            //事实上,这个根本没有在本类中使用,它只是以前老旧代码的遗产
            mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
            //获取DevicePolicyManager,它是设备所有者规定的一些策略,比如是否允许当前用户使用相机等等
            mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
                    Context.DEVICE_POLICY_SERVICE);
    
            //赋值,辅助功能,本类中也未使用该变量,它是以前代码的遗产
            mAccessibilityManager = (AccessibilityManager)
                    mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
    
            //为KeyguardUpdateMonitor设置一个KeyguardBypassController
            //其中KeyguradUpdateMonitor负责监听Keyguard感兴趣的事情,比如SIM卡的变化等
            //KeyguardBypassController负责绕过锁屏的控制,比如人脸识别,识别正确,则直接打开锁屏(注意,此类我不是很确定)
            mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
            //获取StatusBarManagerService。注意StatusBarManagerService和StatusBar之间的关系,见后文补充内容
            mBarService = IStatusBarService.Stub.asInterface(
                    ServiceManager.getService(Context.STATUS_BAR_SERVICE));
    
            //获取KeyguardManager,该类用于解锁和加锁keyguard
            mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
    
            //检查当前用户是否支持设置和查询Wallpaper(壁纸)
            mWallpaperSupported =
                    mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
    
            //CommandQueue增加一个回调,关于CommandQueue的说明,见补充知识点
            mCommandQueue.addCallback(this);
    
            //监听DemoMode。DemoMode的知识点,见补充内容
            mDemoModeController.addCallback(this);
    
            //根据补充内容第三点和第四点,需要建立和sytem_server进程中的StatusBarManagerService之间的联系
            //返回结果包括系统要求的一些东西,如显示哪些图标,禁用哪些功能等
            RegisterStatusBarResult result = null;
            try {
                result = mBarService.registerStatusBar(mCommandQueue);
            } catch (RemoteException ex) {
                ex.rethrowFromSystemServer();
            }
    
            //现在开始创建UI,这个就是在上一篇博文中,提及的UI布局和创建的入口
            //下文详解
            createAndAddWindows(result);
    
            //如果mWallpaperSupported为true,也即当前用户支持访问和修改壁纸
            if (mWallpaperSupported) {
                //那么监听壁纸的改变
                IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
                mBroadcastDispatcher.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter,
                        null /* handler */, UserHandle.ALL);
                //注意,此处主动调用了onRecive()函数,它是为了初始化其他Controller中关于
                //壁纸的一些信息,如,设置NotificationShadeWindowController是否支持Ambient模式,Ambient mode见后文
                mWallpaperChangedReceiver.onReceive(mContext, null);
            } else if (DEBUG) {
                //or,we log the message
                Log.v(TAG, "start(): no wallpaper service ");
            }
    
            //初始化各个presenter后文详细介绍
            setUpPresenter();
    
            //检查Result对象是否要求显示一个临时的StatusBar,这往往是来自于system_server的请求
            //临时的StatusBar对于用户来讲是临时可见的
            if (containsType(result.mTransientBarTypes, ITYPE_STATUS_BAR)) {
                //显示一个临时的StatusBar,它通过显示一个StatusBar的过渡动画来显示
                showTransientUnchecked();
            }
    
            //一旦获取到RegisterStatusBarResult对象(后文称:Result对象),我们就要根据其
            //内容进行相应的设置。
            //用于通知SystemBar的一些属性已经改变。因为这些属性以前没有被设置过
            onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
                    result.mNavbarColorManagedByIme, result.mBehavior, result.mAppFullscreen);
    
            //通知输入法的状态改变,但是此处内容为空。
            setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
                    result.mImeBackDisposition, result.mShowImeSwitcher);
    
            //将图标信息,通过CommandQueue通知给感兴趣的对象
            int numIcons = result.mIcons.size();
            for (int i = 0; i < numIcons; i++) {
                //在该队列中,会调用callback通知其他需要处理图标的对象
                mCommandQueue.setIcon(result.mIcons.keyAt(i), result.mIcons.valueAt(i));
            }
            //省略调试代码
    
            //如果当前用户支持设置壁纸
            if (mWallpaperSupported) {
                //那么就设置壁纸不要处于Ambient模式,ambient mode是关屏之后,屏幕显示一些
                //画面和周围的环境融为一体,如,在电视上显示一副梵高的星空,当做整面墙的装饰
                //被称为:环境融合模式
                IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
                        ServiceManager.getService(Context.WALLPAPER_SERVICE));
                try {
                    //set in ambient mode
                    wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
                } catch (RemoteException e) {
                    // Just pass, nothing critical.
                }
            }
    
            //图标显示的策略,哪些该显示,哪些不该显示
            mIconPolicy.init();
    
            //监听锁屏状态
            mKeyguardStateController.addCallback(this);
            //初始化锁屏相关对象
            startKeyguard();
    
            //StatusBar也需要监听一些外部消息,这些外部消息也是Keyguard感兴趣的消息,如SIM卡的状态改变
            mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
    
            //初始化DozeServiceHost,它和Doze 模式相关,是DozeService和SystemUI其他部分交互的接口。后面文章详细讲解
            mDozeServiceHost.initialize(
                    this,
                    mStatusBarKeyguardViewManager,
                    mNotificationShadeWindowViewController,
                    mNotificationPanelViewController,
                    mAmbientIndicationContainer);
            //在Doze模式下,还有很多配置参数,DozeParameters就是配置参数的逻辑抽象,此处给他增加一个监听
            mDozeParameters.addCallback(this::updateLightRevealScrimVisibility);
    
            //监听配置的改变,如语言改变,时区改变等
            mConfigurationController.addCallback(this);
    
            //监听电池相关的信息
            mBatteryController.observe(mLifecycle, this);
            mLifecycle.setCurrentState(RESUMED);
    
            //初始化disableFlag相关的内容
            //disableFlag相关的内容见后文的补充内容
            int disabledFlags1 = result.mDisabledFlags1;
            int disabledFlags2 = result.mDisabledFlags2;
            //调用InitController,初始化disablFlag相关的内容
            //InitController收集,所有在SystemUI实现类启动完成之后,的任务
            //然后在SystemUIApplication的startServicesIfNeeded()函数中被调用
            //此处通过调用setUpDisableFlags()函数,来处理disableFlags
            //而setUpDisableFlags()函数,通过CommandQueue将需要处理的disableFlags通知给其他需要的对象。比如告诉NavigationBar不要显示recent        
            mInitController.addPostInitTask(
                    () -> setUpDisableFlags(disabledFlags1, disabledFlags2));
    
            //增加误触的监听,当发生误触时,需要复位一些UI,防止一些动画停止在半途
            //Falsingmanager负责管理,一些误触的操作
            mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener);
    
            //给PluginManager,增加一个插件监听器。插件相关内容不做介绍,后面详细介绍
            mPluginManager.addPluginListener(/*省略代码*/}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198

    start()函数主要完成如下的功能:

    1. 初始化各个于SystemUI整个App相关的业务类
    2. 建立这些之间的引用关系
    3. 初始化StatusBarManagerService中的配置,如disablFlag,icon,transient bar等
    4. 调用createAndAddWindow()创建需要的UI

    接下来,我们从createAndAddWindow()函数开始,看看其创建UI的过程。

    基本概念补充

    1. heads up:SystemUI的一种通知显示方式,它允许重要通知以卡片的形式,出现在屏幕的顶部。
    2. Bubble notification:气泡通知,它是一种通知显示方式,它悬浮在屏幕上,如Messages by google 接收到的短信内容
    3. StatusBar和StatusBarManagerService的关系:SystemUI作为一个应用,它并不能被其他的用户所使用,为了保证其他用户的使用,系统内部有一个StatusBarService服务,它位于system_server进程中,它负责和其他用户进行交互。同时当SystemUI启动完成之后,会将自己注册到StatusBarSerivce服务中。这样StatusBarService服务就能够调用SystemUI中的StatusBar功能了。简单的结构如下:SystemUI<---->StatusBarManagerService<----->other app. 为了他们之间能够畅快的沟通,使用binder通信。
    4. CommandQueue:在第三点中,我们提到StatusBarManagerService和SystemUI是通过Binder通信,当SystemUI要调用StatusBarManagerService时,使用的是IStatusBarService接口。而当StatusBarManagerService要调用SystemUI时使用的是IStatusBar接口。这个接口在SystemUI侧的实现即为CommandQueue.可以将ComandQueue理解为:来自于外部(相对于SystemUI的外部)的命令队列。
    5. DemoMode:演示模式,演示模式将固定一个假的statusbar,可以用来调试各个图标的UI。关于DemoMode的进一步打开和关闭指令,在后面细讲时会提及
    6. disableFlags:它表示的是SystemUI中应该被禁止的功能,它被分成两种类型分别为,disable1,disable2.如果其他进程需要修改这两个的值,可以用IStatusBarService的disablexxx()函数进行修改
      • disable1 的值有:
        • DISABLE_NONE:什么也不禁止
        • DISABLE_EXPAND:禁止下拉展开
        • DISABLE_NOTIFICATION_ICONS:禁止通知图标
        • DISABLE_NOTIFICATION_ALERTS:禁止通知声音,震动,弹出警报等功能
        • DISABLE_NOTIFICATION_TICKER:禁止通知滚动条
        • DISABLE_SYSTEM_INFO:禁止状态栏的中间区域的信息显示
        • DISABLE_HOME/RECENT/BACK:分别禁止导航栏中的home,recent,BACK按钮
        • DISABLE_CLOCK:禁止状态栏中的时钟显示
        • DISABLE_SEARCH:禁用搜索
        • DISABLE_ONGOING_CALL_CHIP:禁用状态栏中,正在通话图标
      • disable2 的值有:
        • DISABLE_NONE:什么也不禁止
        • DISABLE_QUICK_SETTINGS:禁用QS
        • DISABLE_SYSTEM_ICON:禁用系统图标
        • DISABLE_NOTIFICATION_SHADE:禁用NotificationShade窗口
        • DISABLE_GLOBAL_ACTION:禁用GlobalActionDialog即,开关机弹框
        • DISABLE_ROTATE_SUGGESTIONS:禁用导航栏中的旋转建议图标
    7. ambient mode:ambient mode是关屏之后,屏幕显示一些画面和周围的环境融为一体,如,在电视上显示一副梵高的星空,当做整面墙的装饰.被称为:环境融合模式
      在这里插入图片描述

    4.1 createAndAddWindwo()函数

    createAndAddWindow()函数原文如下:

    public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
        //创建对应的UI
        makeStatusBarView(result);
        //将NotificationShadeWindow加入屏幕
        mNotificationShadeWindowController.attach();
        //将StatusBarWinidow加入屏幕
        mStatusBarWindowController.attach();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意:关于NotificationShadeWindow和StatusBarWindow的说明见“Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)http://t.csdn.cn/ioWFS

    接下来看看makeStatusBarView()函数

    4.1.1 makeStatusBarView()函数

    makeStatusBarView()函数负责创建三大窗口的View。源码如下:

    protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
        //更新需要用到的资源,如逻辑屏幕的大小
        final Context context = mContext;
        updateDisplaySize(); // populates mDisplayMetrics
        //更新资源,在还没有创建各种View之前,该函数实际调用为空
        updateResources();
        //更新主题
        updateTheme();
    
        //构造真正的View视图,见后文详解
        inflateStatusBarWindow();
        //NotificationShadeWindowViewController是NotificationShadeWindowView的控制器
        //而这个View是NotificationShade窗口的顶层窗口
        mNotificationShadeWindowViewController.setService(this, mNotificationShadeWindowController);
        //为其设置一个触摸监听
        mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener());
    
        //分别找到View层级中的各个view的Controller
        mStackScrollerController =
                mNotificationPanelViewController.getNotificationStackScrollLayoutController();
        mStackScroller = mStackScrollerController.getView();
        NotificationListContainer notifListContainer =
                mStackScrollerController.getNotificationListContainer();
        //并将NotificationListContainer设置到NotificationLogger中
        mNotificationLogger.setUpWithContainer(notifListContainer);
    
        //构造NotificationShelf视图
        inflateShelf();
        //将Shelf中的icon和状态栏中的icon同步一一下
        mNotificationIconAreaController.setupShelf(mNotificationShelfController);
        //为NotificationPanelView设置监听器,监听展开的过程
        mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator);
        mNotificationPanelViewController.addExpansionListener(
                this::dispatchPanelExpansionForKeyguardDismiss);
    
        // 允许Plugin引用DarkDispatcher和StatusBarStateController
        mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class);
        mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class);
        //使用Fragment管理StatusBar的View,达到可重用的目的
        //注意:对于这里提及的各个View,可以查看上一篇关于Layout基本布局的博文
        FragmentHostManager.get(mPhoneStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    //将Fragment转换成CollapsedStatusBarFragment
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
    
                    //先保存以前的PhoneStatusBarView
                    PhoneStatusBarView oldStatusBarView = mStatusBarView;
                    //再获取新的PhoneStatusBarView
                    mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView();
                    //对PhoneStatusBarView进行设置,包括注册监听,传递需要的对象等
                    mStatusBarView.setBar(this);
                    mStatusBarView.setPanel(mNotificationPanelViewController);
                    mStatusBarView.setScrimController(mScrimController);
                    mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
    
                    //如果有一个heads up在顶部,则需要调整为正确的状态
                    if (mHeadsUpManager.hasPinnedHeadsUp()) {
                        //主要是通知各个监听器,更新各自的状态
                        mNotificationPanelViewController.notifyBarPanelExpansionChanged();
                    }
                    //初始化PhoneStatusBarView中的Bouncer
                    //Bouncer界面就是,解锁时要求输入pin,密码等的界面
                    //新创建的PhoneStatusBarView中的Bouncer默认是没有打开的。因此要根据
                    //当前实际进行更新
                    mStatusBarView.setBouncerShowing(mBouncerShowing);
                    //如果以前的StatusBar已经展开了一部分,则要求新的StatusBar也展开同样的大小
                    //因为新创建的PhoneStatusBar,默认展开是0
                    if (oldStatusBarView != null) {
                        float fraction = oldStatusBarView.getExpansionFraction();
                        boolean expanded = oldStatusBarView.isExpanded();
                        mStatusBarView.panelExpansionChanged(fraction, expanded);
                    }
    
                    //重新创建HeadsUpAppearanceController
                    HeadsUpAppearanceController oldController = mHeadsUpAppearanceController;
                    if (mHeadsUpAppearanceController != null) {
                        mHeadsUpAppearanceController.destroy();
                    }
                    //重新创建一个新的HeadsUpAppearanceController对象
                    //这个对象负责控制heads up的外观
                    mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                            mNotificationIconAreaController, mHeadsUpManager,
                            mStackScroller.getController(),
                            mStatusBarStateController, mKeyguardBypassController,
                            mKeyguardStateController, mWakeUpCoordinator, mCommandQueue,
                            mNotificationPanelViewController, mStatusBarView);
                    //从旧对象中读取值赋值给新对象
                    mHeadsUpAppearanceController.readFrom(oldController);
                    
                    /建立LightsOutNotificationController和对应View的关系
          //LightsOutNotificationController负责处理SYSTEM_UI_FLAG_LOW_PROFILE中的
          //图标的消失和隐藏,负责显示小圆点
          //SYSTEM_UI_FLAG_LOW_PROFILE:这个属性的能力是让SystemBar在视觉上变得模糊,
          //具体表现是状态栏图标仅保留电量时间关键图标,并且变暗。导航栏图标变成三个点或者变暗
                    mLightsOutNotifController.setLightsOutNotifView(
                            mStatusBarView.findViewById(R.id.notification_lights_out));
                    //将StatusBar窗口的view,放入NotificationShade窗口的控制器中
                    mNotificationShadeWindowViewController.setStatusBarView(mStatusBarView);
                    //检查是否要进行StatusBar的模式切换,如果要切换则会形成一个过渡动画
                    //关于StatusBar模式切换的细节,我们在介绍完StatusBarWindow的整个初始化过程之后,
                    //另外的文章进一步介绍.此处我们关注整个启动过程
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container,
                        new CollapsedStatusBarFragment(
                                mOngoingCallController,
                                mAnimationScheduler,
                                mStatusBarLocationPublisher,
                                mNotificationIconAreaController,
                                mFeatureFlags,
                                mStatusBarIconController,
                                mKeyguardStateController,
                                mNetworkController,
                                mStatusBarStateController,
                                this,
                                mCommandQueue
                        ),
                        CollapsedStatusBarFragment.TAG)
                .commit();
    
        //设置必要的对象,这些对象的功能和逻辑抽象,在必要的时候介绍.
        //现在,大体可按照如下的方式进行理解
        //HeadsUpManager:负责管理heads up,如管理Heads up通知的更新
        //VisualStabilityManager:保证一种固定的通知显示,当通知超出显示范围的时候,就抑制其重排
        //StatusBarTouchableRegionManager:管理StatusBar的哪一部分可以触摸
        mHeadsUpManager.setup(mVisualStabilityManager);
        mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView);
        mHeadsUpManager.addListener(this);
        mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener());
        mHeadsUpManager.addListener(mVisualStabilityManager);
        mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
    
        //构建NavigationBar
        createNavigationBar(result);
    
        //ENABLE_LOCKSCREEN_WALLPAPER 是否打开锁屏下显示壁纸,默认打开
        //mWallpaperSupported表示当前用户是否支持设置和访问壁纸,默认支持
        if (ENABLE_LOCKSCREEN_WALLPAPER && mWallpaperSupported) {
            //得到LockScreenWallpaper对象
            mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
        }
    
    
        //传递必要的对象
        mNotificationPanelViewController.setKeyguardIndicationController(
                mKeyguardIndicationController);
    
        //这是负责显示Ambient模式的视图,但是在当前版本中是没有实现的
        //目前可以在三星的电视机上有这部分的实现代码
        //本系列文章将不会介绍
        mAmbientIndicationContainer = mNotificationShadeWindowView.findViewById(
                R.id.ambient_indication_container);
    
        //控制自动隐藏的UI元素,当需要判断是否要自动隐藏式,需要查询当前的StatusBar的一些状态
        //故要调用setStatusBar传递过去,此处对StatusBar的函数封装成了AutoHideUiElement对象
        mAutoHideController.setStatusBar(new AutoHideUiElement() {
            @Override
            public void synchronizeState() {
                checkBarModes();
            }
    
            @Override
            public boolean shouldHideOnTouch() {
                return !mRemoteInputManager.getController().isRemoteInputActive();
            }
    
            @Override
            public boolean isVisible() {
                return isTransientShown();
            }
    
            @Override
            public void hide() {
                clearTransient();
            }
        });
    
        //查找遮罩
        //关于遮罩的说明,见上一篇Layout基本布局的博文
        ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
        ScrimView notificationsScrim = mNotificationShadeWindowView
                .findViewById(R.id.scrim_notifications);
        ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
        ScrimView scrimForBubble = mBubblesManagerOptional.isPresent()
                ? mBubblesManagerOptional.get().getScrimForBubble() : null;
    
        //设置遮罩的监听
        mScrimController.setScrimVisibleListener(scrimsVisible -> {
            mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
        });
    
        //将遮罩的controller和view进行连接
        mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront, scrimForBubble);
    
        //找到LightRevealScrim,关于LightRevealScrim见上一篇关于Layout基本布局的博文
        mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
        //设置透明度改变的监听
        mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> {
            Runnable updateOpaqueness = () -> {
                mNotificationShadeWindowController.setLightRevealScrimOpaque(
                        mLightRevealScrim.isScrimOpaque());
            };
            if (opaque) {
                // Delay making the view opaque for a frame, because it needs some time to render
                // otherwise this can lead to a flicker where the scrim doesn't cover the screen
                mLightRevealScrim.post(updateOpaqueness);
            } else {
                updateOpaqueness.run();
            }
        });
        //初始化用于AOD动画的controller,AOD概念见补充知识
        mUnlockedScreenOffAnimationController.initialize(this, mLightRevealScrim);
        //根据配置,进行LightRevealScrim的可见性的设置
        updateLightRevealScrimVisibility();
    
        //为NotificationPanelViewController设置必要的对象
        mNotificationPanelViewController.initDependencies(
                this,
                mNotificationShelfController);
    
        //找到BackDropView,BackDropView的说明见上一篇关于Layout布局的博文
        BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop);
        //因为多媒体播放时,可能会使用BackDropView,因此将BackDropView传递给NotificationMediaManager
        mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
                backdrop.findViewById(R.id.backdrop_back), mScrimController, mLockscreenWallpaper);
        //读取配置,获取最大的壁纸放大系数,默认值为1.10
        float maxWallpaperZoom = mContext.getResources().getFloat(
                com.android.internal.R.dimen.config_wallpaperMaxScale);
        //NotificationShadeDepthController负责statusbar 窗口的模糊
        //此处增加一个监听器,监听模糊的程度,越模糊则depth越大
        mNotificationShadeDepthControllerLazy.get().addListener(depth -> {
            float scale = MathUtils.lerp(maxWallpaperZoom, 1f, depth);
            backdrop.setPivotX(backdrop.getWidth() / 2f);
            backdrop.setPivotY(backdrop.getHeight() / 2f);
            backdrop.setScaleX(scale);
            backdrop.setScaleY(scale);
        });
        //通知NotificationPanelViewController此时此刻,还未走完开机向导
        mNotificationPanelViewController.setUserSetupComplete(mUserSetup);
    
        //获取qs_frame,该view用于放置QS,关于QS,见补充内容
        final View container = mNotificationShadeWindowView.findViewById(R.id.qs_frame);
        if (container != null) {
            //使用Fragment创建一个可以被复用的View,该Fragment用于放置QS
            FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
            //辅助类,创建QSFragment对象,然后提交到FragmentManager中
            ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
                    mExtensionController
                            .newExtension(QS.class)
                            .withPlugin(QS.class)
                            .withDefault(this::createDefaultQSFragment)
                            .build());
            //创建BrightnessMirrorController
            mBrightnessMirrorController = new BrightnessMirrorController(
                    mNotificationShadeWindowView,
                    mNotificationPanelViewController,
                    mNotificationShadeDepthControllerLazy.get(),
                    mBrightnessSliderFactory,
                    (visible) -> {
                        mBrightnessMirrorVisible = visible;
                        updateScrimController();
                    });
            //触发FragmentManager中的onFragmentViewCreated方法,并在触发之后,
            //传递需要的对象
            fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
                QS qs = (QS) f;
                if (qs instanceof QSFragment) {
                    mQSPanelController = ((QSFragment) qs).getQSPanelController();
                    mQSPanelController.setBrightnessMirror(mBrightnessMirrorController);
                }
            });
        }
    
        //省略调试功能代码
    
        //如果未亮屏幕
        //那么主动触发一个ACTION_SCREEN_OFF的操作,后文详解这个操作
        if (!mPowerManager.isScreenOn()) {
            mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
        }
        //创建一个唤醒锁。
        mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                "GestureWakeLock");
        //获取震动服务
        mVibrator = mContext.getSystemService(Vibrator.class);
        //VibrationEffect用于表示触摸震动的视觉效果
        mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
                mVibrator, context.getResources());
    
        //注册广播接收器
        //监听,请求NotificationShadeWindow消失的Intent
        //监听,请求Recent消失的Intent
        //监听,屏幕关闭
        //监听,请求StatusBar 打开设备monitoring dialog
        registerBroadcastReceiver();
    
        //去掉用于调试的代码
    
        //监听用户是否已经设置完,开机向导
        mDeviceProvisionedController.addCallback(mUserSetupObserver);
        //主动调用,用于调用setUserSetupComplete为正确的值
        mUserSetupObserver.onUserSetupChanged();
    
        //下面两句代码,用于hwui库,暂时不用管
        // disable profiling bars, since they overlap and clutter the output on app windows
        ThreadedRenderer.overrideProperty("disableProfileBars", "true");
    
        // Private API call to make the shadows look better for Recents
        ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312

    本方法完成如下功能:

    1. 初始化各种资源
    2. 调用inflateStatusBarWindow()构造NotificationShade窗口和StaturBar窗口的顶层View容器
    3. 调用inflateShelf()构造NotificationShelf
    4. 调用createNavigationBar()构造NavigationBar窗口的顶层View容器
    5. 再通过Fragment创建可重用的View,加入这些顶层容器View中,如QSFragment,CollapsedStatusBarFragment
    6. 再创建Controller和View之间的联系
    7. 注册感兴趣的广播

    基本概念补充

    1. AOD:always on display,SystemUI提供一种在息屏状态下会显示的UI
    2. QS:Quick Settings,也就是下拉状态栏之后,可以快速开关的一排排图标
    3. 唤醒锁:通过调用PowerManager的newWakeLock()获取一个WakeLock对象。加锁则调用WakeLock.acquire(),释放则调用WakeLock.release(). WakeLock可以配置不同的持有锁级别,主要有:
      • PARTIAL_WAKE_LOCK:部分唤醒锁,屏幕和键盘背光可以关闭,但是cpu会一直运行,直到调用了release
      • FULL_WAKE_LOCK:完全唤醒锁,cpu一直运行,屏幕,键盘背光都不会关闭
      • SCREEN_DIM_WAKE_LOCK:屏幕变暗唤醒锁,屏幕常亮,但是会变暗,键盘背光允许关闭。按电源键则会释放锁
      • SCREEN_BRIGHT_WAKE_LOCK:屏幕不会变暗,键盘背光允许关闭。如果按电源,则会释放锁

    接下来我们介绍,两个用来创建顶层View的函数,inflateStatusBarWindow()和createNavigationBar()

    4.1.1.1 inflateStatusBarWindow()函数

    函数源码如下:

    private void inflateStatusBarWindow() {
        //通过工厂类,得到NotificationShade窗口的顶层View,细节见后文补充
        mNotificationShadeWindowView = mSuperStatusBarViewFactory.getNotificationShadeWindowView();
        //根据Dagger2中画的图,获取各个需要的对象,Dagger2的细节见“Android 12 源码分析 —— 应用层 三”
        StatusBarComponent statusBarComponent = mStatusBarComponentBuilder.get()
                .statusBarWindowView(mNotificationShadeWindowView).build();
        //获取需要的依赖
        mNotificationShadeWindowViewController = statusBarComponent
                .getNotificationShadeWindowViewController();
        //建立view和controller之间的联系
        mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
        //创建完顶层View之后,需要创建子View,本方法用于创建子View。这个过程将会在后续文章“NotificationShade窗口”中介绍
        mNotificationShadeWindowViewController.setupExpandedStatusBar();
        //获取依赖并初始化
        mStatusBarWindowController = statusBarComponent.getStatusBarWindowController();
        //根据工厂类,获取StatusBar窗口的顶层View,细节见后文补充
        mPhoneStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
        //获取依赖,并初始化
        mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
        statusBarComponent.getLockIconViewController().init();
    
        //依然是获取依赖并初始化
        mAuthRippleController = statusBarComponent.getAuthRippleController();
        mAuthRippleController.init();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在本函数inflateStatusBarWindow(),主要完成的工作就是:

    1. 创建顶层View,并初始化
    2. 建立Controller和View之间的联系

    在这里先看看上面函数是如何创建NotificationShadeWindow的顶层View的。

    SuperStatusBarViewFactory的getNotificationShadeWindow()如下

    public NotificationShadeWindowView getNotificationShadeWindowView() {
        if (mNotificationShadeWindowView != null) {
            return mNotificationShadeWindowView;
        }
    
        //解析,super_notification_shade.xml文件。 super_notification_shade.xml文件见“Android 12 源码分析 —— 应用层 四”
        mNotificationShadeWindowView = (NotificationShadeWindowView)
                mInjectionInflationController.injectable(
                LayoutInflater.from(mContext)).inflate(R.layout.super_notification_shade,
                /* root= */ null);
        if (mNotificationShadeWindowView == null) {
            throw new IllegalStateException(
                    "R.layout.super_notification_shade could not be properly inflated");
        }
    
        return mNotificationShadeWindowView;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意:super_notification_shade.xml文件的详细说明,见“Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)http://t.csdn.cn/Jmtwu

    接下来还需要看看,StatusBar窗口的顶层View是如何创建的,源码如下:

    public StatusBarWindowView getStatusBarWindowView() {
        if (mStatusBarWindowView != null) {
            return mStatusBarWindowView;
        }
    
        //解析super_status_bar.xml文件,并返回。
        //super_status_bar.xml文件的详细说明,见上一篇博文“Android 12 源码分析 —— 应用层 四”
        mStatusBarWindowView =
                (StatusBarWindowView) mInjectionInflationController.injectable(
                LayoutInflater.from(mContext)).inflate(R.layout.super_status_bar,
                /* root= */ null);
        if (mStatusBarWindowView == null) {
            throw new IllegalStateException(
                    "R.layout.super_status_bar could not be properly inflated");
        }
        return mStatusBarWindowView;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    总结:inflateStatusBarWindow()方法,用于创建两个窗口(StatusBar和NotificationShade)的顶层View

    注意:本文主要关注StatusBar类的初始化过程,对于各个顶层View之后的细节,以及对应的子View的细节,将会在对应的篇章中进行详细的介绍

    4.1.1.2 createNavigationBar()函数

    createNavigationBar()源码如下:

    protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
        //调用控制器方法,创建相应的View和Window
        //在此处我们只需要知道是干什么的就行,在后面的文章中会详细介绍NavigationBar的创建
        mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:本文主题为StatusBar启动过程以及3个窗口的初始化创建,在后面的文章中,我们会详细讨论每个窗口的创建过程

    4.1.1.3 第一次主动触发ACTION_SCREEN_OFF

    在makeStatusBarView()函数中,会主动调用广播接收器的onReceive方法,并传递一个ACTION_SCREEN_OFF的Intent。

    接下来我们看看这个动作所对应的操作。

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Trace.beginSection("StatusBar#onReceive");
            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
            String action = intent.getAction();
            //省略跟SCREEN_OFF无关的代码
            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                //设置其可触摸
                if (mNotificationShadeWindowController != null) {
                    mNotificationShadeWindowController.setNotTouchable(false);
                }
                //如果有气泡通知,则隐藏
                if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
                    // Post to main thread handler, since updating the UI.
                    mMainThreadHandler.post(() -> mBubblesOptional.get().collapseStack());
                }
                //结束StatusBar和NavigationBar的过渡动画
                finishBarAnimations();
                //通知变成折叠状态
                resetUserExpandedStates();
            }
            //省略根SCREEN_OFF无关的代码
            Trace.endSection();
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    总结:

    1. 在初始化的时候,主动触发SCREEN_OFF,并复位一些UI显示

    4.2 setupPresenter()函数

    在start()函数中,还会调用一个重要的初始化presenter的函数,即setupPresenter(),源码如下:

    private void setUpPresenter() {
        //ActivityLaunchAnimator用于打开Activity时触发动画
        mActivityLaunchAnimator = new ActivityLaunchAnimator(this, mContext);
        //NotificationAnimationProvider用于提供从通知中打开Activity时的动画
        mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
                mNotificationShadeWindowViewController,
                mStackScrollerController.getNotificationListContainer(),
                mHeadsUpManager
        );
    
        //创建一个StatusBarNotificationPresenter,它表示的是一种用于呈现(presenter)Notifications的抽象,可以通过它查询Notification的状态
        mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
                mHeadsUpManager, mNotificationShadeWindowView, mStackScrollerController,
                mDozeScrimController, mScrimController, mNotificationShadeWindowController,
                mDynamicPrivacyController, mKeyguardStateController,
                mKeyguardIndicationController,
                this /* statusBar */, mShadeController,
                mLockscreenShadeTransitionController, mCommandQueue, mInitController,
                mNotificationInterruptStateProvider);
    
        //传递必要的对象给NotificationShelf对象
        mNotificationShelfController.setOnActivatedListener(mPresenter);
    
        //传递必要对象
        mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
    
        //NotificationActivityStarter用于处理从Notification中启动Activity
        mNotificationActivityStarter =
                mStatusBarNotificationActivityStarterBuilder
                        .setStatusBar(this)
                        .setActivityLaunchAnimator(mActivityLaunchAnimator)
                        .setNotificationAnimatorControllerProvider(mNotificationAnimationProvider)
                        .setNotificationPresenter(mPresenter)
                        .setNotificationPanelViewController(mNotificationPanelViewController)
                        .build();
        //为mStackScroller设置必要对象,mStackScroller对象即为Notification的父容器NotificationStackScrollLayout
        mStackScroller.setNotificationActivityStarter(mNotificationActivityStarter);
    
        //为NotificationGutsManager设置NotificationActivityStarter对象,NotificationGutsManager
        //是长按notification之后,出现的图标
        mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
    
        //初始化NotificationController
        mNotificationsController.initialize(
                this,
                mBubblesOptional,
                mPresenter,
                mStackScrollerController.getNotificationListContainer(),
                mNotificationActivityStarter,
                mPresenter);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    从这个函数看,它主要负责处理如下内容:

    1. 初始化从StatusBar打开Activity的对象
    2. 初始化从Notification打开Activity的对象
    3. 初始化从NotificationGuts打开Activity的对象

    前面我们已经处理好了Notification相关的初始化,接下来初始化跟keyguard相关的初始化,它从startKeyguard()函数开始

    4.3 startKeyguard()函数

    startKeygurad()函数源码如下:

    protected void startKeyguard() {
        Trace.beginSection("StatusBar#startKeyguard");
        //获取生物解锁控制器,它负责人脸,指纹解锁,虹膜等的解锁
        mBiometricUnlockController = mBiometricUnlockControllerLazy.get();
        //监听生物解锁的各个模式事件,具体细节见后续文章的指纹解锁
        mBiometricUnlockController.setBiometricModeListener(
                new BiometricUnlockController.BiometricModeListener() {
                    @Override
                    public void onResetMode() {
                        setWakeAndUnlocking(false);
                    }
    
                    @Override
                    public void onModeChanged(int mode) {
                        switch (mode) {
                            case BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM:
                            case BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING:
                            case BiometricUnlockController.MODE_WAKE_AND_UNLOCK:
                                setWakeAndUnlocking(true);
                        }
                    }
    
                    @Override
                    public void notifyBiometricAuthModeChanged() {
                        StatusBar.this.notifyBiometricAuthModeChanged();
                    }
    
                    private void setWakeAndUnlocking(boolean wakeAndUnlocking) {
                        if (getNavigationBarView() != null) {
                            getNavigationBarView().setWakeAndUnlocking(wakeAndUnlocking);
                        }
                    }
                });
        //将必要对象注册给StatusBarKeyguardViewManager对象
        mStatusBarKeyguardViewManager.registerStatusBar(
                /* statusBar= */ this, getBouncerContainer(),
                mNotificationPanelViewController, mBiometricUnlockController,
                mStackScroller, mKeyguardBypassController);
        //KeyguardIndicationController
        mKeyguardIndicationController
                .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
        mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
        mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
        //DynamicPrivacyController负责动态控制Notification内容的可见性
        mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
    
        //LightBarController负责浅色模式如何应用到icon上 
        mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
        mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
        mKeyguardDismissUtil.setDismissHandler(this::executeWhenUnlocked);
        Trace.endSection();
    
        //注意如果上面没有注释的,可以直接搜索对象名,在前文中有相应注释
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    该函数也非常的简单,构建各个对象,然后将各个对象传递给需要的对象。

    至此整个StatusBar的初始化过程完成,接下来我们对其关键部分做一个总结,以掌握其主体脉络

    1. 系统启动完成,启动system_server
    2. system_server启动SystemUIService
    3. SystemUIService启动SystemUIApplication的startServicesIfNeeded()
    4. startServicesIfNeeded()启动StatusBar
      (前面四个就是“Android 12 源码分析 —— 应用层 二”和“Android 12 源码分析 —— 应用层 三”的主体内容)
    5. start()函数中,建立与system_server中的联系
    6. start()函数中,调用createAndAddWindow()创建需要的窗口
    7. start()函数中,初始化各个需要的必要对象
    8. createAndAddWindow()函数中,调用makeStatusBarView()创立各个Window和View,并将其添加到屏幕上
    9. makeStatusBarView()函数中,调用inflateStatusBarWindow()创建StatusBar和NotificationShade两个窗口
    10. makeStatusBarView()函数中,调用createNavigationBar()创建NavigationBar窗口
    11. makeStatusBarView()函数中,创建用在StatusBar窗口中的CollapsedStatusBarFragment它代表了StatusBar中的具体内容
    12. makeStatusBarView()函数中,创建用在NotificationShade窗口中的QSFragment它代表了整个下拉状态栏中QS的内容
    13. 并在初始化的过程中,协调各个对象之间的关系
    14. 并在初始化过程中,关闭屏幕,恢复UI到一个初始状态

    在本篇文章中,我们并没有过多深入去讨论CollapsedStatusBarFragment的创建,而是停留在了其顶层View上,因此,接下来几篇文章,将分别介绍CollapsedStatusBarFragment,QSFragment以及StackScroll的创建过程,最后再介绍NavigationBar的创建过程。

    下一篇文章,StatusBar窗口的UI创建和初始化

    ps1:行文过程中,常常发现,中英文交杂,尤其是名字,其实有时候让人挺费解的,若读者有疑问,可在留言,知无不言,言无不尽。

    ps2:当然文中难免有错误,望不吝赐教

  • 相关阅读:
    Maven简介
    flutter出现entrypoint isn‘t within the current project
    从React源码角度看useCallback,useMemo,useContext
    PyQt5学习一(环境搭建)
    结构体定义struct和typedef struct的区别(重新整理版)
    接口框架第二篇—unittest/pytest 有什么区别
    PDFBOX和ASPOSE.PDF
    《Terraform 101 从入门到实践》 Functions函数
    2022面试,Java面试项目推荐,15个项目吃透两个offer拿到手软
    Android系统恢复出场设置流程分析
  • 原文地址:https://blog.csdn.net/xiaowanbiao123/article/details/132842129