学习笔记:参考资源 https://zhuanlan.zhihu.com/p/142596265、https://blog.csdn.net/Bill_xiao/article/details/108244267

一、StatusBar简介
StatusBar由三部分组成:
  1、最左边的一部分显示运营商,时间,通知图标。
  2、最右边的一部分显示系统图标,它由状态图标(例如 wifi ,bt)和电池图标组成。
  3、中间还有一块区域。

status_bar 结构图.png

从上图可以比较直观的看出来顶层树是super_status_bar,之后会走两个分支status_bar_container和status_bar_expanded,status_bar_container这个分支主要呈现的是状态栏界面,状态栏细分左边和右边,左边是通知栏,右边是系统功能的状态图标显示,status_bar_expanded这个分支主要呈现的下拉菜单界面,其实下拉菜单中又分快捷图标和短信通知栏。

二、StatuBar的创建
  StatusBar也是继承SystemUI,启动流程和SystemUI一致。并在start的时候添加创建StatusBar相关的view。
  我们从StatusBar的start()方法开始看。
frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java

public void start() {

// 省略部分代码...// 创建整个SystemUI视图并添加到WindowManager中
createAndAddWindows(result);// 省略部分代码...

}

public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {

// 创建整个SystemUI视图makeStatusBarView(result);// 把视图添加到Window中mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());

}
根据上面代码可知,视图的创建在makeStatusbarView(result)方法中;

 //创建状态栏,即初始化通知图标区域
protected void makeStatusBarView(RegisterStatusBarResult result) {//1.初始化资源文件:导航栏高度 状态栏高度 通知面板位置和高度等final Context context = mContext;updateDisplaySize(); // populates mDisplayMetricsupdateResources();updateTheme();//加载layout文件super_status_bar,mStatusBarWindowinflateStatusBarWindow(context);// ...FragmentHostManager.get(mStatusBarWindow).addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {CollapsedStatusBarFragment statusBarFragment =(CollapsedStatusBarFragment) fragment;// 把控制器中的通知容器加入到状态栏的容器中statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);// ...}).getFragmentManager().beginTransaction()// CollapsedStatusBarFragment实现了状态栏的添加.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),CollapsedStatusBarFragment.TAG).commit(); // ...
}

注意在这里添加了CollapsedStatusBarFragment,这个CollapsedStatusBarFragment就是作为加载状态栏的Fragment。
  在看 CollapsedStatusBarFragment 之前,我们先看看 NotificationIconAreaController(通知图标区域控制器),在 NotificationIconAreaController 的构造函数中会调用如下方法来创建通知图标的容器,即初始化布局。

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

protected void initializeNotificationAreaViews(Context context) {// ...LayoutInflater layoutInflater = LayoutInflater.from(context);// 实例化通知图标区域视图mNotificationIconArea = inflater.inflate(R.layout.notification_icon_area, null);// 这个才是真正存放通知图标的父容器mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);// ...
}

这个类加载的是 R.layout.notification_icon_are.xml 布局。这里先回到 makeStatusBarView(RegisterStatusBarResult result) 方法,我们看 statusBarFragment.initNotificationIconArea(mNotificationIconAreaController) ,这句话的作用就是 将 NotificationIconAreaController 自己创建的通知图标容器,加入到状态栏视图中。

接下来继续看 CollapsedStatusBarFragment,在看之前我们应该带着一个问题去看:这些图标都是动态添加的,是怎么被添加和移除的。
  由 CollapsedStatusBarFragment onCreateView() 可知,加载的布局是 R.layout.status_bar。
  在该布局里包含了这么几个关键的视图:

1、@+id/status_bar_contents 这个LinearLayout,里面包含了@+id/status_bar_left_side ,从名字来看就知道是状态栏左边部分。这个状态栏左边部分包含了时钟@+id/clock和短信通知@+id/notification_icon_area。

2、@+id/system_icon_area这个也是一个LinearLayout包含了
@layout/system_icons,这部分就是状态栏右边部分,里面包含了电池图标和系统状态图标等等。

由 statusBarFragment.initNotificationIconArea(mNotificationIconAreaController) 可知,会进入到CollapsedStatusBarFragment 的 initNotificationIconArea 方法里

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

public void initNotificationIconArea(NotificationIconAreaControllernotificationIconAreaController) {// 通知图标区域ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);// 这个才是通知图标的父容器mNotificationIconAreaInner =notificationIconAreaController.getNotificationInnerAreaView();//移除自己,再添加自己if (mNotificationIconAreaInner.getParent() != null) {((ViewGroup) mNotificationIconAreaInner.getParent()).removeView(mNotificationIconAreaInner);}// 把通知图标父容器添加到通知图标区域里notificationIconArea.addView(mNotificationIconAreaInner);// 省略处理中心图标区域的代码// 这里其实显示了通知图标区域和中心图标区域showNotificationIconArea(false);
}

三、监听通知的服务端
  当一条新通知发送后,它会存储到通知服务端,也就是NotificationManagerService,那么SystemUI是如何知道新通知来临的。这就需要SystemUI向ActivityManagerService注册一个"服务"(一个Binder)。
  这个"服务"就相当于客户端SystemUI在服务端ActivityManagerService注册的一个回调。当有通知来临的时候,就会通过这个"服务"通知SystemUI。通过 notificationListener.registerAsSystemService(),进行注册。
  可以来看下这个注册的实现:

/**
* Directly register this service with the Notification Manager.
*
*

Only system services may use this call. It will fail for non-system callers.
* Apps should ask the user to add their listener in Settings.
*
* @param context Context required for accessing resources. Since this service isn’t
* launched as a real Service when using this method, a context has to be passed in.
* @param componentName the component that will consume the notification information
* @param currentUser the user to use as the stream filter
* @hide
* @removed
*/
@SystemApi
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
if (mWrapper == null) {
// 这就是要注册的Binder,也就一个回调
mWrapper = new NotificationListenerWrapper();
}
mSystemContext = context;
INotificationManager noMan = getNotificationInterface();

    // ...// 向通知的服务端注册回调noMan.registerListener(mWrapper, componentName, currentUser);
}

SystemUI注册的这个“服务”其实就是:NotificationListenerWithPlugins。

注册成功后,就会回调NotificationListenerWithPlugins中NotificationListenerWrapper()方法,并会附带所有的通知信息。

四、通知图标的显示
当一条新的通知来临的时候,通知的服务端会通过NotificationListenerWithPlugins中的onNotificationPosted()进行回调,而最终会调用NotificationListener中的onNotificationPosted()。

@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
// 省略部分代码…
// 进行回调
handler.onNotificationPosted(sbn, rankingMap);
// 省略部分代码 …
}
}
这个回调,将调到 NotificationEntryManager 类里的 onNotificationPosted()方法。

public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
final boolean isUpdateToInflatedNotif = mActiveNotifications.containsKey(sbn.getKey());
if (isUpdateToInflatedNotif) {
updateNotification(sbn, rankingMap);
} else {
addNotification(sbn, rankingMap);
}
}
这里只关注 addNotification(sbn, rankingMap) ,而它内部时调用 addNotificationInternal() 方法实现的。

private void addNotificationInternal(
StatusBarNotification notification,
RankingMap rankingMap) throws InflationException {

    // 省略部分代码 ...NotificationEntry entry = mPendingNotifications.get(key);// 省略部分代码 ...// Construct the expanded view.if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {mNotificationRowBinderLazy.get().inflateViews(entry,() -> performRemoveNotification(notification, REASON_CANCEL),mInflationCallback);}// 省略部分代码 ...
}

首先为通知创建一个NotificationEntry实例,然后再通过NotificationRowBinderImpl中的inflateViews()加载通知视图,绑定通知信息,并在通知栏添加通知视图,以及在状态栏添加通知图标。

到此获取到了数据、图标后面就是更新视图进行显示了,由 NotificationRowBinderImpl#inflateViews → NotificationEntryManager#onAsyncInflationFinished → StatusBarNotificationPresenter#updateNotificationViews

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

public void updateNotificationViews() {// ...//  把通知视图添加到通知面版的通知栏中mViewHierarchyManager.updateNotificationViews();// 这里不仅仅更新了通知面版的通知视图,也更新了状态栏的通知图标mNotificationPanel.updateNotificationViews(reason);// ...
}

最终会调用 NotificationIconAreaController#updateNotificationIcons()进行视图更新。

作者:孤街酒客1310
链接:https://www.jianshu.com/p/0bdf49455914
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Android10.0 StatusBar之状态栏相关推荐

  1. android10 禁止下拉状态栏

    需求:android10 禁止下拉状态栏,也就是禁止下拉如下图的快速设置面板( Quick settings panel,也叫QS面板) 修改后:怎么拉都拉不下来,包括锁屏页面和正常桌面都无法下拉状态 ...

  2. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

  3. Android10.0 开机广播BOOT_COMPLETED发送流程分析

    原文地址:https://skytoby.github.io/2019/%E5%BC%80%E6%9C%BA%E5%B9%BF%E6%92%ADBOOT_COMPLETED%E5%8F%91%E9%8 ...

  4. delphi StatusBar在状态栏中显示checkBox

    //StatusBar在状态栏中显示checkBox procedure TForm1.CheckBox1Click(Sender: TObject); begin        Image1.Vis ...

  5. Android10.0 os定制化系列讲解导读

    一.前言 本专栏主要是作者本人在10.0 frameworks定制化实战功能系列的解读,在从事几年的frameworks定制化功能的经验的积累,开发过平板,广告机,会议机,车机等一系列系统上层定制的功 ...

  6. android view设置按钮颜色_Android关于StatusBar(状态栏)总结

    从事Android开发的同学了解,对于StatusBar的控制,并没有ios那样好,需要对Android不同的系统版本进行适配,同时也需要对小米,魅族等国产手机单独适配,想要如ios那般好的体验,并没 ...

  7. Android SystemUI之StatusBar,状态栏(二)

    Android  SystemUI系列: 1.Android  SystemUI之启动流程(一) 2.Android SystemUI之StatusBar,状态栏(二) 3.Android Syste ...

  8. 编译系统总结篇-Android10.0编译系统(十一)

    摘要:Android10.0编译系统总结 阅读本文大约需要花费20分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢! 欢迎关 ...

  9. Ninja提升编译速度的方法-Android10.0编译系统(十)

    摘要:如何通过Ninja来提升Android编译速度 阅读本文大约需要花费10分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢 ...

最新文章

  1. 【VB】学生信息管理系统6——错误调试
  2. mysql过滤复制的实现
  3. 基于大数据的Uber数据实时监控(Prat 3:使用Vert.x的实时仪表盘)
  4. Python 34(进程重点)
  5. 【译】Easily Build Android APKs on Device in Termux
  6. WPF 不遮挡任务栏最大化和全屏显示
  7. c++ class struct同名_C/C++面向对象编程之封装
  8. RHEL6.2手动封装rpm源码包安装星际译王
  9. docker从入门到实践第三版pdf_测开日常积累--Docker入门到实践
  10. js 获取昨天,今天,本周,上周,季度等时间范围(封装的js)
  11. undefined reference to 'modbus_new_tcp'
  12. Java之美[从菜鸟到高手演变]之设计模式四
  13. 智器SmartQ T7历险记
  14. Spring框架与J2EE框架
  15. 数学牛人们的轶事[下]
  16. 职业也如学习一样,逆水行舟不进则退
  17. vmware: 磁盘加载问题导致,emergency mode: login incorrect 滚动打印
  18. WINDOWS下文件夾里到底有什麼,各個文件夾都代表的什麼?
  19. 【算法实现】随机森林算法的房屋价格预测模型
  20. RT-Thread:在dfs中使用cat、cp等命令时拔掉U盘死机问题

热门文章

  1. 【图文并茂】一键重装win7系统详细教程
  2. 2022中国健康展|山东健康展|特医食品展|健康生活方式展
  3. 16、数据容器-列表(复习)
  4. 使用MCU普通I/O口实现电容触摸感应方案(RC方式)
  5. android输入法可以删掉吗,搜狗输入法功能科普二:如何添加或删除词库里的词(安卓篇)...
  6. Redis报错Field redisTemplate in xxx required a bean of type ‘org.x.RedisTemplate‘that can not be foud
  7. 光纤布拉格光栅传感器的工作原理解析
  8. 组合导航学习笔记--开环闭环介绍
  9. (2022.5.27)【Win10】Windows10微软商店升级报错0xC002001B、Win10开始菜单应用图标变暗且有走不完的进度条——解决方案
  10. photoshop里上色之后,颜色总是灰色的,解决办法