Android SystemUI组件(05)状态栏-系统状态图标显示管理

news/2024/9/18 12:35:12/ 标签: android, systemUI, 状态栏, 系统图标显示

该系列文章总纲链接:专题分纲目录 Android SystemUI组件


本章关键点总结 & 说明:

说明:本章节持续迭代之前章节的思维导图,主要关注下方 SystemBars分析中状态栏中的部分-系统状态图标显示&管理 即可。

1 系统状态图标显示和管理基本解读

系统状态图标区域通常位于状态栏的右侧,显示了诸如电池电量、信号强度、Wi-Fi连接、蓝牙状态、闹钟、自动旋转锁定等系统信息的图标。以下是对这一功能方面的整体描述:

  1. 状态栏的构成状态栏通常位于屏幕的顶部,是一个水平的条状区域。它包括系统状态图标区域和通知图标区域。系统状态图标区域显示了各种系统状态信息,而通知图标区域则显示了应用程序的通知。

  2. 系统状态图标的显示:每个系统状态图标都代表了一个特定的系统状态或功能。图标通常会根据其代表的状态变化而变化,例如,当手机连接到Wi-Fi网络时,Wi-Fi图标会显示为激活状态。某些图标可能会有多种状态,例如电池图标会根据电量的多少显示不同的充电状态。

  3. 图标的交互:用户可以通过点击某些图标来打开相关的设置界面,例如点击音量图标可能会打开音量调节滑块。长按某些图标可能会触发特定的操作或显示更多的选项,例如长按Wi-Fi图标可能会显示可用的Wi-Fi网络列表。

  4. 状态栏的自定义:用户可以在系统设置中对状态栏的某些方面进行自定义,比如选择显示或隐藏某些图标。一些制造商可能还会提供额外的自定义选项,如改变状态栏的透明度或颜色。

  5. 多用户和多任务处理:在多用户环境中,状态栏可能会显示与当前活跃用户相关的信息。在多任务处理时,状态栏可以提供快速切换最近使用应用的入口。

  6. 系统状态图标的更新:当系统状态发生变化时(如连接到新的Wi-Fi网络),状态栏会自动更新相应的图标。系统状态图标的更新通常是由系统服务如StatusBarManagerService通过SystemUI来实现的。

  7. 锁屏状态下的状态栏:在锁屏状态下,状态栏可能会显示简化的信息,或者根据安全策略隐藏某些敏感信息。

  8. 沉浸式体验:在某些全屏应用中,状态栏可能会被隐藏,以提供更加沉浸式的用户体验。

整体而言,系统状态图标区域是Android系统中用户界面的一个重要组成部分,它为用户提供了快速查看和交互系统状态的便捷方式。

2 系统状态图标区域显示图标流程解读

这里的关键流程分析为:系统状态图标区域中显示一个图标的流程,主要分析StatusBarManager的setIcon方法实现。拆毁分成2个过程,具体如下:

2.1 从StatusBarManager的setIcon到mBar.setIcon详细解读

StatusBarManager的setIcon代码实现如下:

public class StatusBarManager {//...private Context mContext;private IStatusBarService mService;private IBinder mToken = new Binder();//...StatusBarManager(Context context) {mContext = context;}//...private synchronized IStatusBarService getService() {if (mService == null) {mService = IStatusBarService.Stub.asInterface(ServiceManager.getService(Context.STATUS_BAR_SERVICE));if (mService == null) {Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");}}return mService;}//...public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) {try {final IStatusBarService svc = getService();if (svc != null) {svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel,contentDescription);}} catch (RemoteException ex) {// system process is dead anyway.throw new RuntimeException(ex);}}//...
}

这个方法的作用是将一个图标添加到状态栏的指定位置,并提供图标的资源ID和描述信息。如果调用成功,状态栏上会在相应的位置显示这个图标。如果svcIStatusBarService的实例)为空或者发生了远程异常(RemoteException),则表示无法与状态栏服务通信,通常会抛出一个运行时异常。其中的4个参数解读如下:

  1. slot:这是一个字符串参数,代表了图标在状态栏中的位置或者"插槽"。状态栏可以有多个这样的"插槽"来显示不同的图标,比如信号强度、电池电量、Wi-Fi连接等。开发者可以通过指定不同的slot来控制图标在状态栏中的具体位置。

  2. iconId:这是一个整型参数,代表了要显示的图标资源的ID。它在config_statusBarIcons所预定义的意图列表之中。这个ID通常指向应用程序的资源文件中的一个图标。例如,如果你有一个表示Wi-Fi连接状态的图标,它可能在资源文件中有一个唯一的ID。

  3. iconLevel:这个整型参数通常用于表示图标的状态或者级别。例如,电池电量图标可能会使用不同的iconLevel来表示不同的电量状态。在某些情况下,这个参数可能不被使用,具体取决于图标的类型和状态栏的实现。

  4. contentDescription:这是一个字符串参数,为图标提供了内容描述。这对于辅助功能(如屏幕阅读器)非常重要,因为它们可以使用这个描述来向用户报告图标的含义。例如,如果图标表示Wi-Fi连接,contentDescription可能会设置为"Wi-Fi连接"。

实际上就是调用StatusBarManagerService的setIcon方法,代码具体实现为:

public class StatusBarManagerService extends IStatusBarService.Stub {private static final String TAG = "StatusBarManagerService";//...private NotificationDelegate mNotificationDelegate;private volatile IStatusBar mBar;private StatusBarIconList mIcons = new StatusBarIconList();//...public StatusBarManagerService(Context context, WindowManagerService windowManager) {mContext = context;mWindowManager = windowManager;final Resources res = context.getResources();mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));LocalServices.addService(StatusBarManagerInternal.class, mInternalService);}//...@Overridepublic void setIcon(String slot, String iconPackage, int iconId, int iconLevel,String contentDescription) {//安全性检查,必须有android.permission.STATUS_BAR系统权限才能设置系统状态图标。enforceStatusBar();synchronized (mIcons) {//从mIcons中获取预定义的意图索引,找不到抛异常int index = mIcons.getSlotIndex(slot);if (index < 0) {throw new SecurityException("invalid status bar icon slot: " + slot);}//创建StatusBarIcon对象(封装图标相关信息)StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.OWNER, iconId,iconLevel, 0,contentDescription);//这里将图标信息保存在副本中,主要用于SystemUI意外退出后恢复使用。mIcons.setIcon(index, icon);if (mBar != null) {try {//这里设置请求发送给BaseSstatusBar,提交到SystemUI状态栏mBar.setIcon(index, icon);} catch (RemoteException ex) {}}}}//...
}

接下来对mBar.setIcon的实现进行详细解读。因为这里涉及了IStatusBar,这里先简单做一个基本的解读。SystemUI是负责提供用户与系统交互界面的组件,其中包括状态栏、通知栏、锁屏界面等。在这个上下文中,CommandQueueStatusBarWindowViewBaseStatusBarPhoneStatusBar是构成状态栏的关键组件。下面是它们之间的关系和作用的解读:

  1. BaseStatusBarBaseStatusBar是一个抽象类,它定义了状态栏的基本接口和一些共用的逻辑。它作为状态栏的核心,处理与状态栏相关的各种事件和请求,比如图标的更新、通知的显示等。它实现了CommandQueue.Callbacks接口,这意味着它可以接收来自CommandQueue的命令并作出响应。

  2. PhoneStatusBarPhoneStatusBarBaseStatusBar的具体实现,它针对手机设备(而不是平板电脑)提供了状态栏的具体逻辑和UI实现。它负责创建和管理状态栏的视图,包括初始化状态栏的布局、处理用户交互(如下拉通知栏)、更新系统图标等。PhoneStatusBar在启动时会创建CommandQueue的实例,并将自己设置为命令的回调对象。

  3. CommandQueueCommandQueue继承了IStatusBar.Stub,它作为状态栏与其他系统服务(如StatusBarManagerService)通信的桥梁。它接收来自系统服务的命令,并将这些命令分发到BaseStatusBar的实现(在这个场景中是PhoneStatusBar)。CommandQueue还持有一个StatusBarIconList的引用,用于管理状态栏图标的状态。

  4. StatusBarWindowViewStatusBarWindowView状态栏窗口的根视图组件,它是所有状态栏UI元素的容器。这个视图在PhoneStatusBarmakeStatusBarView()方法中被创建和初始化,它包含了状态栏的布局和子视图,如时钟、电池图标、信号强度指示器等。StatusBarWindowView负责在屏幕上显示状态栏,并且响应系统主题的变化(如深色模式)。

在Android 系统中,当系统需要更新状态栏(例如,收到新通知、信号强度变化等)时,StatusBarManagerService会通过CommandQueue发送相应的命令。CommandQueue将这些命令转发给PhoneStatusBarBaseStatusBar的具体实现),PhoneStatusBar根据命令更新StatusBarWindowView中的内容,从而在用户设备上反映这些变化。

有了上面的基础,我们继续分析mBar.setIcon的实现。

2.2 mBar.setIcon详细解读

这里的mBar是IStatusBar类型,实际上是CommandQueue(它继承了IStatusBar.Stub)类型。因此继续分析mBar对应类型CommandQueue的setIcon方法。具体实现如下:

public class CommandQueue extends IStatusBar.Stub {private static final int INDEX_MASK = 0xffff;private static final int MSG_SHIFT  = 16;private static final int MSG_MASK   = 0xffff << MSG_SHIFT;private static final int OP_SET_ICON    = 1;private static final int OP_REMOVE_ICON = 2;//...public CommandQueue(Callbacks callbacks, StatusBarIconList list) {mCallbacks = callbacks;mList = list;}public void setIcon(int index, StatusBarIcon icon) {synchronized (mList) {int what = MSG_ICON | index;mHandler.removeMessages(what);//hanlder发送消息OP_SET_ICONmHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();}}public void removeIcon(int index) {synchronized (mList) {int what = MSG_ICON | index;mHandler.removeMessages(what);//hanlder发送消息OP_REMOVE_ICONmHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget();}}//...private final class H extends Handler {public void handleMessage(Message msg) {final int what = msg.what & MSG_MASK;switch (what) {case MSG_ICON: {final int index = msg.what & INDEX_MASK;final int viewIndex = mList.getViewIndex(index);switch (msg.arg1) {case OP_SET_ICON: {//处理消息OP_SET_ICONStatusBarIcon icon = (StatusBarIcon)msg.obj;StatusBarIcon old = mList.getIcon(index);if (old == null) {//不存在则添加图标mList.setIcon(index, icon);//这里的mCallbacks是初始化时传递进来的,实际上就是PhoneStatusBarmCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon);} else {//存在则更新图标mList.setIcon(index, icon);mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,old, icon);}break;}case OP_REMOVE_ICON:if (mList.getIcon(index) != null) {mList.removeIcon(index);//这里的mCallbacks是初始化时传递进来的,实际上就是PhoneStatusBarmCallbacks.removeIcon(mList.getSlot(index), index, viewIndex);}break;}break;}//...}}}//...
}

接下来我们对mCallbacks部分进行简单解读,实际上就是PhoneStatusBar在构造函数阶段初始化时传递给CommandQueue。而PhoneStatusBar又是继承自BaseStatusBar的,BaseStatusBar代码实现如下:

public abstract class BaseStatusBar extends SystemUI implementsCommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,NotificationData.Environment {public static final String TAG = "StatusBar";public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);public static final boolean MULTIUSER_DEBUG = false;public void start() {//...// Connect in to the status bar manager serviceStatusBarIconList iconList = new StatusBarIconList();//这里初始化CommandQueue时传入的实际山是PhoneStatusBarmCommandQueue = new CommandQueue(this, iconList);//...}//...
}

接下来继续看PhoneStatusBar的实现与对setIcon的分别处理(addIcon和updateIcon),代码实现如下:

public class PhoneStatusBar extends BaseStatusBar implements DemoMode,DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener {static final String TAG = "PhoneStatusBar";public static final boolean DEBUG = BaseStatusBar.DEBUG;public static final boolean SPEW = false;public static final boolean DUMPTRUCK = true; // extra dumpsys infopublic static final boolean DEBUG_GESTURES = false;public static final boolean DEBUG_MEDIA = false;public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;//...public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {StatusBarIconView view = new StatusBarIconView(mContext, slot, null);view.set(icon);mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, mIconSize));view = new StatusBarIconView(mContext, slot, null);view.set(icon);mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, mIconSize));}public void updateIcon(String slot, int index, int viewIndex,StatusBarIcon old, StatusBarIcon icon) {StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);view.set(icon);view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);view.set(icon);}public void removeIcon(String slot, int index, int viewIndex) {mStatusIcons.removeViewAt(viewIndex);mStatusIconsKeyguard.removeViewAt(viewIndex);}//...
}

至此,关键代码的流程就分析结束了。总结下

  • BaseStatusBar定义了状态栏的基本行为。
  • PhoneStatusBar提供了这些行为的具体实现
  • CommandQueue处理来自系统服务的命令
  • StatusBarWindowView则是状态栏UI的展示层。

http://www.ppmy.cn/news/1525088.html

相关文章

SenseGlove机器臂遥操作控制:技术优势与高危作业安全保障

在追求高效与安全的工业时代&#xff0c;高危作业任务始终是行业发展的一大障碍。SenseGlove力反馈手套机器臂遥操作应用案例的出现&#xff0c;凭借其独特的技术优势&#xff0c;为解决这一难题提供了创新性解决方案。 一、技术优势 高精度的力反馈技术&#xff1a;SenseGlove…

CTF——简单的《WEB》

文章目录 一、WEB1、easysql2、baby_web3、baby_sql4、upload_easy5、easygame拓展1.1拓展1.2 6、ht_ssti7、包容乃大 一、WEB 1、easysql 题目描述&#xff1a; sql注入漏洞 1.常用的sql注入测试语句 2.sql注入bypass 解题思路 这边提示基本给的也很完整的&#xff0c;不…

基于中心点的目标检测方法CenterNet—CVPR2019

Anchor Free目标检测算法—CenterNet Objects as Points论文解析 Anchor Free和Anchor Base方法的区别在于是否在检测的过程中生成大量的先验框。CenterNet直接预测物体的中心点的位置坐标。 CenterNet本质上类似于一种关键点的识别。识别的是物体的中心点位置。 有了中心点之…

关于Python爬虫的基础知识

爬虫是一种自动获取网页内容的程序或工具。以下是一些关于爬虫的基础知识&#xff1a; 一、爬虫的工作原理 发送请求&#xff1a; 爬虫首先向目标网站发送 HTTP 请求&#xff0c;就像你在浏览器中输入网址并访问一样。请求中包含了一些信息&#xff0c;如请求方法&#xff08;…

Spring Boot集成Akka Stream快速入门Demo

1.什么是Akka Stream&#xff1f; Akka Streams是一个用于处理和传输元素序列的库。它建立在Akka Actors之上&#xff0c;使流的摄入和处理变得简单。由于它是建立在Akka Actors之上的&#xff0c;它为Akka现有的actor模型提供了一个更高层次的抽象。Akka流由3个主要部分组成-…

Linux平台屏幕|摄像头采集并实现RTMP推送两种技术方案探究

技术背景 随着国产化操作系统的推进&#xff0c;市场对国产化操作系统下的生态构建&#xff0c;需求越来越迫切&#xff0c;特别是音视频这块&#xff0c;今天我们讨论的是如何在linux平台实现屏幕|摄像头采集&#xff0c;并推送至RTMP服务。 我们知道&#xff0c;Linux平台&…

洛谷刷题之B2089 数组逆序重存放

数组逆序重存放 题目入口 题目描述 将一个数组中的值按逆序重新存放。例如&#xff0c;原来的顺序为 8 , 6 , 5 , 4 , 1 8,6,5,4,1 8,6,5,4,1。要求改为 1 , 4 , 5 , 6 , 8 1,4,5,6,8 1,4,5,6,8。 输入格式 输入为两行&#xff1a;第一行数组中元素的个数 n n n&#x…

比 GPT-4 便宜 187 倍的Mistral 7B (非广告)

Mistral 7B 是一种设计用来快速处理较长文本的人工智能模型。它采用了一些特别的技术来提高速度和效率&#xff0c;比如“分组查询注意力&#xff08;grouped-query attention&#xff09;”和“滑动窗口注意力&#xff08;sliding-window attention&#xff09;”。 这些技术…

UNI-APP 富文本编辑器,可以对图片、文字格式进行编辑和混排。

✍找了几篇文章对比了一下&#xff0c;大体都差不多各有各的说辞和见解,但是没有提供/style/editor-icon.css文件&#xff0c;找起来虽然说不算太麻烦&#xff0c;但是不够直接&#xff0c;又要花费时间去弄&#xff0c;虽然用的不是很多但是&#xff0c;我还是决定自己写一篇&…

第15-05章:获取运行时类的完整结构

我的后端学习大纲 我的Java学习大纲 6.1.第一组方法API: 1.API列表&#xff1a;java.lang.Class 类&#xff1a; 2.代码测试&#xff1a; public class ReflectionUtils{ puvblic static void main(String[] args){}// 第一组Testpublic void api_01{//上面截图的代码......…

VR 尺寸美学主观评价-解决方案-现场体验研讨会报名

棣拓科技VR创新解决方案助力尺寸美学所见即所得! 诚邀各位行业专家莅临指导交流 请扫描海报二维码踊跃报名&#xff0c;谢谢 中国上海 2024.10.25 亮点介绍 1、通过精湛渲染技术&#xff0c;最真实展现设计效果&#xff0c;并通过VR设备一比一比例进行展现。 2、设置相关设…

基于ACMEv2协议的免费证书申请

项目&#xff1a;https://github.com/cook-code-jazor/acmex 非开源&#xff0c;使用webui管理证书的申请&#xff0c;所有文件本地化存储&#xff0c;支持windows/linux/osx. 运行 很简单,直接运行命令 ./acmex --runas console首次运行没有配置文件&#xff0c;会要求你填…

组件通信——provide 和 inject 实现爷孙组件通信

provide 和 inject 实现爷孙组件通信 介绍 provide 和 inject 是 Vue.js 提供的一种在组件之间共享数据的机制&#xff0c;它允许在组件树中的任何地方注入依赖项。这对于跨越多个层级的组件间通信特别有用&#xff0c;因此无需手动将 prop 数据逐层传递下去。 provide&#…

使用Selenium WebDriver捕获网络请求

在进行Web自动化测试时,捕获网络请求是十分重要的。通过这种方式,我们可以了解到页面加载过程中发生的网络活动,这对于调试、性能分析以及确保应用程序按预期工作都非常有用。本文将详细介绍如何使用Selenium WebDriver和Python来实现捕获网络请求的功能。 前置要求 在开始…

启动ros2_control与gazebo仿真

目录 问题&#xff1a;启动my_world.world文件时&#xff0c;报错&#xff1a; 原因&#xff1a; 解决方法&#xff1a; 1. 确保 robot_state_publisher 节点正在运行 2. 检查配置文件 总结&#xff1a; 问题&#xff1a;启动my_world.world文件时&#xff0c;报错&#x…

分支管理

目录 创建分支 切换分支 合并分支 删除分支 合并冲突 创建分支 git branch [分支]指令 创建新的分⽀后&#xff0c;Git 新建了⼀个指针叫dev&#xff0c; * 表⽰当前 HEAD 指向的分⽀是 master 分⽀。另外&#xff0c;可以通过⽬录结构发现&#xff0c;新的 dev 分⽀…

【CSS】尺寸单位

在 CSS 中&#xff0c;常见的尺寸单位有以下几种&#xff1a; 像素&#xff08;px&#xff09;&#xff1a; 这是最常用的绝对单位。例如 width: 200px; 表示宽度为 200 像素。像素是固定的尺寸&#xff0c;不会随着屏幕分辨率或设备的不同而变化。 备注&#xff1a; 在不同的…

Harmony Next 文件命令操作(发送、读取、媒体文件查询)

查询文件位置 hdc shell mediatool query IMG_20240902_204224.jpg 输出示例 拉取文件 hdc file recv /storage/cloud/100/files/Photo/4/IMG_1725281044_036.jpg aa.jpg 发送文件 hdc file send aa.jpg /storage/media/100/local/files/Docs/Download/ab.jpg 下载目录位置…

兼容pc端和移动端的滑块校验

组件 <template><canvas :class"cvsClass" :width"props.width" :height"props.height" ref"cvs"></canvas> </template><script setup> import { ref, reactive, watch, nextTick } from "vue&q…

【C++开发中XML 文件的妙用】

在C中&#xff0c;XML&#xff08;可扩展标记语言&#xff09;文件通常用于存储配置数据、应用程序设置、数据交换格式等。由于其结构化和可读性强的特点&#xff0c;XML文件在配置管理、序列化、跨平台数据交换以及软件国际化等方面有着广泛的应用。 XML 文件的妙用 配置管理…