SystemUI系列之StatusBar

在上一篇(https://blog.csdn.net/u011164827/article/details/102998091)分析到SystemUI的启动过程,现在分析StatusBar。

启动分析

SystemUI在SystemUIApplication会启动各个模块,在这个地方会调用com.android.systemui.SystemBars的start方法。

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

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


    private void createStatusBarFromConfig() {
53        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
          //取出className
54        final String clsName = mContext.getString(R.string.config_statusBarComponent);
55        if (clsName == null || clsName.length() == 0) {
56            throw andLog("No status bar component configured", null);
57        }
          // 通过反射获取该对象
58        Class<?> cls = null;
59        try {
60            cls = mContext.getClassLoader().loadClass(clsName);
61        } catch (Throwable t) {
62            throw andLog("Error loading status bar component: " + clsName, t);
63        }
64        try {
65            mStatusBar = (SystemUI) cls.newInstance();
66        } catch (Throwable t) {
67            throw andLog("Error creating status bar component: " + clsName, t);
68        }
          //填充信息并启动 StatusBar  start() 方法
69        mStatusBar.mContext = mContext;
70        mStatusBar.mComponents = mComponents;
71        mStatusBar.start();
72        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
73    }

这里面的代码不多,主要是通过反射获取config_statusBarComponent 中定义的对象,并启动该对象的start方法。config_statusBarComponent 的值有3种,默认是phone布局,另外两个是tv和car。

44    <!-- Component to be used as the status bar service.  Must implement the IStatusBar
45     interface.  This name is in the ComponentName flattened format (package/class)  -->
46    <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>

我们这里分析frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

  public void start() {
           //由于状态栏的窗口不属于任何一个Activity,所以需要使用WindowManager窗口创建
656        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
657
658        mDisplay = mWindowManager.getDefaultDisplay();
659        updateDisplaySize();
660
661        Resources res = mContext.getResources();
662        mVibrateOnOpening = mContext.getResources().getBoolean(
663                R.bool.config_vibrateOnIconAnimation);
664        mVibratorHelper = Dependency.get(VibratorHelper.class);
665        mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
666        mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
667
668        DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
669        putComponent(StatusBar.class, this);
670
671        // start old BaseStatusBar.start().
           //状态栏的存在对窗口布局有重要的影响,因此状态栏中所发生的变化有必要通知给WMS
672        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
673        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
674                Context.DEVICE_POLICY_SERVICE);
675
676        mAccessibilityManager = (AccessibilityManager)
677                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
678
679        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
680
681        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
682
683        mBarService = IStatusBarService.Stub.asInterface(
684                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
685
686        mRecents = getComponent(Recents.class);
687
688        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
689        mLockPatternUtils = new LockPatternUtils(mContext);
690
691        mMediaManager.setUpWithPresenter(this, mEntryManager);
692
693        // Connect in to the status bar manager service
           //mCommandQueue是CommandQueue类的一个实例。CommandQueue继承自IStatusBar.Stub。因此它是IStatusBar的Bn端。在完成注册后,这一Binder对象的Bp端将会保存在
		   //IStatusBarService中,因此它是IStatusBarService与BaseStatusBar进行通信的桥梁。
694        mCommandQueue = getComponent(CommandQueue.class);
695        mCommandQueue.addCallbacks(this);
696        /*
           *switches存储了一些杂项:禁用功能列表,SystemUIVisiblity,是否在导航栏中显示虚拟的菜单键,输入法窗口是否可见,输入法是否消费BACK键,是否接入了实体键盘
		   *实体键盘是否被启用
		   */
697        int[] switches = new int[9];
698        ArrayList<IBinder> binders = new ArrayList<>();
699        ArrayList<String> iconSlots = new ArrayList<>();
700        ArrayList<StatusBarIcon> icons = new ArrayList<>();
701        Rect fullscreenStackBounds = new Rect();
702        Rect dockedStackBounds = new Rect();
703        try {
               //向IStatusBarServie进行注册,并获取所有保存在IStatusBarService中的信息副本
704            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
705                    fullscreenStackBounds, dockedStackBounds);
706        } catch (RemoteException ex) {
707            // If the system process isn't there we're doomed anyway.
708        }
709        //创建状态栏与导航栏的窗口
710        createAndAddWindows();
711
712        // Make sure we always have the most current wallpaper info.
713        IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
714        mContext.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter);
715        mWallpaperChangedReceiver.onReceive(mContext, null);
716
717        mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
718        mCommandQueue.disable(switches[0], switches[6], false /* animate */); //禁用某些功能
719        setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
720                fullscreenStackBounds, dockedStackBounds); //设置SystemUIVisibilty
721        topAppWindowChanged(switches[2] != 0); //设置菜单键的可见性
722        // StatusBarManagerService has a back up of IME token and it's restored here.
723        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0); //根据输入法窗口的可见性调整导航栏的样式
724
725        // Set up the initial icon state
           //依次向系统状态去添加状态图标
726        int N = iconSlots.size();
727        for (int i=0; i < N; i++) {
728            mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
729        }
730
731        // Set up the initial notification state.
           //初始化通知栏
732        mNotificationListener.setUpWithPresenter(this, mEntryManager);
733
734        if (DEBUG) {
735            Log.d(TAG, String.format(
736                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
737                   icons.size(),
738                   switches[0],
739                   switches[1],
740                   switches[2],
741                   switches[3]
742                   ));
743        }
744
745        setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());
746
747        IntentFilter internalFilter = new IntentFilter();
748        internalFilter.addAction(BANNER_ACTION_CANCEL);
749        internalFilter.addAction(BANNER_ACTION_SETUP);
750        mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
751                null);
752
753        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
754                Context.VR_SERVICE));
755        try {
756            vrManager.registerListener(mVrStateCallbacks);
757        } catch (RemoteException e) {
758            Slog.e(TAG, "Failed to register VR mode state listener: " + e);
759        }
760
761        IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
762                ServiceManager.getService(Context.WALLPAPER_SERVICE));
763        try {
764            wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */);
765        } catch (RemoteException e) {
766            // Just pass, nothing critical.
767        }
768
769        // end old BaseStatusBar.start().
770
771        // Lastly, call to the icon policy to install/update all the icons.
           //最后,调用图标策略以安装/更新所有图标
772        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
773        mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
774
775        mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
776        mUnlockMethodCache.addListener(this);
777        startKeyguard();
778
779        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
780        putComponent(DozeHost.class, mDozeServiceHost);
781
782        mScreenPinningRequest = new ScreenPinningRequest(mContext);
783        mFalsingManager = FalsingManager.getInstance(mContext);
784
785        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
786
787        Dependency.get(ConfigurationController.class).addCallback(this);
788    }

StatusBar.java中有大量的代码。

mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE));

这一行获取IStatusBarService的实例。IStatusBarService是一个系统服务,由ServerThread启动并常驻system_seerver进程中。IStatusBarService为那些对状态栏感兴趣的其它系统服务定义了一系列API,然而对SystemUI而言,它更像一个客户端。因为IStatusBarService会将操作状态栏的请求发给SystemUI,并由后者完成请求。

这里主要看一下createAndAddWindows方法

状态栏的布局

状态栏需要显示的信息分为以下5种:

  • 通知信息:在状态栏左侧显示一个图标提醒用户,并在下拉卷帘中为用户显示更加详细的信息。
  • 时间信息:显示在状态栏最右侧的一般小型数字时钟,是一个名为Clock的继承自TextView的控件。监听了几个和时间有关的广播:ACTION_TIME_TICK、ACTION_TIME_CHANGED、ACTION_TIMEZONE_CHANGED、ACTION_CONFIGURAITON_CHANGED。当其中一个广播到来时从Calendar类中获取当前的系统时间,然后进行字符串格式化后显示出来。时间信息的维护工作在状态栏内部完成,外界无法通过API修改时间信息的显示或行为。
  • 电量信息:显示一个电池图标,用于提示设备当前的电量情况。它是一个被BatteryController类所管理的ImageView。BatteryController通过监听android.intent.action.ABTTERY_CHANGED广播以从BatteryService中获取电量信息。和时间信息一样,外界无法干预状态栏对电量信息的显示行为。
  • 信号信息:显示系统当前的WiFi、移动信号网络的信号状态。用户所看到的WiFi图标、手机信号图标、飞行模式图标都属于信号信息的范围。它们被NetworkController类维护着。NetworkController监听了一系列与信号相关的广播,如WIFI_STATE_CHANGED_ACTION 、WIFI_STATE_SIM_ACTION、ACTION_AIRPLANE_MODE_CHANGED等,并在这些广播到来时显示、更改或移除相关的图标。注意,在Android 8.0之后,手机信号图标不在通过ImageView而是通过自定义view实现。

系统状态图标区:这个区域用来显示系统当前的状态,比如可以展示蓝牙状态、闹铃等。StatusBarManagerService通过setIcon()接口为外界提供了修改系统状态图标的途径,但是它对信息的内容有很强的限制。1、系统状态图标无法显示图标以外的信息;2、系统状态图标对其显示的图标数量以及图标锁表示的意图有严格的限制。

我们继续分析createAndAddWindows

    public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
	    //创建状态栏的控件树
        makeStatusBarView();
        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
        mRemoteInputController = new RemoteInputController(mHeadsUpManager);
		//通过StatusBarWindowManager.add创建状态栏的窗口
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
    }
	/*
	*获取statusbar高度,在framework/base/core/res/res/values/diamens.xml中设置
	*/
    public int getStatusBarHeight() {
        if (mNaturalBarHeight < 0) {
            final Resources res = mContext.getResources();
            mNaturalBarHeight =
                    res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
        }
        return mNaturalBarHeight;
    }
	
    // ================================================================================
    // Constructing the view
    // ================================================================================
    protected void makeStatusBarView() {
        final Context context = mContext;
       //获取屏幕参数
        updateDisplaySize(); // populates mDisplayMetrics
       //更新Panels资源数据,statusbar包含很多panel,在创建PhoneStatusBarView时需要更新panel数据
        updateResources();
        updateTheme();

        inflateStatusBarWindow(context);  //加载布局
        mStatusBarWindow.setService(this);
        mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener()); //mStatusBarWindow的点击事件
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
        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)  //替换为CollapsedStatusBarFragment
                .commit();
        mIconController = Dependency.get(StatusBarIconController.class);
    }
	/*
	*加载布局
	*/
	protected void inflateStatusBarWindow(Context context) {
        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);
    }

调用流程是createAndAddWindows——>addStatusBarWindow——>makeStatusBarView

    /**
87     * Adds the status bar view to the window manager.
88     *
89     * @param statusBarView The view to add.
90     * @param barHeight The height of the status bar in collapsed state.
91     */
92    public void add(View statusBarView, int barHeight) {
93
94        // Now that the status bar window encompasses the sliding panel and its
95        // translucent backdrop, the entire thing is made TRANSLUCENT and is
96        // hardware-accelerated.
97        mLp = new WindowManager.LayoutParams(
98                ViewGroup.LayoutParams.MATCH_PARENT,
99                barHeight,
100                WindowManager.LayoutParams.TYPE_STATUS_BAR,
101                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
102                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
103                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
104                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
105                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
106                PixelFormat.TRANSLUCENT);
107        mLp.token = new Binder();
108        mLp.gravity = Gravity.TOP;
109        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
110        mLp.setTitle("StatusBar");
111        mLp.packageName = mContext.getPackageName();
112        mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
113        mStatusBarView = statusBarView;
114        mBarHeight = barHeight;
115        mWindowManager.addView(mStatusBarView, mLp);
116        mLpChanged = new WindowManager.LayoutParams();
117        mLpChanged.copyFrom(mLp);
118    }

状态栏的高度是从frameworks/base/core/res/res/values/dimens.xml中获取的,默认为25dp。TYPE_STATUS_BAR使得PhomeWindowManager
为状态栏的窗口分配了较大的layer值,使其可以显示在其它应用窗口上。FLAG_NOT_FOCUSABLE、FLAG_TOUCHABLE_WHEN_WAKING、FLAG_SPLIT_TOUCH
定义了输入事件的响应行为。另外当窗口创建后LayoutParams是会反生变化的。状态栏窗口创建时高度为25dip,flags描述为其不可接受按键事件。不过当用户
按下状态栏导致卷帘下拉时,StatusBar会通过WindowManager.updateViewLayout()方法修改窗口的LayoutParams高度为match_parent,即充满整个屏幕使得卷帘
可以满屏显示,并且移除FLAG_NOT_FOCUSABLE,使得StatusBar可以监听back按钮

在inflateStatusBarWindow会初始化布局

	<!-- This is the combined status bar / notification panel window. -->
	<-- StatusBarWindowView 继承于FrameLayout  -->
<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"
        />

    <com.android.systemui.statusbar.AlphaOptimizedView
        android:id="@+id/heads_up_scrim"
        android:layout_width="match_parent"
        android:layout_height="@dimen/heads_up_scrim_height"
        android:background="@drawable/heads_up_scrim"
        sysui:ignoreRightInset="true"
        android:importantForAccessibility="no"/>

    <FrameLayout
        android:id="@+id/status_bar_container" //顶部状态栏
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <include layout="@layout/brightness_mirror" /> //亮度调节

    <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"  //QuickSettings和Notification栏
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible" />

    <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>

在super_status_bar.xml文件中主要定义了三个布局顶部状态栏、亮度调节、QuickSettings和Notification。继续分析顶部状态栏,顶部状态栏是一个Fragment,布局文件是SystemUI/res/layout/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"
    >
    <!--notification_lights_out 一般情况下是不可见,在SystemUIVisiblity中有一个名为SYSTEM_UI_FLAG_LOW_PROFLE的标记
	当一个应用程序希望让客户注意力更对集中在它所显示的内容时,可以在其SystemUIVisiblity中添加这一标记,SYSTEM_UI_FLAG_LOW_PROFLE会使
	得状态栏与导航栏进入低识别度模式。低识别度模式下的状态栏将不会显示任何信息,只是在黑色背景中显示一个灰色圆点,这个圆点即这个-->
    <ImageView
        android:id="@+id/notification_lights_out"
        android:layout_width="@dimen/status_bar_icon_size"
        android:layout_height="match_parent"
        android:paddingStart="6dip"
        android:paddingBottom="2dip"
        android:src="@drawable/ic_sysbar_lights_out_dot_small"
        android:scaleType="center"
        android:visibility="gone"
        />
    <!-- status_bar_contents显示顶部状态栏的各种信息 -->
    <LinearLayout android:id="@+id/status_bar_contents"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingStart="6dp"
        android:paddingEnd="8dp"
        android:orientation="horizontal"
        >

        <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
             PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
		<!--消息通知 -->
        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/notification_icon_area"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" />
        <!--system_icon_area 继承一个LinearLayout 除消息通知以外的信息 -->
        <com.android.keyguard.AlphaOptimizedLinearLayout 
		    android:id="@+id/system_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            >
            <!--显示wifi SIM卡 电量等 -->
            <include layout="@layout/system_icons" />
            !--clock 显示时间信息 -->
            <com.android.systemui.statusbar.policy.Clock
                android:id="@+id/clock"
                android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:singleLine="true"
                android:paddingStart="@dimen/status_bar_clock_starting_padding"
                android:paddingEnd="@dimen/status_bar_clock_end_padding"
                android:gravity="center_vertical|start"
                />
        </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>

@+id/system_icon_area的宽度定义为ware_content,而@+id/notification_icon_area的weight被设置为1.在这种情况下system_icon_area将在状态栏右侧根据其所显示的图标个数调整其尺寸。而notification_icon_area则会占用状态栏左侧的剩余空间。这说明一个问题:系统图标区将优先占用状态栏的控件进行信息的显示。

面又嵌套了一个SystemUI/res/layout/system_icons.xml布局,system_icons里面包含电量、系统状态、信号等图标。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical">
    <!--系统状态图标 -->
    <com.android.keyguard.AlphaOptimizedLinearLayout 
	    android:id="@+id/statusIcons"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>
    <!--信号图标区域 -->
    <include layout="@layout/signal_cluster_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/signal_cluster_margin_start"/>
    <!--显示电量信息 -->
    <com.android.systemui.BatteryMeterView 
	    android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        />
</LinearLayout>

信号图标显示在signal_cluster_view.xml文件中,这里就不继续深入分析,等到分析信号时再做研究。

现在看一下状态栏的控件树结构

SystemUI常见问题修改

1、删除顶部状态栏

framework/base/core/res/res/values/dimens.xml中将status_bar_height设置为0dp

2、删除下方的导航栏

将qemu.hw.mainkeys属性设置为0

在看一下SystemUI的全套布局

参考资料:

Android 8.0 SystemUI(三):一说顶部 StatusBar

系统服务-SystemUI9.0

深入理解Android卷3

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值