前言

上一篇我们具体分析了系统状态栏StatusBar的创建过程,其中状态栏视图就存储在CollapsedStatusBarFragment中,这个视图被添加到id为status_bar_container的容器中,而CollapsedStatusBarFragment会去加载status_bar.xml布局文件,从该布局文件的内容可以知道系统状态栏主要由三个部分组成。

  1. 最左边的一部分显示运营商,时间,通知图标。
  2. 最右边的一部分显示系统图标,它由状态图标(例如 wifi ,bt)和电池图标组成。

本文我们主要来分析一下系统状态栏图标(例如 wifi ,bt)是如何被控制显示的。

一、注册状态栏图标管理器

1、在CollapsedStatusBarFragment的onViewCreated方法中,会进行图标管理器的注册。

import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {...@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,Bundle savedInstanceState) {//系统状态栏所对应的布局文件return inflater.inflate(R.layout.status_bar, container, false);}@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);mStatusBar = (PhoneStatusBarView) view;if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));}//创建一个状态图标区的图标管理器,R.id.statusIcons代表状态图标区,例如bt, wifimDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));mDarkIconManager.setShouldLog(true);//向StatusBarIconControllerImpl注册图标管理器Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);mClockView = mStatusBar.findViewById(R.id.clock);showSystemIconArea(false);showClock(false);initEmergencyCryptkeeperText();initOperatorName();}...
}

2、上面的代码中有通过Dependency对象来获取StatusBarIconController的对象实例,关于Dependency组件,它和StatusBar组件一样都是存储在config_systemUIServiceComponents中的,如下所示:

    <string-array name="config_systemUIServiceComponents" translatable="false"><item>com.android.systemui.Dependency</item><item>com.android.systemui.SystemBars</item>...</string-array>

前面的篇章我们有讲过,SystemUIApplication的startServicesIfNeeded方法会依次实例化config_systemUIServiceComponents里面的所有组件并调用其start方法,这就意味着Dependency组件也是在SystemUIApplication中被实例化并调用start方法的。Dependency类的start方法会在mProviders中存储许多常用的键值对,比如我们现在获取的key为StatusBarIconController,value为StatusBarIconController的键值对,这样后续Dependency.get(StatusBarIconController.class)才能获取到StatusBarIconControllerImpl实例对象,关键代码如下所示:

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

public class Dependency extends SystemUI {...private final ArrayMap<Object, DependencyProvider> mProviders = new ArrayMap<>();@Overridepublic void start() {...//在mProviders中存储StatusBarIconController的具体实例对象mProviders.put(StatusBarIconController.class, () -> new StatusBarIconControllerImpl(mContext));...    }...
}

二、状态栏图标控制器

状态栏上状态图标的控制,都要通过一个接口来实现,这个接口就是StatusBarIconController,该接口的部分代码如下所示:

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

public interface StatusBarIconController {// 设置图标public void setIcon(String slot, int resourceId, CharSequence contentDescription);public void setIcon(String slot, StatusBarIcon icon);// 设置wifi图标public void setSignalIcon(String slot, WifiIconState state);// 设置手机信号图标public void setMobileIcons(String slot, List<MobileIconState> states);// 设置图标可见性public void setIconVisibility(String slot, boolean b);
}

而它的实现类是 StatusBarIconControllerImpl,注释说它接收来自CommandQueue关于图标的回调,然后分发给已经注册的IconManager。然而它的功能还不仅仅如此,SystemUI在任何地方都可以调用它来给状态栏设置图标,因为它还实现了StatusBarIconController接口,这个接口部分内容如下:

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

/*** Receives the callbacks from CommandQueue related to icons and tracks the state of* all the icons. Dispatches this state to any IconManagers that are currently* registered with it.*/
public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable,ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController {...public StatusBarIconControllerImpl(Context context) {// 通过父类保存状态栏上图标的名字super(context.getResources().getStringArray(com.android.internal.R.array.config_statusBarIcons));// 注册CommandQueue的回调Dependency.get(ConfigurationController.class).addCallback(this);mContext = context;loadDimens();SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallbacks(this);// 实现黑名单的功能,原理是监听数据库中黑名单的值Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);}...
}

这里主要做了三件事

  1. 保存状态栏上图标的名字。
  2. 向CommandQueue 注册回调。
  3. 监听数据库黑名单。

黑名单的功能很简单,就是监听数据库中关于黑名单的URI的变化,然后更新黑名单列表,然后在设置图标的时候去查询黑名单,再决定如何设置。
CommandQueue是一个Binder类,它被StatusBar#start()注册到了StatusBarManagerService中,用于接收服务端的消息,其实就相当于在服务端注册了一个回调。而StatusBarIconControllerImpl向CommandQueue注册回调,是为了获取关于图标的消息,以便它能正确地在状态栏上设置图标。下面来看下保存的图标名字的数组 config_statusBarIcons:

frameworks/base/core/res/res/values/config.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"><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><item><xliff:g id="id">@string/status_bar_nfc</xliff:g></item><item><xliff:g id="id">@string/status_bar_tty</xliff:g></item><item><xliff:g id="id">@string/status_bar_speakerphone</xliff:g></item><item><xliff:g id="id">@string/status_bar_cdma_eri</xliff:g></item><item><xliff:g id="id">@string/status_bar_data_connection</xliff:g></item><item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item><item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item><item><xliff:g id="id">@string/status_bar_secure</xliff:g></item><item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item><item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item><item><xliff:g id="id">@string/status_bar_cast</xliff:g></item><item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item><item><xliff:g id="id">@string/status_bar_mute</xliff:g></item><item><xliff:g id="id">@string/status_bar_volume</xliff:g></item><item><xliff:g id="id">@string/status_bar_location</xliff:g></item><item><xliff:g id="id">@string/status_bar_zen</xliff:g></item><item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item><item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item><item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item><item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item><item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item><item><xliff:g id="id">@string/status_bar_battery</xliff:g></item></string-array><string translatable="false" name="status_bar_alarm_clock">alarm_clock</string><!--时钟闹钟--><string translatable="false" name="status_bar_rotate">rotate</string><string translatable="false" name="status_bar_headset">headset</string><string translatable="false" name="status_bar_data_saver">data_saver</string><string translatable="false" name="status_bar_ime">ime</string><!--手机卡--><string translatable="false" name="status_bar_sync_failing">sync_failing</string><string translatable="false" name="status_bar_sync_active">sync_active</string><string translatable="false" name="status_bar_nfc">nfc</string><string translatable="false" name="status_bar_tty">tty</string><string translatable="false" name="status_bar_speakerphone">speakerphone</string><string translatable="false" name="status_bar_cdma_eri">cdma_eri</string><string translatable="false" name="status_bar_data_connection">data_connection</string><string translatable="false" name="status_bar_phone_evdo_signal">phone_evdo_signal</string><string translatable="false" name="status_bar_phone_signal">phone_signal</string><!--手机信号--><string translatable="false" name="status_bar_secure">secure</string><string translatable="false" name="status_bar_bluetooth">bluetooth</string><!--蓝牙--><string translatable="false" name="status_bar_managed_profile">managed_profile</string>    <string translatable="false" name="status_bar_cast">cast</string><string translatable="false" name="status_bar_vpn">vpn</string><!--VPN--><string translatable="false" name="status_bar_mute">mute</string><!--静音--><string translatable="false" name="status_bar_volume">volume</string><!--音量--><string translatable="false" name="status_bar_location">location</string><!--定位--><string translatable="false" name="status_bar_zen">zen</string><string translatable="false" name="status_bar_ethernet">ethernet</string><!--网络--><string translatable="false" name="status_bar_wifi">wifi</string><!--Wifi--><string translatable="false" name="status_bar_hotspot">hotspot</string><!--热点--><string translatable="false" name="status_bar_mobile">mobile</string><!--手机--><string translatable="false" name="status_bar_airplane">airplane</string><!--飞行模式--><string translatable="false" name="status_bar_battery">battery</string><!--电池-->...

这个数组不仅仅定义了图标的名字,而且还定义了图标的顺序,例如飞行模式图标肯定在电池图标之前,VPN图标肯定在飞行模式图标之前,蓝牙图标肯定在VPN之前。

三、设置状态图标

前面两步我们具体介绍了状态栏图标控制器,那么状态栏图标的设置究竟是如何实现的呢?让我们重新回到StatusBar的start()方法中:

public class StatusBar extends SystemUI implements DemoMode,DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {...@Overridepublic void start() {...createAndAddWindows(); ...// Lastly, call to the icon policy to install/update all the icons.mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);//手机状态栏策略类mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);//状态栏信号策略类...}...
}

所有的状态图标的设置都是在这两个策略类中,我们接下来来看下手机信号图标是如何设置的,它在StatusBarSignalPolicy中:

//状态栏信号策略类
public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,SecurityController.SecurityControllerCallback, Tunable {...public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {mContext = context;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);mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);// 这个就是StatusBarIconContrllerImpl对象mIconController = iconController;// 注册网络监听mNetworkController = Dependency.get(NetworkController.class);mSecurityController = Dependency.get(SecurityController.class);//添加网络监听的回调mNetworkController.addCallback(this);mSecurityController.addCallback(this);}}

要设置某一个图标,首先要获取图标的名字,这个名字可以从上面提到的数组中获取,然后注册网络控制器;网络控制器类的主要代码如下所示:

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java

//网络控制器接口
public interface NetworkController extends CallbackController<SignalCallback>, DemoMode {//添加回调接口void addCallback(SignalCallback cb);
}//回调方法
public interface SignalCallback {// 设置Wifidefault void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,boolean activityIn, boolean activityOut, String description, boolean isTransient,String statusLabel) {}// 设置手机信号图标default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,String description, boolean isWide, int subId, boolean roaming) {}default void setSubs(List<SubscriptionInfo> subs) {}// 设置手机SIM卡的状态default void setNoSims(boolean show, boolean simDetected) {}default void setEthernetIndicators(IconState icon) {}// 设置飞行模式default void setIsAirplaneMode(IconState icon) {}default void setMobileDataEnabled(boolean enabled) {}
}

SignalCallback回调接口的具体实现类:


public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,SecurityController.SecurityControllerCallback, Tunable {//状态栏图标控制器private final StatusBarIconController mIconController;public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {// 获取信号图标的名字mSlotMobile   = mContext.getString(com.android.internal.R.string.status_bar_mobile);...// 这个就是StatusBarIconContrllerImpl对象mIconController = iconController;// 注册网络监听mNetworkController = Dependency.get(NetworkController.class);...//添加网络监听的回调mNetworkController.addCallback(this);...}@Overridepublic void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,String description, boolean isWide, int subId, boolean roaming) {...// Always send a copy to maintain value type semantics// 设置信号图标,第一个参数表示图标名字,第二个参数表示状态mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));...}
}

这样就可以获得关于手机信号的事件,可以看到是通过StatusBarIconController#setMobileIcons()实现的,具体的细节就不深入的。通过StatusBarIconController接口设置图标的套路都是一样的

  • 获取图标名字
  • 监听事件
  • 通过StatusBarIconController相应的方法设置图标。

四、设置无SIM卡图标

假如我们想要设置一个没有SIM卡时候的状态栏图标,这个接口其实系统已经提供,就在 StatusBarSignalPolicy 中

public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,SecurityController.SecurityControllerCallback, Tunable {//状态栏图标控制器private final StatusBarIconController mIconController;@Overridepublic void setNoSims(boolean show, boolean simDetected) {String mobileSlot = mContext.getString(com.android.internal.R.string.status_bar_mobile);if (show && !simDetected) {mIconController.setIcon(mobileSlot, R.drawable.ic_no_sim_black_24dp, "no_sim");mIconController.setIconVisibility(mobileSlot, true);} else {mIconController.setIconVisibility(mobileSlot, false);}}
}

Android 9.0系统源码_SystemUI(三)系统状态图标控制相关推荐

  1. 【转】Ubuntu 14.04.3上配置并成功编译Android 6.0 r1源码

    http://www.linuxidc.com/Linux/2016-01/127292.htm 终于成功把Android 6.0 r1源码的源码编译.先上图,这是在Ubuntu中运行的Android ...

  2. Android 11.0 Settings源码分析 - 主界面加载

    Android 11.0 Settings源码分析 - 主界面加载 本篇主要记录AndroidR Settings源码主界面加载流程,方便后续工作调试其流程. Settings代码路径: packag ...

  3. Android 4.0.1 源码下载,编译和运行

    [牛人分享]Android 4.0.1 源码下载,编译和运行 转自 http://blog.csdn.net/rambo2188/article/details/6943382 ----------- ...

  4. android 4.0模拟器启动不了,Android 4.0 framework源码修改编译,模拟器运行不起来,求助...

    当前位置:编程学习 > wap >> Android 4.0 framework源码修改编译,模拟器运行不起来,求助 我下载编译了android 4.0 ICS的源码,然后能利用编译 ...

  5. java计算机毕业设计web在线考试系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计web在线考试系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计web在线考试系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构:B ...

  6. java计算机毕业设计钢材出入库管理系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计钢材出入库管理系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计钢材出入库管理系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构:B ...

  7. 仿抖音短视频系统源码,获取系统图片

    仿抖音短视频系统源码,实现获取系统图片的相关代码如下: 首先开权限 <uses-permission android:name="android.permission.WRITE_EX ...

  8. java计算机毕业设计高铁在线购票系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计高铁在线购票系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计高铁在线购票系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构:B/S ...

  9. java计算机毕业设计疆域特色农家乐系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计疆域特色农家乐系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计疆域特色农家乐系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构:B ...

  10. java计算机毕业设计Web端校园报修系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计Web端校园报修系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计Web端校园报修系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构 ...

最新文章

  1. jar包 和 war包?
  2. Jmeter_简单的关联设置
  3. 安卓手机浏览器排行_安卓手机双11性价比排行发布|拯救者手机发透明版|小米发大光圈手机镜头...
  4. java模拟登陆_java-模拟登陆练习(示例代码)
  5. Abp连接多个数据源
  6. Unity打包APK细节(翻译自官网)
  7. python字典value排序_python字典按照value排序方法
  8. Java Kafka 简单示例
  9. 图解 Elasticsearch 写入流程
  10. 标记集合 java编译_深入理解Java虚拟机读书笔记-java编译期和运行期优化
  11. tomcat下载安装及配置教程
  12. 干货 | 携程商旅订单系统架构设计和优化实践
  13. android摄像头方向反,Android前置摄像头图像被倒置保存
  14. python编程计算圆面积和体积_计算sph体积和表面积的面向对象Python程序
  15. usaco Typo
  16. 【WiFi 6E】WiFi 6E信道分布
  17. 量化交易系统设计的六大细节
  18. JIAR 使用笔记 - 素材
  19. 数据科学与大数据技术专业毕业设计选题
  20. 华擎主板bios设置图解_华擎主板设置BIOS的图解教程

热门文章

  1. windows上的一些文件夹为什么图标是快捷方式的图标
  2. IDEA如何创建webapp(IDEA)
  3. 【洛谷入门】P7659 [COCI2014-2015#5] FUNGHI
  4. 服务器主控系统,服务器控制管理
  5. Oracle中游标(Cursor)介绍和使用
  6. python 解压的几种方法
  7. python反素数算法优化_合数
  8. 江苏上海php培训,2019年第一期班组长素质提升培训班在江苏南京成功举办
  9. [Android下载]北京新版小学英语三年级上册点读手机软件
  10. 经济学入门必看:绝对经典的20部影片!