美文网首页Android开发Android 源码浅析Android技术知识
Android 13.0 StatusBar顶部图标加载流程

Android 13.0 StatusBar顶部图标加载流程

作者: 孤街酒客0911 | 来源:发表于2022-11-28 20:07 被阅读0次

学习笔记:

说到 StatusBar 的顶部图标,就不得不提起以下两个类:

  • PhoneStatusBarPolicy:定义了系统通知图标的设置策略;
  • StatusBarSignalPolicy:定义了状态栏网络信号策略;

StatusBarSignalPolicy 前面有过分析,这次以 PhoneStatusBarPolicy 为例进行分析;

PhoneStatusBarPolicy 在 StatusBar 的 start() 方法里初始化:

// StatusBar.java 
@Override
public void start() {
    
    // 省略部分代码......
    mStatusBarSignalPolicy.init();  // 这里Android 13 与前面 Android 11 的初始化方法有点不同。

    // 创建整个SystemUI视图并添加到WindowManager中
    createAndAddWindows();//这个重点方法,创建相关的视图

    // 省略部分代码......

    // 调用图标策略来显示更新所有图标。
    mIconPolicy.init();

    // 省略部分代码......
}

这里直接看PhoneStatusBarPolicy#init() 这·个·方法很关键:

// PhoneStatusBarPolicy.java
 public void init() {
        // 注册广播监听。
        IntentFilter filter = new IntentFilter();
        // 耳机是否插入
        filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
        // SIM卡广播
        filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
        // TTY 模式已更改,(文字电话)
        filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
        // 可用 配置文件
        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
        // 不可用 配置文件
        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
        // 删除 配置文件
        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
        /// 添加用户切换操作以更新可能的警报图标
        filter.addAction(Intent.ACTION_USER_SWITCHED);

        // 向处理程序注册接收器
        mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler,UserHandle.ALL);
        // 注册闹钟已更改
        registerAlarmClockChanged(UserHandle.USER_OWNER, false);
        Observer<Integer> observer = ringer -> mHandler.post(this::updateVolumeZen);

        mRingerModeTracker.getRingerMode().observeForever(observer);
        mRingerModeTracker.getRingerModeInternal().observeForever(observer);

        // 监听用户配置文件更改.
        try {
            mIActivityManager.registerUserSwitchObserver(mUserSwitchListener, TAG);
        } catch (RemoteException e) {
            // Ignore
        }

        // TTY状态
        updateTTY();

        // 蓝牙状态
        updateBluetooth();


        //eMBMS状态
        mIconController.setIcon(mSlotEmbms, R.drawable.stat_sys_embms, null);
        mIconController.setIconVisibility(mSlotEmbms, false);

        // 闹钟
        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);

        // 振动
        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);

        // 热点
        mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
                mResources.getString(R.string.accessibility_status_bar_hotspot));
        mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());

        // managed profile
        updateManagedProfile();

        // 数据保护程序
        mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
                mResources.getString(R.string.accessibility_data_saver_on));
        mIconController.setIconVisibility(mSlotDataSaver, false);


        // 隐私 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);

        // 传感器关闭
        mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off,
                mResources.getString(R.string.accessibility_sensors_off_active));
        mIconController.setIconVisibility(mSlotSensorsOff,
                mSensorPrivacyController.isSensorPrivacyEnabled());

        // 录屏
        mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null);
        mIconController.setIconVisibility(mSlotScreenRecord, false);

        mRotationLockController.addCallback(this);
        mBluetooth.addCallback(this);
        mProvisionedController.addCallback(this);
        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);
    }

每个icon对应一个updatexxx(),依靠监听和回调机制,可以实现控制状态栏icon图标的显示、隐藏。

上述就是图标的加载显示和移除了,那么布局又是在哪添加的呢??


下面接着看 CollapsedStatusBarFragment ,启动方式前面讲过,这里不在重复;看其的 onViewCreated():
CollapsedStatusBarFragment #onViewCreated()

// CollapsedStatusBarFragment.java
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(this);
        mStatusBarFragmentComponent.init();

        mStatusBar = (PhoneStatusBarView) view;
        View contents = mStatusBar.findViewById(R.id.status_bar_contents);
        contents.addOnLayoutChangeListener(mStatusBarLayoutListener);
        updateStatusBarLocation(contents.getLeft(), contents.getRight());
        if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
            mStatusBar.restoreHierarchyState(
                    savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
        }
        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags);
        mDarkIconManager.setShouldLog(true);
        updateBlockedIcons();
        mStatusBarIconController.addIconGroup(mDarkIconManager);
        mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
        mClockView = mStatusBar.findViewById(R.id.clock);
        mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
        showSystemIconArea(false);
        showClock(false);
        initEmergencyCryptkeeperText();
        initOperatorName();
        initNotificationIconArea();
        mSystemEventAnimator =
                new StatusBarSystemEventAnimator(mSystemIconArea, getResources());
        mCarrierConfigTracker.addCallback(mCarrierConfigCallback);
        mCarrierConfigTracker.addDefaultDataSubscriptionChangedListener(mDefaultDataListener);
    }

补充:在 status_bar.xml 中

  • system_icon_area:就是显示蓝牙、wifi、VPN、网卡icon那块区域。

接着我看可以注意到这么几句代码:

        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags);
        mDarkIconManager.setShouldLog(true);
        updateBlockedIcons();
        // 添加图标组
        mStatusBarIconController.addIconGroup(mDarkIconManager);

上述 R.id.statusIcons 即是 system_icons.xml 里面的控件。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:systemui="http://schemas.android.com/apk/res-auto"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical|end"
    android:gravity="center_vertical">

    <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"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:clipToPadding="false"
        android:clipChildren="false"
        systemui:textAppearance="@style/TextAppearance.StatusBar.Clock" />
</LinearLayout>

我们接着看 StatusBarIconControllerImpl 的构造函数,因为 mStatusBarIconController 是一个接口,而其的实现类是 StatusBarIconControllerImpl。

 // StatusBarIconControllerImpl.java
    @Inject
    public StatusBarIconControllerImpl(
            Context context,
            CommandQueue commandQueue,
            DemoModeController demoModeController,
            ConfigurationController configurationController,
            TunerService tunerService,
            DumpManager dumpManager) {
        super(context.getResources().getStringArray(
                com.android.internal.R.array.config_statusBarIcons),context);
        // 省略部分代码......
    }

我们可以发现状态栏 icon 加载的图标来源于framework/base/core/res/res/values/config.xml 文件在这里我们就找到了 index 和 slot 的出处,原来在初始化的时候就已经定义好了所有的 slots,然后从 framework 中加载出来,index 就是 string-array 中的顺序。

   <string-array name="config_statusBarIcons">
        <item><xliff:g id="id">@string/status_bar_alarm_clock</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_rotate</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_headset</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_data_saver</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_ime</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sync_failing</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sync_active</xliff:g></item>
        ................
    </string-array>  

然后是 StatusBarIconControllerImpl.java 这个控制器来控制 icon 的加载显示和移除。

相关文章

网友评论

    本文标题:Android 13.0 StatusBar顶部图标加载流程

    本文链接:https://www.haomeiwen.com/subject/jnqaxdtx.html