本文將比較全面的介紹SystemUI的組成,實現,佈局以及客製化方案等等。本博文基於android8.0源碼進行分析,因爲android8.0相比之前的版本SystemUI部分改動是很是大的。java
1、SystemUI組成
SystemUI包含的功能很是豐富,組成元素主要包含常見的System Bars,以及ScreenShot截屏、壁紙、最近運行的應用程序等。SystemUI也是各大安卓版本中變化比較大的一個部分。android
Status Bar
Navigation Bar
Combined Bar (主要爲Tablet設備使用)
Notifications
LockScreen
Recent (最近任務)
QuickSettings
等等
2、SystemUI實現
瞭解了SystemUI後,本文先來大概講解下StatusBar的實現流程。ide
一、應用啓動相關代碼
相關代碼主要分爲兩個部分
1)、Service部分
代碼路徑:framework/base/services/java/com/android/server
2) 、應用部分
代碼路徑:framework/base/packages/SystemUI佈局
SystemUI中SystemUIService是整個系統UI比較重要的載體,因此咱們的分析將從SystemUIService開始,而SystemUIService是從SystemServer中啓動的。關於這部分這裏不作多的分析,詳見SystemServer.java中的startSystemUi()方法。下面來看一下SystemUIServer中的onCreate()方法。ui
/*framework/base/packages/systemui/src/com/android/systemui/SystemUIService.java*/
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();this
// For debugging RescueParty
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
throw new RuntimeException();
}
}
上面的代碼能夠看出SystemUIService中實際有效代碼只是實例化了一個SystemUIApplication對象,而且調用了startServiceIfNeeded()方法。下面來看SystemUIApplication中的具體實現邏輯。spa
public void startServicesIfNeeded() {
startServicesIfNeeded(SERVICES);
}
其中SERVICES是一組全部用戶共用的SystemUI服務,以下:.net
/**
* The classes of the stuff to start.
*/
private final Class<?>[] SERVICES = new Class[] {
Dependency.class,
NotificationChannels.class, //通知管理
CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class, //鎖屏管理
Recents.class, //近期應用管理,以堆疊棧的形式展示
VolumeUI.class, //用來展現和控制音量的變化:媒體音量、鈴聲音量和鬧鐘音量
Divider.class, //分屏管理
SystemBars.class,
StorageNotification.class,
PowerUI.class, //主要處理和Power相關的事件,好比省電模式切換,電池電量變化和開關屏幕等事件
RingtonePlayer.class, //鈴聲播放
KeyboardUI.class,
PipUI.class, //提供對畫中畫模式的管理
ShortcutKeyDispatcher.class, //
VendorServices.class,
GarbageMonitor.Service.class,
LatencyTester.class,
GlobalActionsComponent.class,
RoundedCorners.class,
};debug
/**
* The classes of the stuff to start for each user. This is a subset of the services listed
* above.
*/
private final Class<?>[] SERVICES_PER_USER = new Class[] {
Dependency.class,
NotificationChannels.class,
Recents.class
};
上面對SystemUI要啓動的一系列服務有了個基本的介紹,下面來看SystemUIApplication中是怎麼啓動這一些列服務的component
private void startServicesIfNeeded(Class<?>[] services) {
...
log.traceBegin("StartServices");
final int N = services.length; //獲取要啓動的服務列表的長度
for (int i = 0; i < N; i++) {
Class<?> cl = services[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
log.traceBegin("StartServices" + cl.getSimpleName());
long ti = System.currentTimeMillis();
try {
/* 經過SystemUIFactory來建立相應的單例 */
Object newService = SystemUIFactory.getInstance().createInstance(cl);
mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
}...
mServices[i].mContext = this;
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start(); //服務啓動的地方
log.traceEnd();
// Warn if initialization of component takes too long
ti = System.currentTimeMillis() - ti;
if (ti > 1000) {
Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
}
if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
log .traceEnd(); ...
}
能夠看到SystemBar這個服務只是做爲了一箇中間過程,啓動了StatusBar,如今咱們開看一下StatusBar的start()方法:
@Override
public void start() {
... //這裏面進行了StatusBar中各個組件的初始化
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
...
try {
/* 通過一系列對象的建立與初始化後,開始向StatusBarService進行註冊。這裏涉及跨進程操做,
於是傳遞的參數都是繼承自Parcelable的 */
mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
fullscreenStackBounds, dockedStackBounds);
} ...
createAndAddWindows(); //這裏纔是真正將Status Bar顯示出來的地方
}
這裏你們就會有疑問了,既然已經有了StatusBar了,那麼這裏忽然殺出來個StatusBarService,究竟是爲何呢?
先來看看StatusBarService,經過Context.STATUS_BAR_SERVICE,直覺告訴咱們這個應用程序應該是在SystemServer中。咱們能夠看看是誰向SystemServer中註冊的這個服務,下面來看一下SystemUI中的代碼。
if (!disableSystemUI) {
traceBeginAndSlog("StartStatusBarManagerService");
try {
statusBar = new StatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e); //原來StatusBarManagerService這個傢伙註冊的
}
traceEnd();
}
接下來進一步分析StatusBarManagerService的實現,首先來看下其中的registerStatusBar中的代碼:
@Override
public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
Rect fullscreenStackBounds, Rect dockedStackBounds) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
mBar = bar;
try {
mBar.asBinder().linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
mBar = null;
notifyBarAttachChanged();
}
}, 0);
} catch (RemoteException e) {
}
notifyBarAttachChanged();
synchronized (mIcons) { //複製icon列表
for (String slot : mIcons.keySet()) {
iconSlots.add(slot);
iconList.add(mIcons.get(slot));
}
}
synchronized (mLock) {
switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
switches[1] = mSystemUiVisibility;
switches[2] = mMenuVisible ? 1 : 0;
switches[3] = mImeWindowVis;
switches[4] = mImeBackDisposition;
switches[5] = mShowImeSwitcher ? 1 : 0;
switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
switches[7] = mFullscreenStackSysUiVisibility;
switches[8] = mDockedStackSysUiVisibility;
binders.add(mImeToken);
fullscreenStackBounds.set(mFullscreenStackBounds);
dockedStackBounds.set(mDockedStackBounds);
}
}
從上面的代碼看,registerStatusBar的做用主要是:1、爲新啓動的SystemUI應用賦予當前系統的真實值(好比有多少須要顯示的圖標);2、經過成員變量mBar記錄IstatusBar對象,它在SystemUI中對應的是CommandQueue。
下面經過本身整理的調用流程圖,你們能夠參考一下: