如7.1.1节所述,状态栏与导航栏的启动由其PhoneStatusBar.start()完成。参考其实现:
**PhoneStatusBar.java-->PhoneStatusBar.start()**
```
public void start() {
......
// **① 调用父类BaseStatusBar的start()方法进行初始化。**
super.start();
// 创建导航栏的窗口
addNavigationBar();
// **② 创建PhoneStatusBarPolicy。**PhoneStatusBarPolicy定义了系统通知图标的设置策略
mIconPolicy = new PhoneStatusBarPolicy(mContext);
}
```
参考BaseStatusBar.start()的实现,这段代码比较长,并且涉及到了本章随后会详细介绍的内容。因此倘若读者阅读起来比较吃力可以仅关注那三个关键步骤。在完成本章的学习之后再回过头来阅读这部分代码便会发现十分简单了。
**BaseStatusBar-->BaseStatusBar.start()**
```
public void start() {
/* 由于状态栏的窗口不属于任何一个Activity,所以需要使用第6章所介绍的WindowManager
进行窗口的创建 */
mWindowManager = (WindowManager)mContext
.getSystemService(Context.WINDOW_SERVICE);
/* 在第4章介绍窗口的布局时曾经提到状态栏的存在对窗口布局有着重要的影响。因此状态栏中
所发生的变化有必要通知给WMS */
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
......
/*mProvisioningOberver是一个ContentObserver。
它负责监听Settings.Global.DEVICE_PROVISIONED设置的变化。这一设置表示此设备是否已经
归属于某一个用户。比如当用户打开一个新购买的设备时,初始化设置向导将会引导用户阅读使用条款、
设置帐户等一系列的初始化操作。在初始化设置向导完成之前,
Settings.Global.DEVICE_PROVISIONED的值为false,表示这台设备并未归属于某
一个用户。
当设备并未归属于某以用户时,状态栏会禁用一些功能以避免信息的泄露。mProvisioningObserver
即是用来监听设备归属状态的变化,以禁用或启用某些功能 */
mProvisioningObserver.onChange(false); // set up
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
mProvisioningObserver);
/* **① 获取IStatusBarService的实例。**IStatusBarService是一个系统服务,由ServerThread
启动并常驻system_server进程中。IStatusBarService为那些对状态栏感兴趣的其他系统服务定
义了一系列API,然而对SystemUI而言,它更像是一个客户端。因为IStatusBarService会将操作
状态栏的请求发送给SystemUI,并由后者完成请求 */
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
/* 随后BaseStatusBar将自己注册到IStatusBarService之中。以此声明本实例才是状态栏的真正
实现者,IStatusBarService会将其所接受到的请求转发给本实例。
“天有不测风云”,SystemUI难免会因为某些原因使得其意外终止。而状态栏中所显示的信息并不属于状态
栏自己,而是属于其他的应用程序或是其他的系统服务。因此当SystemUI重新启动时,便需要恢复其
终止前所显示的信息以避免信息的丢失。为此,IStatusBarService中保存了所有的需要状态栏进行显
示的信息的副本,并在新的状态栏实例启动后,这些副本将会伴随着注册的过程传递给状态栏并进行显示,
从而避免了信息的丢失。
从代码分析的角度来看,这一从IstatusBarService中取回信息副本的过程正好完整地体现了状态栏
所能显示的信息的类型*/
/*iconList是向IStatusBarService进行注册的参数之一。它保存了用于显示在状态栏的系统状态
区中的状态图标列表。在完成注册之后,IStatusBarService将会在其中填充两个数组,一个字符串
数组用于表示状态的名称,一个StatusBarIcon类型的数组用于存储需要显示的图标资源。
关于系统状态区的工作原理将在7.2.3节介绍*/
StatusBarIconList iconList = new StatusBarIconList();
/*notificationKeys和StatusBarNotification则存储了需要显示在状态栏的通知区中通知信息。
前者存储了一个用Binder表示的通知发送者的ID列表。而notifications则存储了通知列表。二者
通过索引号一一对应。关于通知的工作原理将在7.2.2节介绍 */
ArrayList<IBinder> notificationKeys = newArrayList<IBinder>();
ArrayList<StatusBarNotification> notifications
= newArrayList<StatusBarNotification>();
/*mCommandQueue是CommandQueue类的一个实例。CommandQueue继承自IStatusBar.Stub。
因此它是IStatusBar的Bn端。在完成注册后,这一Binder对象的Bp端将会保存在
IStatusBarService之中。因此它是IStatusBarService与BaseStatusBar进行通信的桥梁。
*/
mCommandQueue= new CommandQueue(this, iconList);
/*switches则存储了一些杂项:禁用功能列表,SystemUIVisiblity,是否在导航栏中显示虚拟的
菜单键,输入法窗口是否可见、输入法窗口是否消费BACK键、是否接入了实体键盘、实体键盘是否被启用。
在后文中将会介绍它们的具体影响 */
int[]switches = new int[7];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
// **② 向IStatusBarServie进行注册,并获取所有保存在IStatusBarService中的信息副本**
mBarService.registerStatusBar(mCommandQueue, iconList,
notificationKeys,notifications,
switches, binders);
} catch(RemoteException ex) {......}
// **③ 创建状态栏与导航栏的窗口。**由于创建状态栏与导航栏的窗口涉及到控件树的创建,因此它由子类
PhoneStatusBar或TabletStatusBar实现,以根据不同的布局方案选择创建不同的窗口与控件树 */
createAndAddWindows();
/*应用来自IStatusBarService中所获取的信息
mCommandQueue已经注册到IStatusBarService中,状态栏与导航栏的窗口与控件树也都创建完毕
因此接下来的任务就是应用从IStatusBarService中所获取的信息 */
disable(switches[0]); // 禁用某些功能
setSystemUiVisibility(switches[1], 0xffffffff); // 设置SystemUIVisibility
topAppWindowChanged(switches[2]!= 0); // 设置菜单键的可见性
// 根据输入法窗口的可见性调整导航栏的样式
setImeWindowStatus(binders.get(0), switches[3], switches[4]);
// 设置硬件键盘信息。
setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
// 依次向系统状态区添加状态图标
int N = iconList.size();
......
// 依次向通知栏添加通知
N = notificationKeys.size();
......
/* 至此,与IStatusBarService的连接已建立,状态栏与导航栏的窗口也已完成创建与显示,并且
保存在IStatusBarService中的信息都已完成了显示或设置。状态栏与导航栏的启动正式完成 */
}
```
可见,状态栏与导航栏的启动分为如下几个过程:
- 获取IStatusBarService,IStatusBarService是运行于system\_server的一个系统服务,它接受操作状态栏/导航栏的请求并将其转发给BaseStatusBar。为了保证SystemUI意外退出后不会发生信息丢失,IStatusBarService保存了所有需要状态栏与导航栏进行显示或处理的信息副本。
- 将一个继承自IStatusBar.Stub的CommandQueue的实例注册到IStatusBarService以建立通信,并将信息副本取回。
- 通过调用子类的createAndAddWindows()方法完成状态栏与导航栏的控件树及窗口的创建与显示。
- 使用从IStatusBarService取回的信息副本。
- 前言
- 推荐序
- 第1章 开发环境部署
- 1.1获取Android源代码
- 1.2Android的编译
- 1.3在IDE中导入Android源代码
- 1.3.1将Android源代码导入Eclipse
- 1.3.2将Android源代码导入SourceInsight
- 1.4调试Android源代码
- 1.4.1使用Eclipse调试Android Java源代码
- 1.4.2使用gdb调试Android C/C 源代码
- 1.5本章小结
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java层中的Binder分析
- 2.2.1Binder架构总览
- 2.2.2初始化Java层Binder框架
- 2.2.3窥一斑,可见全豹乎
- 2.2.4理解AIDL
- 2.2.5Java层Binder架构总结
- 2.3心系两界的MessageQueue
- 2.3.1MessageQueue的创建
- 2.3.2提取消息
- 2.3.3nativePollOnce函数分析
- 2.3.4MessageQueue总结
- 2.4本章小结
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量键的处理流程
- 3.2.2通用的音量设置函数setStreamVolume()
- 3.2.3静音控制
- 3.2.4音量控制小结
- 3.3音频外设的管理
- 3.3.1 WiredAccessoryObserver 设备状态的监控
- 3.3.2AudioService的外设状态管理
- 3.3.3音频外设管理小结
- 3.4AudioFocus机制的实现
- 3.4.1AudioFocus简单的例子
- 3.4.2AudioFocus实现原理简介
- 3.4.3申请AudioFocus
- 3.4.4释放AudioFocus
- 3.4.5AudioFocus小结
- 3.5AudioService的其他功能
- 3.6本章小结
- 第4章 深入理解WindowManager-Service
- 4.1初识WindowManagerService
- 4.1.1一个从命令行启动的动画窗口
- 4.1.2WMS的构成
- 4.1.3初识WMS的小结
- 4.2WMS的窗口管理结构
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的显示次序
- 4.3.1主序、子序和窗口类型
- 4.3.2通过主序与子序确定窗口的次序
- 4.3.3更新显示次序到Surface
- 4.3.4关于显示次序的小结
- 4.4窗口的布局
- 4.4.1从relayoutWindow()开始
- 4.4.2布局操作的外围代码分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期处理
- 4.4.5布局DisplayContent
- 4.4.6布局的阶段
- 4.5WMS的动画系统
- 4.5.1Android动画原理简介
- 4.5.2WMS的动画系统框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口动画
- 4.5.5交替运行的布局系统与动画系统
- 4.5.6动画系统总结
- 4.6本章小结
- 第5章 深入理解Android输入系统
- 5.1初识Android输入系统
- 5.1.1getevent与sendevent工具
- 5.1.2Android输入系统简介
- 5.1.3IMS的构成
- 5.2原始事件的读取与加工
- 5.2.1基础知识:INotify与Epoll
- 5.2.2 InputReader的总体流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的读取与加工总结
- 5.3输入事件的派发
- 5.3.1通用事件派发流程
- 5.3.2按键事件的派发
- 5.3.3DispatcherPolicy与InputFilter
- 5.3.4输入事件的派发总结
- 5.4输入事件的发送、接收与反馈
- 5.4.1深入理解InputChannel
- 5.4.2连接InputDispatcher和窗口
- 5.4.3事件的发送
- 5.4.4事件的接收
- 5.4.5事件的反馈与发送循环
- 5.4.6输入事件的发送、接收与反馈总结
- 5.5关于输入系统的其他重要话题
- 5.5.1输入事件ANR的产生
- 5.5.2 焦点窗口的确定
- 5.5.3以软件方式模拟用户操作
- 5.6本章小结
- 第6章 深入理解控件系统
- 6.1 初识Android的控件系统
- 6.1.1 另一种创建窗口的方法
- 6.1.2 控件系统的组成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的创建与体系结构
- 6.2.2 通过WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 删除窗口
- 6.2.5 WindowManager的总结
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的创建及其重要的成员
- 6.3.2 控件系统的心跳:performTraversals()
- 6.3.3 ViewRootImpl总结
- 6.4 深入理解控件树的绘制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()与脏区域
- 6.4.3 开始绘制
- 6.4.4 软件绘制的原理
- 6.4.5 硬件加速绘制的原理
- 6.4.6 使用绘图缓存
- 6.4.7 控件动画
- 6.4.8 绘制控件树的总结
- 6.5 深入理解输入事件的派发
- 6.5.1 触摸模式
- 6.5.2 控件焦点
- 6.5.3 输入事件派发的综述
- 6.5.4 按键事件的派发
- 6.5.5 触摸事件的派发
- 6.5.6 输入事件派发的总结
- 6.6 Activity与控件系统
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的创建与显示
- 6.7 本章小结
- 第7章 深入理解SystemUI
- 7.1 初识SystemUI
- 7.1.1 SystemUIService的启动
- 7.1.2 状态栏与导航栏的创建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的体系结构
- 7.2 深入理解状态栏
- 7.2.1 状态栏窗口的创建与控件树结构
- 7.2.2 通知信息的管理与显示
- 7.2.3 系统状态图标区的管理与显示
- 7.2.4 状态栏总结
- 7.3 深入理解导航栏
- 7.3.1 导航栏的创建
- 7.3.2 虚拟按键的工作原理
- 7.3.3 SearchPanel
- 7.3.4 关于导航栏的其他话题
- 7.3.5 导航栏总结
- 7.4 禁用状态栏与导航栏的功能
- 7.4.1 如何禁用状态栏与导航栏的功能
- 7.4.2 StatusBarManagerService对禁用标记的维护
- 7.4.3 状态栏与导航栏对禁用标记的响应
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系统中的漫游过程
- 7.5.2 SystemUIVisibility发挥作用
- 7.5.3 SystemUIVisibility总结
- 7.6 本章小结
- 第8章 深入理解Android壁纸
- 8.1 初识Android壁纸
- 8.2深入理解动态壁纸
- 8.2.1启动动态壁纸的方法
- 8.2.2壁纸服务的启动原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁纸的销毁
- 8.2.5 理解Engine的回调
- 8.3 深入理解静态壁纸-ImageWallpaper
- 8.3.1 获取用作静态壁纸的位图
- 8.3.2 静态壁纸位图的设置
- 8.3.3 连接静态壁纸的设置与获取-WallpaperObserver
- 8.4 WMS对壁纸窗口的特殊处理
- 8.4.1 壁纸窗口Z序的确定
- 8.4.2 壁纸窗口的可见性
- 8.4.3 壁纸窗口的动画
- 8.4.4 壁纸窗口总结
- 8.5 本章小结