• Android 9.0系统源码_SystemUI(二)StatusBar系统状态栏的启动流程


    前言

    上一篇我们具体分析了SystemUI的启动流程,在SystemServer的startOtherServices方法中,会启动SystemUIService服务,SystemUIService服务的onCreate方法会继续调用SystemUIApplication的startServicesIfNeeded方法,在该方法中会获取SystemUI组件各个类的具体路径,并通过反射创建对应的实例对象,然后依次调用每个组件的start() 方法启动相关类的服务,启动完成后,又会再次调用该组件的onBootCompleted( ) 方法。

        private void startServicesIfNeeded(String[] services) {
     		...
            mServices = new SystemUI[services.length];
            ...
            final int N = services.length;
            for (int i = 0; i < N; i++) {
                String clsName = services[i];//具体系统控件类的完整路径
            	...
                Class cls = Class.forName(clsName);
                mServices[i] = (SystemUI) cls.newInstance();//通过反射创建实例对象
                ...
                mServices[i].start(); //调用start()启动
    			...
                if (mBootCompleted) {
                    mServices[i].onBootCompleted(); //启动完毕,调用对应的onBootCompleted()方法
                }
            }
    		...
            mServicesStarted = true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
        <string-array name="config_systemUIServiceComponents" translatable="false">
            <item>com.android.systemui.Dependencyitem>
            <item>com.android.systemui.util.NotificationChannelsitem>
            <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStartitem>
            <item>com.android.systemui.keyguard.KeyguardViewMediatoritem>
            <item>com.android.systemui.recents.Recentsitem>
            <item>com.android.systemui.volume.VolumeUIitem>
            <item>com.android.systemui.stackdivider.Divideritem>
            <item>com.android.systemui.SystemBarsitem>
            <item>com.android.systemui.usb.StorageNotificationitem>
            <item>com.android.systemui.power.PowerUIitem>
            <item>com.android.systemui.media.RingtonePlayeritem>
            <item>com.android.systemui.keyboard.KeyboardUIitem>
            <item>com.android.systemui.pip.PipUIitem>
            <item>com.android.systemui.shortcut.ShortcutKeyDispatcheritem>
            <item>@string/config_systemUIVendorServiceComponentitem>
            <item>com.android.systemui.util.leak.GarbageMonitor$Serviceitem>
            <item>com.android.systemui.LatencyTesteritem>
            <item>com.android.systemui.globalactions.GlobalActionsComponentitem>
            <item>com.android.systemui.ScreenDecorationsitem>
            <item>com.android.systemui.fingerprint.FingerprintDialogImplitem>
            <item>com.android.systemui.SliceBroadcastRelayHandleritem>
        string-array>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    对这些 SystemUI服务 做一点介绍:

    • com.android.systemui.Dependency 是为了创建全局可用的依赖关系。
    • com.android.systemui.SystemBars创建整个SystemUI视图的入口类。
    • com.android.systemui.recents.Recents 最近任务
    • com.android.systemui.volume.VolumeUI 音量控制
    • com.android.systemui.pip.PipUI 画中画
    • com.android.systemui.statusbar.CommandQueue 是一个 Binder 类,它会被StatusBar注册到 StatusBarManagerService 中,用于接收StatusBarManagerService服务端的消息。

    一、创建StatusBar

    1、上面说过,SystemBars这个组件是整个SystemUI视图创建的入口类,它被启动时会调用 start() 方法,先看下该类的 start() 方法:

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

    public class SystemBars extends SystemUI {
     	...
        @Override
        public void start() {
            createStatusBarFromConfig();//通过配置创建系统状态栏
        }
        ...
       private void 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();//通过反射创建实例对象
          } catch (Throwable t) {
              throw andLog("Error creating status bar component: " + clsName, t);
          }
          mStatusBar.mContext = mContext;
          mStatusBar.mComponents = mComponents;
          mStatusBar.start();//调用系统状态栏的start方法
      }
    
    • 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

    从中可以知道,该方法中先读取 value/config.xml文件中config_statusBarComponent的值

    <string name="config_statusBarComponent">com.android.systemui.statusbar.phone.StatusBarstring>
    
    • 1

    该数值其实就是状态栏所对应类的完整路径,然后再通过反射创建出具体的StatusBar对象实例,最后调用StatusBar的start()方法。

    2、StatusBar的start方法如下所示,该类的start()方法代码较多,这里我们只看重点,在该方法里面有调用createAndAddWindows()方法,然后再调用addStatusBarWindow()方法,该方法又会继续调用makeStatusBarView方法,makeStatusBarView方法具体来构建系统状态栏视图。

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

    public class StatusBar extends SystemUI implements DemoMode,
            DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
            OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
            ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
     	...
        @Override
        public void start() {
        	...
            createAndAddWindows(); //创建整个SystemUI视图并添加到WindowManager中
            ...
        }
        ...
        public void createAndAddWindows() {
            addStatusBarWindow();
        }
        private void addStatusBarWindow() {
            makeStatusBarView(); //创建整个SystemUI视图
       		...
        }
     	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    二、通过布局文件构建StatusBar所对应的视图

    1、StatusBar的makeStatusBarView方法如下,该方法会继续调用inflateStatusBarWindow方法,将R.layout.super_status_bar布局文件构建成对应的视图。

        protected void makeStatusBarView() {
            final Context context = mContext;
            updateDisplaySize(); // populates mDisplayMetrics
            updateResources();
            updateTheme();
            //实例化整个SystemUI视图,包括状态栏,通知面版,锁屏
            inflateStatusBarWindow(context);
            ...
        }
        
        protected void inflateStatusBarWindow(Context context) {
        	//实例化整个SystemUI视图,包括状态栏,通知面版,锁屏
            mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null);
        }
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2、布局super_status_bar.xmlz其实就是整个SystemUI视图,它的的具体内容如下所示:

    frameworks/base/packages/SystemUI/res/layout/super_status_bar.xml

    <com.android.systemui.statusbar.phone.StatusBarWindowView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:sysui="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">
    
        <com.android.systemui.statusbar.BackDropView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="gone"
                sysui:ignoreRightInset="true"
                >
            <ImageView android:id="@+id/backdrop_back"
                       android:layout_width="match_parent"
                       android:scaleType="centerCrop"
                       android:layout_height="match_parent" />
            <ImageView android:id="@+id/backdrop_front"
                       android:layout_width="match_parent"
                       android:layout_height="match_parent"
                       android:scaleType="centerCrop"
                       android:visibility="invisible" />
        com.android.systemui.statusbar.BackDropView>
    
        <com.android.systemui.statusbar.ScrimView
            android:id="@+id/scrim_behind"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:importantForAccessibility="no"
            sysui:ignoreRightInset="true"
            />
            
        
        <FrameLayout
            android:id="@+id/status_bar_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
                  android:layout="@layout/car_fullscreen_user_switcher"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"/>
                  
        
        <include layout="@layout/status_bar_expanded"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="invisible" />
    
        <include layout="@layout/brightness_mirror" />
    
        <com.android.systemui.statusbar.ScrimView
            android:id="@+id/scrim_in_front"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:importantForAccessibility="no"
            sysui:ignoreRightInset="true"
            />
    
    com.android.systemui.statusbar.phone.StatusBarWindowView>
    
    • 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

    根视图StatusBarWindowView是一个FrameLayout,那么状态栏显示在最下面,然后通知面版会覆盖状态栏,最后还有一个底部视图在最上面。另外值得注意的一点就是id为status_bar_container的组件就是系统状态栏,接下来会向这个容器中添加状态栏视图。

    三、系统状态栏所对应的布局文件

    1、继续看StatusBar的makeStatusBarView方法,我们就会发现,id为status_bar_container所对应的Fragment其实就是状态栏,而它所对应的具体实现类就是CollapsedStatusBarFragment。

        protected void makeStatusBarView() {
            final Context context = mContext;
            updateDisplaySize();
            updateResources();
            updateTheme();
            //实例化整个SystemUI视图,包括状态栏,通知面版,锁屏
            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);
                        if (mHeadsUpAppearanceController != null) {
                            // This view is being recreated, let's destroy the old one
                            mHeadsUpAppearanceController.destroy();
                        }
                        mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                                mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
                        setAreThereNotifications();
                        checkBarModes();
                    }).getFragmentManager()
                    .beginTransaction()
                    // CollapsedStatusBarFragment实现了状态栏的添加
                    .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                            CollapsedStatusBarFragment.TAG)
                    .commit();
           	...
         }
    
    • 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

    可以看到CollapsedStatusBarFragment代表的就是状态栏视图,这个视图被添加到ID为status_bar_container的容器中。

    2、接下来继续分析CollapsedStatusBarFragment的生命周期,即可知道状态栏的创建过程。这里创建视图的地方就在CollapsedStatusBarFragment的onCreateView方法中,该方法会将status_bar.xml布局文件转化为对应的视图。

    public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {
    	...
    	 @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                Bundle savedInstanceState) {
            //系统状态栏所对应的布局文件
            return inflater.inflate(R.layout.status_bar, container, false);
        }
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、status_bar.xml 就是状态栏视图布局,该布局文件的具体内容如下所示:

    <com.android.systemui.statusbar.phone.PhoneStatusBarView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
        android:layout_width="match_parent"
        android:layout_height="@dimen/status_bar_height"
        android:id="@+id/status_bar"
        android:background="@drawable/system_bar_background"
        android:orientation="vertical"
        android:focusable="false"
        android:descendantFocusability="afterDescendants"
        android:accessibilityPaneTitle="@string/status_bar">
    
        <ImageView
            android:id="@+id/notification_lights_out"
            android:layout_width="@dimen/status_bar_icon_size"
            android:layout_height="match_parent"
            android:paddingStart="@dimen/status_bar_padding_start"
            android:paddingBottom="2dip"
            android:src="@drawable/ic_sysbar_lights_out_dot_small"
            android:scaleType="center"
            android:visibility="gone"/>
    
        <LinearLayout android:id="@+id/status_bar_contents"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingStart="@dimen/status_bar_padding_start"
            android:paddingEnd="@dimen/status_bar_padding_end"
            android:orientation="horizontal">
            
            <ViewStub
                android:id="@+id/operator_name"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout="@layout/operator_name" />
                
            <FrameLayout
                android:layout_height="match_parent"
                android:layout_width="0dp"
                android:layout_weight="1">
    
                <include layout="@layout/heads_up_status_bar_layout" />
                
              	
                <LinearLayout
                    android:id="@+id/status_bar_left_side"
                    android:layout_height="match_parent"
                    android:layout_width="match_parent"
                    android:clipChildren="false">
                    
                    <com.android.systemui.statusbar.policy.Clock
                        android:id="@+id/clock"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                        android:singleLine="true"
                        android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
                        android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
                        android:gravity="center_vertical|start"/>
                        
                    
                    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
                        android:id="@+id/notification_icon_area"
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:orientation="horizontal"
                        android:clipChildren="false"/>
    
                LinearLayout>
            FrameLayout>
    
            <android.widget.Space
                android:id="@+id/cutout_space_view"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:gravity="center_horizontal|center_vertical"/>
    
            
            <com.android.keyguard.AlphaOptimizedLinearLayout
                android:id="@+id/system_icon_area"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="horizontal"
                android:gravity="center_vertical|end"
                >
    
                <include layout="@layout/system_icons" />
                
            com.android.keyguard.AlphaOptimizedLinearLayout>
        LinearLayout>
    
        <ViewStub
            android:id="@+id/emergency_cryptkeeper_text"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout="@layout/emergency_cryptkeeper_text"/>
    
    com.android.systemui.statusbar.phone.PhoneStatusBarView>
    
    • 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

    从这个布局可以分析出状态栏从左到右到底显示了什么。

    • 最左边的一块区域,依次显示运营商名字,时间,通知图标。
    • 中间一块区域。
    • 然后是最右边一块区域,显示的是状态图标(例如bt, wifi),以及电池图标。

    这样一来,我们就对整个状态栏上的布局有个了解,后续的篇章我们将会继续分析下状态上的状态图标(例如bt, wifi)是如何显示上去的。

    四、系统下拉通知窗口的布局文件

    1、重新回到第二步,继续看StatusBar所对应的super_status_bar.xml,该布局文件中
    include所包含的status_bar_expanded就是系统下拉的通知窗口的布局文件。

    <com.android.systemui.statusbar.phone.NotificationPanelView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:systemui="http://schemas.android.com/apk/res-auto"
        android:id="@+id/notification_panel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent" >
    
        <include
            layout="@layout/keyguard_status_view"
            android:visibility="gone" />
    
        <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="@integer/notification_panel_layout_gravity"
            android:id="@+id/notification_container_parent"
            android:clipToPadding="false"
            android:clipChildren="false">
    
            <FrameLayout
                android:id="@+id/qs_frame"
                android:layout="@layout/qs_panel"
                android:layout_width="@dimen/qs_panel_width"
                android:layout_height="match_parent"
                android:layout_gravity="@integer/notification_panel_layout_gravity"
                android:clipToPadding="false"
                android:clipChildren="false"
                systemui:viewType="com.android.systemui.plugins.qs.QS" />
    
            <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
                android:id="@+id/notification_stack_scroller"
                android:layout_marginTop="@dimen/notification_panel_margin_top"
                android:layout_width="@dimen/notification_panel_width"
                android:layout_height="match_parent"
                android:layout_gravity="@integer/notification_panel_layout_gravity"
                android:layout_marginBottom="@dimen/close_handle_underlap" />
    
            <include layout="@layout/ambient_indication"
                android:id="@+id/ambient_indication_container" />
    
            <ViewStub
                android:id="@+id/keyguard_user_switcher"
                android:layout="@layout/keyguard_user_switcher"
                android:layout_height="match_parent"
                android:layout_width="match_parent" />
    
            <include
                layout="@layout/keyguard_status_bar"
                android:visibility="invisible" />
    
            <Button
                android:id="@+id/report_rejected_touch"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
                android:text="@string/report_rejected_touch"
                android:visibility="gone" />
    
        com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
    
        <include
            layout="@layout/keyguard_bottom_area"
            android:visibility="gone" />
    
        <com.android.systemui.statusbar.AlphaOptimizedView
            android:id="@+id/qs_navbar_scrim"
            android:layout_height="96dp"
            android:layout_width="match_parent"
            android:layout_gravity="bottom"
            android:visibility="invisible"
            android:background="@drawable/qs_navbar_scrim" />
    
    com.android.systemui.statusbar.phone.NotificationPanelView>
    
    • 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
  • 相关阅读:
    水晶球,构造回文(关键词-字符串)
    MindSpore是一种适用于端边云场景的新型开源深度学习训练/推理框架
    【Pm4py第六讲】关于合规性检查
    自定义MVC增删改查
    计算机毕业设计django基于python的热门短视频推荐系统(源码+系统+mysql数据库+Lw文档)
    linux编程与基础:第三章用户与用户组管理--自我总结
    JAVA毕设项目商店管理系统演示录像(java+VUE+Mybatis+Maven+Mysql)
    Python基础语句
    一个非常不错的开源Docker管理工具-DockerUI
    Java版本+企业电子招投标系统源代码+支持二开+招投标系统+中小型企业采购供应商招投标平台
  • 原文地址:https://blog.csdn.net/abc6368765/article/details/126268639