本文主要分享 SystemUI Notification 具体如何呈现的?基于 AOSP 9.0 分析。
概述
在《Android 9.0 SystemUI 主要视图 SystemBars》知道通知在折叠时状态栏、下拉状态栏、锁屏都有通知,其中锁屏和下拉状态栏是一个布局,折叠状态栏 是在 CollapsedStatusBarFragment,status_bar.xml,PhoneStatusBarView
,锁屏是 NotificationStackScrollLayout,@+id/notification_stack_scroller
,先来看看锁屏的通知,NotificationStackScrollLayout 是 ViewGroup,如果来了条通知,肯定是有地方进行 addView,我们就沿着这个思路去 AOSP 寻找答案。
序列图
序列图为来通知到 SystemUI 锁屏通知呈现整个流程。
锁屏通知
NotificationStackScrollLayout#addContainerView
锁屏是 NotificationStackScrollLayout,直接找 NotificationStackScrollLayout,看到有个 addContainerView方法,一看,果然是目标 addView:
反查,看到 addContainerView 被 NotificationViewHierarchyManager#updateNotificationViews 方法调用了。
NotificationViewHierarchyManager#updateNotificationViews
|
|
这里 mListContainer 是 NotificationListContainer,NotificationStackScrollLayout#addContainerView 进行了重写。
反查, NotificationViewHierarchyManager#updateNotificationViews 被 StatusBar#updateNotificationViews 方法调用了。
StatusBar#updateNotificationViews
|
|
StatusBar#updateNotificationViews 被 NotificationEntryManager#updateNotifications 调用了。
NotificationEntryManager#updateNotifications
|
|
presenter 是 NotificationPresenter 对象,从 StatusBar#makeStatusBarView 传过来了,继续看 NotificationEntryManager#updateNotifications 哪里被调用了,是 NotificationEntryManager#addNotificationViews。
NotificationEntryManager#addNotificationViews
|
|
NotificationEntryManager#addEntry 由 NotificationEntryManager#onAsyncInflationFinished 调用了。
NotificationEntryManager#onAsyncInflationFinished
|
|
问题来了,NotificationEntryManager#onAsyncInflationFinished 哪里被调到了,似乎断掉了,是怎么和来通知关联起来的?这得需要看看通知的流程。
通知流程
这部分分析按照正常的调用顺序来分析。
NotificationManager#notify
NotificationManager 调用 notify 方法发送 notification,最后调用到 notifyAsUser() 方法:
这里 service 是 INotificationManager,对应的是 NotificationManagerService,看 NotificationManagerService#enqueueNotificationWithTag,又调用了 NotificationManagerService#enqueueNotificationInternal。
NotificationManagerService#enqueueNotificationInternal
|
|
EnqueueNotificationRunnable#run
|
|
PostNotificationRunnable#run
|
|
mListeners 是 NotificationListeners,调用 NotificationManagerService#notifyPostedLocked。
NotificationManagerService#notifyPostedLocked
|
|
这里 service 是 INotificationListener,对应的是 NotificationListenerWrapper,看 NotificationListenerWrapper#onNotificationPosted。
NotificationListenerWrapper#onNotificationPosted
|
|
看 MyHandler 处理中的 MSG_ON_NOTIFICATION_POSTED。
MyHandler#handleMessage
|
|
NotificationListenerService#onNotificationPosted
|
|
NotificationListenerService 是抽象类,NotificationListenerService#onNotificationPosted 在 NotificationListener##onNotificationPosted 有重写。
NotificationListener#onNotificationPosted
|
|
调用了 NotificationEntryManager#addNotification。
NotificationEntryManager#addNotification
|
|
从 NotificationEntryManager#addNotification 到 NotificationEntryManager#addNotificationInternal 再到 NotificationEntryManager#inflateViews 方法。
NotificationEntryManager#inflateViews
|
|
RowInflaterTask#inflate
|
|
再看 RowInflaterTask#onInflateFinished:
看 NotificationEntryManager#row 会调用 bindRow 和 updateNotification,看 updateNotification方法最终会调用 ExpandableNotificationRow#updateNotification。
ExpandableNotificationRow#updateNotification
|
|
继续跟,到 NotificationInflater#inflateNotificationViews。
NotificationInflater#inflateNotificationViews
|
|
看 AsyncInflationTask 执行的结果:
|
|
调用 NotificationInflater#apply,最终会到 NotificationInflater#applyRemoteView
继续看 NotificationInflater#finishIfDone,这个方法看到最后的endListener.onAsyncInflationFinished(row.getEntry());
实现方法在 NotificationEntryManager#onAsyncInflationFinished。
NotificationEntryManager#onAsyncInflationFinished
|
|
这里的 addEntry 方法调用了addNotificationViews,好了,终于和 SystemUI 的通知关联起来了,这样,锁屏来通知分析结束。
折叠状态栏通知
有了以上锁屏通知分析,再来分析折叠状态栏通知就简单很多了,先看来折叠状态栏初始化部分。
status_bar.xml
折叠状态栏对应的布局文件是 status_bar.xml:
如果来通知,就在 notification_icon_area 进行 addView 填充。再看看代码初始化。
StatusBar#makeStatusBarView
|
|
CollapsedStatusBarFragment#initNotificationIconArea
|
|
看到这里的notificationIconArea.addView(mNotificationIconAreaInner);
,notificationIconArea 被 mNotificationIconAreaInner 填充,因此我们要重点关注 NotificationIconAreaController 什么时候被填充。
有以上锁屏通知分析知道有通知来最后会调用 StatusBar#updateNotificationViews。
StatusBar#updateNotificationViews
|
|
调用 NotificationIconAreaController#updateNotificationIcons。
NotificationIconAreaController#updateNotificationIcons
|
|
OK,折叠状态栏通知分析结束。
结语
本篇梳理了 SystemUI Notification 大致流程,分为锁屏的通知和状态栏通知,代码很多,细节没有去纠结,省略了很多代码,有兴趣,可以自己去 AOSP 查看。