上一篇我们具体分析了状态栏上状态图标,例如 wifi、蓝牙等图标的控制流程,本篇文章我们继续来分析下状态栏上通知图标的控制流程。主要分析当一个新通知来临时,新通知的图标是如何一步步显示到状态栏上的。
1、通过上一篇系统状态栏图标控制可知,状态栏图标是由一个叫StatusBarIconController接口控制显示的,而通知图标区域也有一个控制器,叫NotificationIconAreaController(它不是一个接口)。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
public class NotificationIconAreaController implements DarkReceiver {
...
public NotificationIconAreaController(Context context, StatusBar statusBar) {
mStatusBar = statusBar;
mNotificationColorUtil = NotificationColorUtil.getInstance(context);//通知栏颜色工具
mContext = context;
mEntryManager = Dependency.get(NotificationEntryManager.class);
initializeNotificationAreaViews(context);//初始化通知栏区域视图
}
...
}
2、在NotificationIconAreaController的构造函数中会调用如下方法来创建通知图标的容器
public class NotificationIconAreaController implements DarkReceiver {
...
/**
* 初始化化通知图标区域视图
*/
protected void initializeNotificationAreaViews(Context context) {
reloadDimens(context);
LayoutInflater layoutInflater = LayoutInflater.from(context);
// 实例化通知图标区域视图
mNotificationIconArea = inflateIconArea(layoutInflater);
// mNotificationIcons才是真正存放通知图标的父容器
mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(R.id.notificationIcons);
mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
}
...
protected View inflateIconArea(LayoutInflater inflater) {
// 实例化通知图标区域视图
return inflater.inflate(R.layout.notification_icon_area, null);
}
...
}
3、这里加载了notification_icon_are.xml布局,来看下这个布局
frameworks/base/packages/SystemUI/res/layout/notification_icon_area.xml
<com.android.keyguard.AlphaOptimizedLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_icon_area_inner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">
<com.android.systemui.statusbar.phone.NotificationIconContainer
android:id="@+id/notificationIcons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:clipChildren="false"/>
com.android.keyguard.AlphaOptimizedLinearLayout>
id为notificationIcons的NotificationIconContainer就是通知图标容器,对应于上面代码的mNotificationIcons变量。
1、既然是NotificationIconAreaController自己创建了通知图标容器,那么通知图标是如何被添加到状态栏视图中的呢?这个动作其实是在创建状态栏视图后完成的,主要是在StatusBar的makeStatusBarView方法中。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
...
// 创建状态栏视图
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();
...
}
2、调用的就是CollapsedStatusBarFragment的initNotificationIconArea()方法。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
public void initNotificationIconArea(NotificationIconAreaController
notificationIconAreaController) {
// 通知图标区域
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);
}