SystemUI之StatusBar状态栏
- 布局结构
下拉菜单、状态栏都是属于statusbar,结构树上也是属于顶层的super_status_bar.xml(StatusBarWindowView)
从上图可以看出顶层树是super_status_bar,之后会走两个分支status_bar_container和status_bar_expanded。
status_bar_expanded下拉菜单,分快捷图标和通知栏。
status_bar_container状态栏,分左边通知栏和右边系统功能的状态图标显示。
二、代码控制流程
2.1、StatusBar创建准备工作
2.1.1、StatusBar :start()
SystemUIService(extends Service) :onCreate()à
((SystemUIApplication).startServicesIfNeeded() à mServices[i].start()
StatusBar也是SystemUI的一个服务(并非真正的service),所以它的启动入口也是从start()方法开始。主要做了以下几件事:
1.获取各种服务为后续工作做准备。
2.建立farmework的联系,把自己注册到StatusBarService中以供其他app使用--能在APP层来控制导航栏和状态栏可见
mBarService=IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders, fullscreenStackBounds, dockedStackBounds);
3. 创建StatusBar.java :createAndAddWindows() ,并且做一些初始化值
- public void start() {
- ……
- mKeyguardIndicationController.init();
- ……
- mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- ……
- mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); ……
- mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- ……
- try {
- result = mBarService.registerStatusBar(mCommandQueue);
- } catch (RemoteException ex) {
- ex.rethrowFromSystemServer();
- }
- createAndAddWindows(result);
- ……
- }
|
- public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
- makeStatusBarView(result);
- mNotificationShadeWindowController.attach();
- //会将statusbarView添加到window上àmWindowManager.addView(mStatusBarView, mLp);
- mStatusBarWindowController.attach();
- }
|
2.1.1、StatusBar :createAndAddWindows()
createAndAddWindows() à makeStatusBarView(result)
makeStatusBarView负责状态栏具体创建
1.加载statusbar设备树super_status_bar :inflateStatusBarWindow(context)-->mPhoneStatusBarWindow(mSuperStatusBarViewFactory.getStatusBarWindowView()),这个设备树的根View是StatusBarWindowView
2.CollapsedStatusBarFragment就是作为加载状态栏的Fragment
- // Constructing the view
- protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
- ……
- inflateStatusBarWindow();
- ……
- //主要是有关notification的服务类获取
- mStackScrollerController =
- mNotificationPanelViewController.getNotificationStackScrollLayoutController();
- ……
- FragmentHostManager.get(mPhoneStatusBarWindow)
- .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
- CollapsedStatusBarFragment statusBarFragment =
- (CollapsedStatusBarFragment) fragment;
- ……
- }).getFragmentManager()
- .beginTransaction()
- .replace(R.id.status_bar_container,
- new CollapsedStatusBarFragment(
- mOngoingCallController,
- ……
- this,
- mCommandQueue
- ),
- CollapsedStatusBarFragment.TAG)
- .commit();
-
- mHeadsUpManager.setup(mVisualStabilityManager);
- ……
- createNavigationBar(result);
- ……
- // 通知背景、Qs背景等
- ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
- ……
- // receive broadcasts
- registerBroadcastReceiver();
- ……
- }
|
|
public void attach() {
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
mBarHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
……
mLp.gravity = Gravity.TOP;
……
mWindowManager.addView(mStatusBarView, mLp);
……
} |
|
|
扩展:StatusBar在窗口的位置如何确定 ???
DisplayPolicy.java à layoutStatusBar
2.2、状态栏图标加载及数据初始化(CollapsedStatusBarFragment)
2.2.1、布局加载
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.status_bar, container, false);
- }
|
status_bar.xml的文件:
1.根View :StatusBarWindowView,这个是一个继承FrameLayout的View。所以能比较初步的知道这个子View的界面的加载流程
2.@+id/status_bar_contents 这个LinearLayout,里面包含了@+id/status_bar_left_side ,状态栏左边部分。这个状态栏左边部分包含了时钟@+id/clock和通知@+id/notification_icon_area
3.@+id/system_icon_area这个也是一个LinearLayout包含了@layout/system_icons,状态栏右边部分,里面包含了电池图标和系统状态图标
系统状态图标还是通知图标都是动态加载
2.2.2、数据加载
1、左边通知图标的添加流程(@+id/notification_icon_area)
a、左边通知view加载过程
- @Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
- ……
- View contents = mStatusBar.findViewById(R.id.status_bar_contents);
- ……
- mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
- mClockView = mStatusBar.findViewById(R.id.clock);
- ……
- initOperatorName();
- initNotificationIconArea();
- }
|
- /** Initializes views related to the notification icon area. */
- public void initNotificationIconArea() {
- ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
- mNotificationIconAreaInner =
- mNotificationIconAreaController.getNotificationInnerAreaView();
- if (mNotificationIconAreaInner.getParent() != null) {
- ((ViewGroup) mNotificationIconAreaInner.getParent())
- .removeView(mNotificationIconAreaInner);
- }
- notificationIconArea.addView(mNotificationIconAreaInner);
- ……
- statusBarCenteredIconArea.addView(mCenteredIconArea);
- }
|
NotificationIconAreaController:这个类主要是用于通知icon的控制类。
mNotificationIconAreaInner是通过加载notification_icon_area而生成的view;
b、左边通知data加载过程
每次系统通知变化的会回调NotificationListenerService的onNotificationPosted
NotificationListener.onNotificationPosted à handler.onNotificationPosted(sbn, rankingMap) à NotificationEntryManager.onNotificationPosted(sbn, rankingMap)
- private final NotificationHandler mNotifListener = new NotificationHandler() {
- @Override
- public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
- final boolean isUpdateToInflatedNotif = ……
- if (isUpdateToInflatedNotif) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap);
- }
- }
|
1.addNotification(sbn, rankingMap) à addNotificationInternal(icon首次添加)
a、StatusBarNotification 里面的信息转换成NotificationEntry。
b、绑定一些监听。
c、把新添加的信息保持在mPendingNotifications,这个集合保持了所有显示的通知
2.updateNotification à updateNotificationInternal
View显示有关的内容:
à updateNotifications à mPresenter.updateNotificationViews(reason)
mPresenter是StatusBarNotificationPresenter.java的实例
à updateNotificationViews à mNotificationPanel.updateNotificationViews(reason);
mNotificationIconAreaController:updateNotificationIcons à updateStatusBarIcons
à updateIconsForLayout
- /**
- * Updates the notification icons for a host layout. This will ensure that the notification
- */
- private void updateIconsForLayout(Function function,
- NotificationIconContainer hostLayout,……) {
- ArrayList toShow = new ArrayList<>(mNotificationEntries.size());
- ……
- for (int i = 0; i < toShow.size(); i++) {
- StatusBarIconView v = toShow.get(i);
- hostLayout.removeTransientView(v);
- if (v.getParent() == null) {
- if (hideDismissed) {
- v.setOnDismissListener(mUpdateStatusBarIcons);
- }
- hostLayout.addView(v, i, params);
- }
- }
-
- hostLayout.setChangingViewPositions(true);
- // Re-sort notification icons
- final int childCount = hostLayout.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View actual = hostLayout.getChildAt(i);
- StatusBarIconView expected = toShow.get(i);
- if (actual == expected) {
- continue;
- }
- hostLayout.removeView(expected);
- hostLayout.addView(expected, i);
- }
- ……
- }
|
从上面的代码看出updateIconsForLayout含税会把StatusBarIconView添加到NotificationIconContainer这个ViewGroup中,而NotificationIconContainer依据前面的分析是挂载在左边通知区域。到现在整个的通知信息加载流程梳理完成。
2、系统icon的加载 @+id/system_icon_area
a、CollapsedStatusBarFragment.onViewCreated
以上把StatusIconContainer保存到IconManager里面:
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons))
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
R.id.statusIcons这个其实是在system_icons.xml里面的StatusIconContainer,这个View是一个LinearLayout(另外一个是BatteryMeterView)。
DarkIconManager是StatusBarIconController的一个内部类,DarkIconManager extends IconManager,IconManager这个类里面做的事情是创建StatusBarIconView,部分代码:
b、子view添加到StatusIconContainer流程
StatusBar.java.start()-->(PhoneStatusBarPolicy)mIconPolicy.init()
PhoneStatusBarPolicy是除了信号的状态Icon的所有系统Icon。而信号的icon就由StatusBarSignalPolicy来做初始化;
PhoneStatusBarPolicy.java
- /** Initialize the object after construction. */
- public void init() {
- ……
- // TTY status
- updateTTY();
- // bluetooth status
- updateBluetooth();
- // Alarm clock
- mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
- mIconController.setIconVisibility(mSlotAlarmClock, false);
- ……
- }
|
StatusBarIconControllerImpl
setIcon() à addSystemIcon(index, holder) à onIconAdded
- @Override
- public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
- boolean isNew = getIcon(index, holder.getTag()) == null;
- super.setIcon(index, holder);
-
- if (isNew) {
- addSystemIcon(index, holder); //新增
- } else {
- handleSet(index, holder); //更新
- }
- }
|
- private void addSystemIcon(int index, StatusBarIconHolder holder) {
- String slot = getSlotName(index);
- int viewIndex = getViewIndex(index, holder.getTag());
- boolean hidden = mIconHideList.contains(slot);
-
- mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
- }
|
StatusBarIconController.IconManager.onIconAdded--> addHolder
- protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
- StatusBarIconHolder holder) {
- if (mBlockList.contains(slot)) {
- blocked = true;
- }
- switch (holder.getType()) {
- case TYPE_ICON:
- return addIcon(index, slot, blocked, holder.getIcon());
-
- case TYPE_WIFI:
- return addSignalIcon(index, slot, holder.getWifiState());
-
- case TYPE_MOBILE:
- return addMobileIcon(index, slot, holder.getMobileState());
- }
- return null;
- }
|
- protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
- StatusBarIcon icon) {
- StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
- view.set(icon);
- mGroup.addView(view, index, onCreateLayoutParams());
- return view;
- }
|
最后会调用addIcon,创建一个StatusBarIconView 添加到mGroup,而mGroup就是我们在所提到的R.id.statusIcons,也就是StatusIconContainer。到现在系统icon就添加到状态栏右边了。