在源码中的位置/frameworks/base/package/SystemUI
SystemUI是什么?
systemui : 截屏操作TakeScreenshotService、图片壁纸ImageWallpaper、低电警告powerui、播放铃声ringtoneplayer、usb、volumeui、状态栏statusbar、导航栏navigationbar、最近使用列表recents、锁屏keyguardviewmediator
状态栏需要实时反馈系统状态,那么它就会长存系统中(AndroidManifest.xml中的android:persistent="true"),而在Android中长存系统运行的组件只有Service,那么,状态栏就是一个长存系统进程空间运行的Service,它是一个系统服务。
运行于一个名为SystemUIService的system_server进程通过Context.startService()方式启动的常规Android服务中,并且通过WindowManager.addView()创建他们的窗口。
SystemUIService:一个普通的Android服务,它以一个容器的角色运行于SystemUI进程中。在它内部运行着多个子服务,其中之一便是状态栏与导航栏的实现者——BaseStatusBar的子类之一。
IstatusBarService:即系统服务StatusBarManagerService,状态导航栏向外界提供服务的前端端口,运行于system_server进程中。
BaseStatusBar及其子类:状态栏与导航栏的实际实现者,运行于SystemUIService中。
IstatusBar,即SystemUI中的CommandQueue,联系StatusBarManagerService与BaseStatusBar的桥梁。
ImageWallpaper、RecentActivity、TaskScreenshotService等都是标准的Android应用程序组件,且相互独立。
状态栏和导航栏运行于一个名称为SystemUIService的Service中,因此其启动过程就是SystemUIService的启动过程。
SystemUIService何时由谁启动?作为一个系统级别的UI组件,应是在系统启动过程中完成。在负责启动各种系统服务的ServerThread中,当核心系统服务启动完成后,ServerThread会通过调用ActivityManagerService.systemReady()方法通知AMS系统已经就绪。这个systemReady拥有一个名为goingCallback的Runnable实例作为参数。顾名思义,当AMS完成对systemReady()的处理后将会回调这一Runnable的run()方法。在这一run()方法中可以找到SystemUI的身影。则启动流程如图所示。
PhoneStatusBar,CommandQueue,StatusBarManagerService
当StatusBarManagerService接受到操作状态栏与导航栏的请求时,首先将请求信息保存在副本中,然后再将这一请求通过mBar(即CommandQueue)发送给BaseStatusBar。
StatusBarManagerService作用与工作原理:在ServerThread中创建(参考代码SystemServer.java->main()->run()->startOtherServices())。
①StatusBarManagerService是SystemUI中状态栏与导航栏在system_server的代理。所有对状态栏和导航栏有需求的对象都可以通过获取StatusBarManagerService的实例达到其目的。不过应具备权限。
②它保存了状态栏和导航栏所需信息的副本,用于在SystemUI意外退出之后的恢复。
PhoneStatusBar
PhoneStatusBar通过IstatusBarService来访问StatusBarManagerService;
StatusBarManagerService通过CommandQueue来和PhoneStatusBar交互。
在SystemUiApplication中,根据需要启动以下的Service
privatefinal Class>[] SERVICES = new Class[]
{
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recent.Recents.class,
com.android.systemui.volume.VolumeUI.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class
};
相关类:
PhoneStatusBarPolicy设置图标,通过监听系统状态相关的广播来修改图标
StatusBarManager
StatusBarManagerService
CommandQueue
PhoneStatusBar
BaseStatusBar
系统启动时在SystemServer的main->run()->startOtherServices(),
if (!disableSystemUI) {
try {
Slog.i(TAG, "Status Bar");
statusBar = newStatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE,statusBar);
} catch (Throwable e) {
reportWtf("startingStatusBarManagerService", e);
}
}
而StatusBarManagerService在构造方法中,
publicStatusBarManagerService(Context context,WindowManagerServicewindowManager) {
mContext = context;
mWindowManager = windowManager;
final Resources res = context.getResources();
mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
LocalServices.addService(StatusBarManagerInternal.class,mInternalService);
}
图标名称和顺序
总结下,在SystemServer进程中,维系了一个StatusBarManagerService对象statusBar,而statusBar对象维系了一个StatusBarIconList对象mIcons,这样就实现了在SystemServer中维系了一个mIcons,而这个mIcons存储了status bar中图标(String)和顺序。
StatusBarManagerService对外接口三个
setIcon
setIconVisibility
removeIcon
当然,这些接口是系统内容使用的,应用只能通过间接的方法去改变系统状态图标,无法直接更改。例如要让系统状态显示设置了闹钟,就需要发送anction.intent.action.ALARM_CHANGED广播,在SystemUi中接收这一广播并调用以上接口来改变图标的显示情况。
UI有2个接口,在CommandQueue中实现
setIcon
removeIcon
经过桥接的CommandQueue最后交给UI实现的接口3个
addIcon如果调用的setIcon的slot没有在SystemUI中的数据有记录,那么会调用这个,SystemUI添加上一个StatuaBarIconView
updateIcon如果调用的setIcon的slot在SystemUI中有记录,调用这个,SystemUI更新下已有的状态
removeIconSystemUI移除一个已经添加的图标
下图为加载Icon的时序图:
最后到StatusBarIconView的set中看更新状态
PS:
setIcon的参数:
slot:用于声明图标的意图。它必须存在于config_statusBarIcons所预定的意图列表中。
Icon:用于显示图标资源id。
iconLevel:图标资源level。
contentDescription:详细描述图标的含义。