这篇首要学习下非打开的状态栏,也便是缩短状态栏,下图红线部分

android framework13-SystemUi(02 CollapsedStatusBarFragment)

1.温习下StatusBarWindowView

温习下,上节5.3里面有讲,StatusBar加载的布局是R.layout.super_status_bar,下边再简略整理下相关的流程

首要CentralSurfacesImpl.java的结构办法里实例化了StatusBarWindowController.java,而StatusBarWindowController的结构办法里又实例化了StatusBarWindowView,完事attach办法addView

StatusBarWindowController

    @Inject
    public StatusBarWindowController(
            Context context,
            //结构办法传递的view
            @StatusBarWindowModule.InternalWindowView StatusBarWindowView statusBarWindowView,
 //...           
     public void attach() {
        mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
        // 增加view
        mWindowManager.addView(mStatusBarWindowView, mLp);

CentralSurfacesImpl.java里面会调用StatusBarWindowController的attach办法

    @Inject
    public CentralSurfacesImpl(
//...
            StatusBarWindowController statusBarWindowController,//controller
    //...
    public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
        makeStatusBarView(result);
        mNotificationShadeWindowController.attach();
        mStatusBarWindowController.attach();//这行
    }

getBarLayoutParams

如下,状态栏高度是固定的

    private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
        int height = SystemBarUtils.getStatusBarHeightForRotation(mContext, rotation);
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                height,

StatusBarWindowView

注解生成的,如下

@Module
abstract class StatusBarWindowModule {
    @Module
    companion object {
        @JvmStatic
        @Provides
        @SysUISingleton
        @InternalWindowView
        fun providesStatusBarWindowView(layoutInflater: LayoutInflater): StatusBarWindowView {
            return layoutInflater.inflate(
                R.layout.super_status_bar,
                /* root= */null
            ) as StatusBarWindowView?
}

布局super_status_bar

<!-- This is the status bar window. -->
<com.android.systemui.statusbar.window.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">
    <FrameLayout
        android:id="@+id/status_bar_launch_animation_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <FrameLayout
        android:id="@+id/status_bar_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/system_bar_background" />
</com.android.systemui.statusbar.window.StatusBarWindowView>

之后那个id为status_bar_container的布局会被替换成一个Fragment,详细逻辑在上节5.1的下边这行代码

## CentralSurfacesImpl.java
        // Set up CollapsedStatusBarFragment and PhoneStatusBarView
        StatusBarInitializer initializer = mCentralSurfacesComponent.getStatusBarInitializer();
//...
        initializer.initializeStatusBar(mCentralSurfacesComponent);

StatusBarInitializer

StatusBarInitializer.kt经过replace办法,把布局里的容器换成了Fragment

    fun initializeStatusBar(
        centralSurfacesComponent: CentralSurfacesComponent
    ) {
        windowController.fragmentHostManager.addTagListener(
                CollapsedStatusBarFragment.TAG,
                object : FragmentHostManager.FragmentListener {
                    override fun onFragmentViewCreated(tag: String, fragment: Fragment) {
                        val statusBarFragmentComponent = (fragment as CollapsedStatusBarFragment)
                                .statusBarFragmentComponent ?: throw IllegalStateException()
                        statusBarViewUpdatedListener?.onStatusBarViewUpdated(
                            statusBarFragmentComponent.phoneStatusBarView,//注解获取的
                            statusBarFragmentComponent.phoneStatusBarViewController,
                            statusBarFragmentComponent.phoneStatusBarTransitions
                        )
                        creationListeners.forEach { listener ->
                            listener.onStatusBarViewInitialized(statusBarFragmentComponent)
                        }
                    }
                    override fun onFragmentViewDestroyed(tag: String?, fragment: Fragment?) {
                        // nop
                    }
                }).fragmentManager
                .beginTransaction()
                .replace(R.id.status_bar_container,//这儿
                        centralSurfacesComponent.createCollapsedStatusBarFragment(),//替换的fragment
                        CollapsedStatusBarFragment.TAG)
                .commit()
    }

centralSurfacesComponent.createCollapsedStatusBarFragment() 这个注解生成的fragment便是下边要讲的

2.CollapsedStatusBarFragment

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

status_bar.xml

先看下这个fragment加载的布局。

<?xml version="1.0" encoding="utf-8"?>
## 帧布局
<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: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:paddingTop="@dimen/status_bar_padding_top"
        android:orientation="horizontal">
        <!-- Container for the entire start half of the status bar. It will always use the same
             width, independent of the number of visible children and sub-children. -->
        <FrameLayout
            android:id="@+id/status_bar_start_side_container"
            android:layout_height="match_parent"
            android:layout_width="0dp"
            android:clipChildren="false"
            android:layout_weight="1">
            <!-- Container that is wrapped around the views on the start half of the status bar.
                 Its width will change with the number of visible children and sub-children.
                 It is useful when we want to know the visible bounds of the content. -->
            <FrameLayout
                android:id="@+id/status_bar_start_side_content"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:clipChildren="false">
                <include layout="@layout/heads_up_status_bar_layout" />
                <!-- The alpha of the start side is controlled by PhoneStatusBarTransitions, and the
                     individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK
                     and DISABLE_NOTIFICATION_ICONS, respectively -->
                <LinearLayout
                    android:id="@+id/status_bar_start_side_except_heads_up"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:clipChildren="false">
                    <ViewStub
                        android:id="@+id/operator_name"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout="@layout/operator_name" />
                    <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"
                    />
                    <include layout="@layout/ongoing_call_chip" />
                    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
                        android:id="@+id/notification_icon_area"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:orientation="horizontal"
                        android:clipChildren="false"/>
                </LinearLayout>
            </FrameLayout>
        </FrameLayout>
        <!-- Space should cover the notch (if it exists) and let other views lay out around it -->
        <android.widget.Space
            android:id="@+id/cutout_space_view"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:gravity="center_horizontal|center_vertical"
        />
        <!-- Container for the entire end half of the status bar. It will always use the same
             width, independent of the number of visible children and sub-children. -->
        <FrameLayout
            android:id="@+id/status_bar_end_side_container"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:clipChildren="false">
            <!-- Container that is wrapped around the views on the end half of the
                 status bar. Its width will change with the number of visible children and
                 sub-children.
                 It is useful when we want know the visible bounds of the content.-->
            <com.android.keyguard.AlphaOptimizedLinearLayout
                android:id="@+id/status_bar_end_side_content"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_gravity="end"
                android:orientation="horizontal"
                android:gravity="center_vertical|end"
                android:clipChildren="false">
                <include
                    android:id="@+id/user_switcher_container"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
                    layout="@layout/status_bar_user_chip_container" />
                <include layout="@layout/system_icons" />
            </com.android.keyguard.AlphaOptimizedLinearLayout>
        </FrameLayout>
    </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>

其他相关的布局 ongoing_call_chip.xml


<!-- Have the wrapper frame layout match the parent height so that we get a larger touch area for
     the chip. -->
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ongoing_call_chip"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical|start"
    android:layout_marginStart="5dp"
>
    <LinearLayout
        android:id="@+id/ongoing_call_chip_background"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/ongoing_appops_chip_height"
        android:layout_gravity="center_vertical"
        android:gravity="center"
        android:background="@drawable/ongoing_call_chip_bg"
        android:paddingStart="@dimen/ongoing_call_chip_side_padding"
        android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
        android:contentDescription="@string/ongoing_phone_call_content_description"
        android:minWidth="@dimen/min_clickable_item_size"
    >
        <ImageView
            android:src="@*android:drawable/ic_phone"
            android:layout_width="@dimen/ongoing_call_chip_icon_size"
            android:layout_height="@dimen/ongoing_call_chip_icon_size"
            android:tint="?android:attr/colorPrimary"
        />
        <com.android.systemui.statusbar.phone.ongoingcall.OngoingCallChronometer
            android:id="@+id/ongoing_call_chip_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:gravity="center|start"
            android:paddingStart="@dimen/ongoing_call_chip_icon_text_padding"
            android:textAppearance="@android:style/TextAppearance.Material.Small"
            android:fontFamily="@*android:string/config_headlineFontFamily"
            android:textColor="?android:attr/colorPrimary"
        />
    </LinearLayout>
</FrameLayout>

1.PhoneStatusBarView

这个类首要计算下status bar的高度,监听下clock,batter图标的漆黑颜色变化,还有cutout_space_view的大小动态设置

public class PhoneStatusBarView extends FrameLayout {

简化下status_bar.xml布局如下,首要看下核心的第二层,里面有2个帧布局,比重是都是1

<com.android.systemui.statusbar.phone.PhoneStatusBarView
    >
## 第一层
    <ImageView
        android:id="@+id/notification_lights_out"
        />
## 第二层
    <LinearLayout android:id="@+id/status_bar_contents"
        <FrameLayout
            android:id="@+id/status_bar_start_side_container"
        <android.widget.Space
            android:id="@+id/cutout_space_view"
        />
        <FrameLayout
            android:id="@+id/status_bar_end_side_container"
        </FrameLayout>
    </LinearLayout>
## 第三层
    <ViewStub
        android:layout="@layout/emergency_cryptkeeper_text"
    />
</com.android.systemui.statusbar.phone.PhoneStatusBarView>

下边就详细来看下第二层布局里,左右两部分ui都有啥

>status_bar_start_side_container

状态栏左边部分

<LinearLayout android:id="@+id/status_bar_start_side_except_heads_up" >
# 像是sim卡运营商的姓名,调用的getCarrierName办法,fragment里初始化的
<ViewStub android:id="@+id/operator_name" 
android:layout="@layout/operator_name" /> 
# 当前时刻
<com.android.systemui.statusbar.policy.Clock 
android:id="@+id/clock"  /> 
# 通话时长
<include layout="@layout/ongoing_call_chip" /> 
# 其他告诉icon
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"/> 
</LinearLayout>

>status_bar_end_side_container

状态栏右侧部分

        <FrameLayout
            android:id="@+id/status_bar_end_side_container">
            <com.android.keyguard.AlphaOptimizedLinearLayout
                android:id="@+id/status_bar_end_side_content">
# 当前用户的信息,头像和姓名
                <include
                    android:id="@+id/user_switcher_container"
                    layout="@layout/status_bar_user_chip_container" />
#系统icons
                <include layout="@layout/system_icons" />
            </com.android.keyguard.AlphaOptimizedLinearLayout>
        </FrameLayout>

布局system_icons.xml 能够看到,右侧固定有个电池图标

<LinearLayout
    android:layout_gravity="center_vertical|end"
    android:gravity="center_vertical">
## 这儿是动态增加的icon
    <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:paddingEnd="@dimen/signal_cluster_battery_padding"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>
## 固定有个电池控件
    <com.android.systemui.battery.BatteryMeterView android:id="@+id/battery" />
</LinearLayout>

2.onViewCreated

    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
//...
        mStatusBarFragmentComponent.init();
//...
        mStatusBar = (PhoneStatusBarView) view;
//...
//statusIcons便是右侧的icon容器,电量图标左边的部分
        mDarkIconManager = mDarkIconManagerFactory.create(
                view.findViewById(R.id.statusIcons), StatusBarLocation.HOME);
//...
        updateBlockedIcons();//便是默许不显现的icon,从装备里读取,然后赋值给IconManager,显现的时分会判别过滤掉
        mStatusBarIconController.addIconGroup(mDarkIconManager);//详细逻辑见下边概况
//...
        initNotificationIconArea();//状态栏左边时刻控件右边的icons容器
//...
    }

>DarkIconManager

继承IconManager,首要处理icon的动态增加逻辑,create办法第一个参数,便是icon要增加到的viewGroup

            public DarkIconManager create(LinearLayout group, StatusBarLocation location) {
                return new DarkIconManager(
                        group,
                        location,
        public DarkIconManager(
                LinearLayout linearLayout,
                StatusBarLocation location,
//...
                DarkIconDispatcher darkIconDispatcher) {
            super(linearLayout,
                    location,

IconManager,能够看到blocked字段对wifi和mobile图标是不收效的。

        public IconManager(
                ViewGroup group,
                StatusBarLocation location,
                //...
        ) {
            mGroup = group;
            mStatusBarPipelineFlags = statusBarPipelineFlags;
        public void setBlockList(@Nullable List<String> blockList) {
            mBlockList.clear();
            mBlockList.addAll(blockList);
            if (mController != null) {
                mController.refreshIconGroup(this);
            }
        }  
        protected void onIconAdded(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            addHolder(index, slot, blocked, holder);
        }
        protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            // This is a little hacky, and probably regrettable, but just set `blocked` on any icon
            // that is in our blocked list, then we'll never see it
            if (mBlockList.contains(slot)) {
                blocked = true;
            }
            //下边add办法便是把view增加到mGroup里
            switch (holder.getType()) {
                case TYPE_ICON:
                    return addIcon(index, slot, blocked, holder.getIcon());
                case TYPE_WIFI:
                    return addWifiIcon(index, slot, holder.getWifiState());
                case TYPE_WIFI_NEW:
                    return addNewWifiIcon(index, slot);
                case TYPE_MOBILE:
                    return addMobileIcon(index, slot, holder.getMobileState());
                case TYPE_MOBILE_NEW:
                    return addNewMobileIcon(index, slot, holder.getTag());
            }
            return null;
        }        

>config_collapsed_statusbar_icon_blocklist

    <!-- Icons that don't show in a collapsed non-keyguard statusbar -->
    <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
        <item>@*android:string/status_bar_volume</item>
        <item>@*android:string/status_bar_alarm_clock</item>
        <item>@*android:string/status_bar_call_strength</item>
    </string-array>

>addIconGroup办法

办法的完成是在这个类里frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java

    public void addIconGroup(IconManager group) {
//...
        group.setController(this);
        mIconGroups.add(group);
        List<Slot> allSlots = mStatusBarIconList.getSlots();
        for (int i = 0; i < allSlots.size(); i++) {
            Slot slot = allSlots.get(i);
            List<StatusBarIconHolder> holders = slot.getHolderListInViewOrder();
            boolean hidden = mIconHideList.contains(slot.getName());
//这儿刚开始holders调集是空的,所以啥也没干
            for (StatusBarIconHolder holder : holders) {
                int viewIndex = mStatusBarIconList.getViewIndex(slot.getName(), holder.getTag());
                group.onIconAdded(viewIndex, slot.getName(), hidden, holder);
            }
        }
    }

>>StatusBarIconList

这个目标是注解生成的,数据是装备里读取的,相关的数组在frameworks/base/core/res/res/values/config.xml 数组长度有30多个,就不贴了。

    @Provides
    @SysUISingleton
    static StatusBarIconList provideStatusBarIconList(Context context) {
        return new StatusBarIconList(
                context.getResources().getStringArray(
                        com.android.internal.R.array.config_statusBarIcons));
    }
public class StatusBarIconList {
    private final ArrayList<Slot> mSlots = new ArrayList<>();
    private final List<Slot> mViewOnlySlots = Collections.unmodifiableList(mSlots);
    public StatusBarIconList(String[] slots) {
        final int N = slots.length;
        for (int i = 0; i < N; i++) {
            mSlots.add(new Slot(slots[i], null));//就个姓名
        }
    }
    /** Returns the list of current slots. */
    public List<Slot> getSlots() {
        return mViewOnlySlots;
    }

能够看到,默许的Slot就姓名不是空的,其他都是空的,所以下边if条件都不满足。

        public List<StatusBarIconHolder> getHolderListInViewOrder() {
            ArrayList<StatusBarIconHolder> holders = new ArrayList<>();
            if (mSubSlots != null) {
                for (int i = mSubSlots.size() - 1; i >= 0; i--) {
                    holders.add(mSubSlots.get(i));
                }
            }
            if (mHolder != null) {
                holders.add(mHolder);
            }
            return holders;
        }

Fragment里代码看完了,没有发现增加icon的当地

3.onIconAdded

        protected void onIconAdded(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            addHolder(index, slot, blocked, holder);
        }

找不到icon哪里增加的,那从最基本的来找,便是前边的贴的IconManager里有addView的办法,所以查看哪里调用即可。我们Fragment里用到的是DarkIconManager,查下里面的onIconAdded办法都哪里用到,很简单找到StatusBarIconControllerImpl.java里有用到,这个类里有许多setIcon的办法,找些哪里用的, 最后发现icon都在下边2个XXXPolicy类里增加的。

4.PhoneStatusBarPolicy(一般图标)

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

>初始化

这个类是CentralSurfacesImpl的结构办法里生成的,然后在其start办法里init的,如下

//上一篇说过的,这个start会主动履行的
    public void start() {
    //...
       // Lastly, call to the icon policy to install/update all the icons.
        mIconPolicy.init();

CentralSurfacesImpl是完成接口CoreStartable的,会主动履行start办法

public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {

>init办法

持续看这个类的init办法,能够看到里面增加的icon都默许不可见的,这儿应该便是初始化下icon数据,办法最后是一些监听回调,会动态修正图标的可见性。

        // TTY status: teletypewriter,电传打字机的缩写,指的是一种用于文本通讯的设备
        updateTTY();
        // bluetooth status ,看了下逻辑,只有在蓝牙衔接而且audio正常的情况下才有这个图标
        updateBluetooth();
        // Alarm clock
        mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
        mIconController.setIconVisibility(mSlotAlarmClock, false);
        // zen
        mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null);
        mIconController.setIconVisibility(mSlotZen, false);
        // vibrate
        mIconController.setIcon(mSlotVibrate, R.drawable.stat_sys_ringer_vibrate,
                mResources.getString(R.string.accessibility_ringer_vibrate));
        mIconController.setIconVisibility(mSlotVibrate, false);
        // mute
        mIconController.setIcon(mSlotMute, R.drawable.stat_sys_ringer_silent,
                mResources.getString(R.string.accessibility_ringer_silent));
        mIconController.setIconVisibility(mSlotMute, false);
        updateVolumeZen();
        // cast
        mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
        mIconController.setIconVisibility(mSlotCast, false);
        // hotspot
        mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
                mResources.getString(R.string.accessibility_status_bar_hotspot));
        mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
        // managed profile
        updateManagedProfile();
        // data saver
        mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
                mResources.getString(R.string.accessibility_data_saver_on));
        mIconController.setIconVisibility(mSlotDataSaver, false);
        // privacy items
        String microphoneString = mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId());
        String microphoneDesc = mResources.getString(
                R.string.ongoing_privacy_chip_content_multiple_apps, microphoneString);
        mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(),
                microphoneDesc);
        mIconController.setIconVisibility(mSlotMicrophone, false);
        String cameraString = mResources.getString(PrivacyType.TYPE_CAMERA.getNameId());
        String cameraDesc = mResources.getString(
                R.string.ongoing_privacy_chip_content_multiple_apps, cameraString);
        mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(),
                cameraDesc);
        mIconController.setIconVisibility(mSlotCamera, false);
        mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
                mResources.getString(R.string.accessibility_location_active));
        mIconController.setIconVisibility(mSlotLocation, false);
        // sensors off
        mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off,
                mResources.getString(R.string.accessibility_sensors_off_active));
        mIconController.setIconVisibility(mSlotSensorsOff,
                mSensorPrivacyController.isSensorPrivacyEnabled());
        // screen record
        mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null);
        mIconController.setIconVisibility(mSlotScreenRecord, false);
//下边这些回调,会动态修正图标的可见性
        mRotationLockController.addCallback(this);
        mBluetooth.addCallback(this);
        mProvisionedController.addCallback(this);
        mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
        mZenController.addCallback(this);
        mCast.addCallback(mCastCallback);
        mHotspot.addCallback(mHotspotCallback);
        mNextAlarmController.addCallback(mNextAlarmCallback);
        mDataSaver.addCallback(this);
        mKeyguardStateController.addCallback(this);
        mPrivacyItemController.addCallback(this);
        mSensorPrivacyController.addCallback(mSensorPrivacyListener);
        mLocationController.addCallback(this);
        mRecordingController.addCallback(this);
        mCommandQueue.addCallback(this);
    }

5 StatusBarSignalPolicy(信号图标)

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

>初始化

同上,也是CentralSurfacesImpl.java结构办法里实例化目标,start办法里履行init办法

    public void start() {
//...
        mStatusBarSignalPolicy.init();

>init办法

在监听里处理icon的

    public void init() {
        if (mInitialized) {
            return;
        }
        mInitialized = true;
        mTunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
        mNetworkController.addCallback(this);
        mSecurityController.addCallback(this);
    }

看下这个类用到的字符串,就知道他都处理哪些图标了

        mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
        mSlotMobile   = mContext.getString(com.android.internal.R.string.status_bar_mobile);
        mSlotWifi     = mContext.getString(com.android.internal.R.string.status_bar_wifi);
        mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);
        mSlotVpn      = mContext.getString(com.android.internal.R.string.status_bar_vpn);
        mSlotNoCalling = mContext.getString(com.android.internal.R.string.status_bar_no_calling);
        mSlotCallStrength =
                mContext.getString(com.android.internal.R.string.status_bar_call_strength);
        mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);

6.setIcon

上边剖析过,StatusBarIconControllerImpl.java里有许多setIcon的办法,如下图

android framework13-SystemUi(02 CollapsedStatusBarFragment)
这儿就拿其间一种来剖析下流程,默许的holder是null的,所以下边的代码会进入if,创立新的holder

    public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
        StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, 0);
        if (holder == null) {
        //实例化一个icon目标
            StatusBarIcon icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
                    Icon.createWithResource(
                            mContext, resourceId), 0, 0, contentDescription);
                            //创立holder目标,并把icon赋值给holder目标
            holder = StatusBarIconHolder.fromIcon(icon);
            setIcon(slot, holder);
        } else {
        //更新下icon信息即可
            holder.getIcon().icon = Icon.createWithResource(mContext, resourceId);
            holder.getIcon().contentDescription = contentDescription;
            handleSet(slot, holder);
        }
    }

>StatusBarIconHolder.fromIcon(icon)

   public static StatusBarIconHolder fromIcon(StatusBarIcon icon) {
        StatusBarIconHolder wrapper = new StatusBarIconHolder();
        wrapper.mIcon = icon;
        return wrapper;
    }

>setIcon

前边剖析过mStatusBarIconList时注解生成的,默许里面的holder是null的,所以这儿判别下,为null就addIcon,不为null就做更新操作

    private void setIcon(String slot, @NonNull StatusBarIconHolder holder) {
        boolean isNew = mStatusBarIconList.getIconHolder(slot, holder.getTag()) == null;
        mStatusBarIconList.setIcon(slot, holder);//给对应的icon设置holder
        if (isNew) {
            addSystemIcon(slot, holder);
        } else {
            handleSet(slot, holder);
        }
    }

持续

    private void addSystemIcon(String slot, StatusBarIconHolder holder) {
        int viewIndex = mStatusBarIconList.getViewIndex(slot, holder.getTag());
        boolean hidden = mIconHideList.contains(slot);
//这个是增加新的icon  view,mIconGroups里目前已知的是那个 mDarkIconManager
        mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
    }

>handleSet

    private void handleSet(String slotName, StatusBarIconHolder holder) {
        int viewIndex = mStatusBarIconList.getViewIndex(slotName, holder.getTag());
        //这儿是找到就的icon view,更新其显现的图标
        mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
    }

7.Icon的品种

首要就一般的icon和特别的icon(wifi,mobile)

>一般的icon

        protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
                StatusBarIcon icon) {
            StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
            view.set(icon);
            mGroup.addView(view, index, onCreateLayoutParams());
            return view;
        }
        private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
            return new StatusBarIconView(mContext, slot, null, blocked);
        }

StatusBarIconView

public class StatusBarIconView extends AnimatedImageView implements StatusIconDisplayable {

view.set(icon)的办法,看下可见性的处理。能够看到,需求是icon自身可见而且block为false。

        if (!visibilityEquals) {
            setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
        }
        return true;
    }

>特别的icon(wifi,mobile)

wifi ,new wifi ,mobile ,new mobile 是4种不同的view

final StatusBarWifiView view = onCreateStatusBarWifiView(slot);
ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
StatusBarMobileView mobileView = onCreateStatusBarMobileView(state.subId, slot);
BaseStatusBarFrameLayout view = onCreateModernStatusBarMobileView(slot, subId);

>>新旧icon显现的判别

那么到底显现新的还是旧的,咋判别的?如下,能够看到是statusBarPipelineFlags这个类决议的

        public IconManager(
                ViewGroup group,
                StatusBarLocation location,
                StatusBarPipelineFlags statusBarPipelineFlags,
                WifiUiAdapter wifiUiAdapter,
                MobileUiAdapter mobileUiAdapter,
                MobileContextProvider mobileContextProvider
        ) {
            mGroup = group;
            mStatusBarPipelineFlags = statusBarPipelineFlags;
            mMobileContextProvider = mobileContextProvider;
            mContext = group.getContext();
            mIconSize = mContext.getResources().getDimensionPixelSize(
                    com.android.internal.R.dimen.status_bar_icon_size);
            mLocation = location;
//是否是新的mobile icon
            if (statusBarPipelineFlags.runNewMobileIconsBackend()) {
                // This starts the flow for the new pipeline, and will notify us of changes if
                // {@link StatusBarPipelineFlags#useNewMobileIcons} is also true.
                mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
                MobileIconsBinder.bind(mGroup, mMobileIconsViewModel);
            } else {
                mMobileIconsViewModel = null;
            }
//是否是新的wifi icon
            if (statusBarPipelineFlags.runNewWifiIconBackend()) {
                // This starts the flow for the new pipeline, and will notify us of changes if
                // {@link StatusBarPipelineFlags#useNewWifiIcon} is also true.
                mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
            } else {
                mWifiViewModel = null;
            }
        }

持续,能够看到,又是由FeatureFlags决议,这个东西是个接口,有两种完成

class StatusBarPipelineFlags @Inject constructor(private val featureFlags: FeatureFlags) {
    fun useNewMobileIcons(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS)
    fun runNewMobileIconsBackend(): Boolean =
        featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS_BACKEND) || useNewMobileIcons()
    fun useNewWifiIcon(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON)
    fun runNewWifiIconBackend(): Boolean =
        featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON_BACKEND) || useNewWifiIcon()

如下,都是false

public class FeatureFlagsRelease implements FeatureFlags {
    public boolean isEnabled(@NotNull UnreleasedFlag flag) {
        return false;
    }

debug模式下,能够看到直接用的便是参数flag的默许的值,详细的能够点进去用到的flag查看,默许都是false的

public class FeatureFlagsDebug implements FeatureFlags {
    public boolean isEnabled(@NotNull UnreleasedFlag flag) {
        return isEnabledInternal(flag);
    }
    private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
        int id = flag.getId();
        if (!mBooleanFlagCache.containsKey(id)) {
            mBooleanFlagCache.put(id,
                    readBooleanFlagInternal(flag, flag.getDefault()));
        }
        return mBooleanFlagCache.get(id);
    }

>>addMobileIcon

            StatusBarMobileView mobileView = onCreateStatusBarMobileView(state.subId, slot);
            StatusBarMobileView view = StatusBarMobileView
                    .fromContext(mobileContext, slot);
            return view;
    public static StatusBarMobileView fromContext(
            Context context,
            String slot
    ) {
        LayoutInflater inflater = LayoutInflater.from(context);
        StatusBarMobileView v = (StatusBarMobileView)
                inflater.inflate(R.layout.status_bar_mobile_signal_group, null);
        v.setSlot(slot);
        v.init();
        v.setVisibleState(STATE_ICON);
        return v;
    }

布局看下

<com.android.systemui.statusbar.StatusBarMobileView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mobile_combo"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical" >
    <include layout="@layout/status_bar_mobile_signal_group_inner" />
</com.android.systemui.statusbar.StatusBarMobileView>

status_bar_mobile_signal_group_inner.xml

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res-auto" >
    <com.android.keyguard.AlphaOptimizedLinearLayout
        android:id="@+id/mobile_group"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal" >
//移动数据的接纳发送,图片是向上向下的箭头
        <FrameLayout
            android:id="@+id/inout_container"
            android:layout_height="17dp"
            android:layout_width="wrap_content"
            android:layout_gravity="center_vertical">
            <ImageView
                android:id="@+id/mobile_in"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:src="@drawable/ic_activity_down"
                android:visibility="gone"
                android:paddingEnd="2dp"
                />
            <ImageView
                android:id="@+id/mobile_out"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:src="@drawable/ic_activity_up"
                android:paddingEnd="2dp"
                android:visibility="gone"
                />
        </FrameLayout>
        //移动数据的类型
        <ImageView
            android:id="@+id/mobile_type"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_gravity="center_vertical"
            android:paddingStart="2.5dp"
            android:paddingEnd="1dp"
            android:visibility="gone" />
        <Space
            android:id="@+id/mobile_roaming_space"
            android:layout_height="match_parent"
            android:layout_width="@dimen/roaming_icon_start_padding"
            android:visibility="gone"
            />
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical">
            <com.android.systemui.statusbar.AnimatedImageView
                android:id="@+id/mobile_signal"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                systemui:hasOverlappingRendering="false"
                />
                //小的漫游图标,左上角一个R
            <ImageView
                android:id="@+id/mobile_roaming"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/stat_sys_roaming"
                android:contentDescription="@string/data_connection_roaming"
                android:visibility="gone" />
        </FrameLayout>
        //大的漫游图标,居中的R
        <ImageView
            android:id="@+id/mobile_roaming_large"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/stat_sys_roaming_large"
            android:contentDescription="@string/data_connection_roaming"
            android:visibility="gone" />
    </com.android.keyguard.AlphaOptimizedLinearLayout>
</merge>

addWifiIcon

        private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
            StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, slot);
            return view;
        }
    public static StatusBarWifiView fromContext(Context context, String slot) {
        LayoutInflater inflater = LayoutInflater.from(context);
        StatusBarWifiView v = (StatusBarWifiView) inflater.inflate(R.layout.status_bar_wifi_group, null);
        v.setSlot(slot);
        v.init();
        v.setVisibleState(STATE_ICON);
        return v;
    }

布局就不贴了,自己看下

8. exclude

便是决议哪些图标不显现,能够在装备里增加

>初始过滤

假如图标不想让它显现,把它增加在这儿就行了。

    <string-array name="config_statusBarIconsToExclude" translatable="false">
        <item>@*android:string/status_bar_rotate</item>
        <item>@*android:string/status_bar_headset</item>
        <item>@*android:string/status_bar_screen_record</item>
    </string-array>

StatusBarIconControllerImpl.java

    public void onTuningChanged(String key, String newValue) {
        if (!ICON_HIDE_LIST.equals(key)) {
            return;
        }
        mIconHideList.clear();
        mIconHideList.addAll(StatusBarIconController.getIconHideList(mContext, newValue));

数据获取

    static ArraySet<String> getIconHideList(Context context, String hideListStr) {
        ArraySet<String> ret = new ArraySet<>();
        String[] hideList = hideListStr == null
                ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
                : hideListStr.split(",");
        for (String slot : hideList) {
            if (!TextUtils.isEmpty(slot)) {
                ret.add(slot);
            }
        }
        return ret;
    }

这个调集的调用当地

    private void addSystemIcon(String slot, StatusBarIconHolder holder) {
        int viewIndex = mStatusBarIconList.getViewIndex(slot, holder.getTag());
        boolean hidden = mIconHideList.contains(slot);
        mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
    }

>2次过滤

过滤的icon在这个数组里config_collapsed_statusbar_icon_blocklist,所以不想显现的图标也能够写在这个数组里。CollapsedStatusBarFragment.java

    void updateBlockedIcons() {
        mBlockedIcons.clear();
        // Reload the blocklist from res
        List<String> blockList = Arrays.asList(getResources().getStringArray(
                R.array.config_collapsed_statusbar_icon_blocklist));
        String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume);
        boolean showVibrateIcon =//
        // Filter out vibrate icon from the blocklist if the setting is on
        mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
    }

IconManager

        public void setBlockList(@Nullable List<String> blockList) {
            Assert.isMainThread();
            mBlockList.clear();
            mBlockList.addAll(blockList);
            if (mController != null) {
                mController.refreshIconGroup(this);
            }
        }

需求注意:wifi和mobile是不受这个block影响的。

        protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
//2次判别
            if (mBlockList.contains(slot)) {
                blocked = true;
            }
            switch (holder.getType()) {
                case TYPE_ICON:
                    return addIcon(index, slot, blocked, holder.getIcon());
                case TYPE_WIFI:
                    return addWifiIcon(index, slot, holder.getWifiState());
                case TYPE_MOBILE:
                    return addMobileIcon(index, slot, holder.getMobileState());
            }
        }

3.总结

这篇首要介绍了状态栏(非打开状态)的图标显现逻辑。

  • StatusBarView的增加
  • 经过CollapsedStatusBarFragment管理icon的显现
  • icon的管理类有2个,PhoneStatusBarPollicy以及StatusBarSignalPolicy
  • 能够在string里装备哪些icon不用显现