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

Android SystemUI组件(05)状态栏-系统状态图标显示&管理说明 本章节持续迭代之前章节的思维导图 主要关注下方 SystemBars 分析中状态栏中的部分 系统状态图标显示 amp 管理即可

大家好,欢迎来到IT知识分享网。

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


本章关键点总结 & 说明:

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

说明:本章节持续迭代之前章节的思维导图,主要关注下方 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); } //... @Override public 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_ICON mHandler.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_ICON mHandler.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_ICON StatusBarIcon icon = (StatusBarIcon)msg.obj; StatusBarIcon old = mList.getIcon(index); if (old == null) {//不存在则添加图标 mList.setIcon(index, icon); //这里的mCallbacks是初始化时传递进来的,实际上就是PhoneStatusBar mCallbacks.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是初始化时传递进来的,实际上就是PhoneStatusBar mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex); } break; } break; } //... } } } //... }

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

public abstract class BaseStatusBar extends SystemUI implements CommandQueue.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 service StatusBarIconList iconList = new StatusBarIconList(); //这里初始化CommandQueue时传入的实际山是PhoneStatusBar mCommandQueue = 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 info public 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的展示层。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/151630.html

(0)
上一篇 2025-03-12 18:00
下一篇 2025-03-12 18:05

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信