1. 程式人生 > >Android KitKat SystemUI之Status Bar

Android KitKat SystemUI之Status Bar

一、啟動流程

StatusBar的啟動流程是一個View建立,狀態設定,新增到WindowManager的過程:

SystemServer通過下面的程式碼啟動SystemUIService:

  1. staticfinalvoid startSystemUi(Context context) {  
  2.     Intent intent = new Intent();  
  3.     intent.setComponent(new ComponentName("com.android.systemui",  
  4.                 "com.android.systemui.SystemUIService"
    ));  
  5.     //Slog.d(TAG, "Starting service: " + intent);
  6.     context.startServiceAsUser(intent, UserHandle.OWNER);  
  7. }  
SystemUIService註冊在SystemUI package 的AndroidManifest.xml中,SystemUIService只是一箇中間類,它負責啟動如下的Service:
  1. privatefinal Class<?>[] SERVICES = new Class[] {  
  2.         com.android.systemui.recent.Recents.class
    ,  
  3.         com.android.systemui.statusbar.SystemBars.class,  
  4.         com.android.systemui.usb.StorageNotification.class,  
  5.         com.android.systemui.power.PowerUI.class,  
  6.         com.android.systemui.media.RingtonePlayer.class,  
  7.         com.android.systemui.settings.SettingsUI.class,  
  8.     };  
從這兒我們可以看到Recent task, system bar, storage notification, PowerUI, Ringtone Player, SettingsUI都屬於SystemUI的範疇。

那SystemBars是怎麼啟動了PhoneStatusBar的呢?分析如下的程式碼:

  1. privatevoid createStatusBarFromConfig() {  
  2.     if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");  
  3.     final String clsName = mContext.getString(R.string.config_statusBarComponent);  
  4.     if (clsName == null || clsName.length() == 0) {  
  5.         throw andLog("No status bar component configured"null);  
  6.     }  
  7.     Class<?> cls = null;  
  8.     try {  
  9.         cls = mContext.getClassLoader().loadClass(clsName);  
  10.     } catch (Throwable t) {  
  11.         throw andLog("Error loading status bar component: " + clsName, t);  
  12.     }  
  13.     try {  
  14.         mStatusBar = (BaseStatusBar) cls.newInstance();  
  15.     } catch (Throwable t) {  
  16.         throw andLog("Error creating status bar component: " + clsName, t);  
  17.     }  
  18.     mStatusBar.mContext = mContext;  
  19.     mStatusBar.mComponents = mComponents;  
  20.     mStatusBar.start();  
  21.     if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());  
  22. }  
它是從一個配置檔案獲取了一個BaseStatusBar類檔名,並建立
  1. <stringname="config_statusBarComponent"translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>

Android4.2中的statusBar包括:TabletStatusBarPhoneStatusBar, TvStatusBar,而在4.4PhoneTablet合併為PhoneStatusBar

我們再看一下PhoneStatusBar的程式碼:

  1. publicvoid start() {  
  2.     mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))  
  3.             .getDefaultDisplay();  
  4.     updateDisplaySize();//<span style="font-family:宋體;">JPH:</span>獲取螢幕大小
  5.     super.start(); // calls createAndAddWindows()
  6.     addNavigationBar();  
  7.     // Lastly, call to the icon policy to install/update all the icons.
  8.     mIconPolicy = new PhoneStatusBarPolicy(mContext);  
  9.     <span style="font-family:宋體;">//JPH:在Status Bar上顯示Notification</span>
  10.     mHeadsUpObserver.onChange(true); // set up
  11.     if (ENABLE_HEADS_UP) {  
  12.         mContext.getContentResolver().registerContentObserver(  
  13.                 Settings.Global.getUriFor(SETTING_HEADS_UP), true,  
  14.                 mHeadsUpObserver);  
  15.     }  
  16. }  
這個方法最重要的是呼叫了父類的start方法,其實父類就是BaseStatusBar,另外添加了Navigation Bar。

我們看一下BaseStatusBar的start方法:

  1. publicvoid start() {  
  2.     mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);  
  3.     mWindowManagerService = WindowManagerGlobal.getWindowManagerService();  
  4.     mDisplay = mWindowManager.getDefaultDisplay();  
  5.     mDreamManager = IDreamManager.Stub.asInterface(  
  6.             ServiceManager.checkService(DreamService.DREAM_SERVICE));  
  7.     mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);  
  8.     mProvisioningObserver.onChange(false); // set up
  9.     mContext.getContentResolver().registerContentObserver(  
  10.             Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,  
  11.             mProvisioningObserver);  
  12.     mBarService = IStatusBarService.Stub.asInterface(  
  13.             ServiceManager.getService(Context.STATUS_BAR_SERVICE));  
  14.     mRecents = getComponent(RecentsComponent.class);  
  15.     mLocale = mContext.getResources().getConfiguration().locale;  
  16.     mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);  
  17.     // Connect in to the status bar manager service
  18.     StatusBarIconList iconList = new StatusBarIconList();  
  19.     ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();  
  20.     ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();  
  21.     mCommandQueue = new CommandQueue(this, iconList);  
  22.     int[] switches = newint[7];  
  23.     ArrayList<IBinder> binders = new ArrayList<IBinder>();  
  24.     try {  
  25.         mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,  
  26.                 switches, binders);  
  27.     } catch (RemoteException ex) {  
  28.         // If the system process isn't there we're doomed anyway.
  29.     }  
  30.     createAndAddWindows();  
  31.     disable(switches[0]);  
  32.     setSystemUiVisibility(switches[1], 0xffffffff);  
  33.     topAppWindowChanged(switches[2] != 0);  
  34.     // StatusBarManagerService has a back up of IME token and it's restored here.
  35.     setImeWindowStatus(binders.get(0), switches[3], switches[4]);  
  36.     setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);  
  37.     // Set up the initial icon state
  38.     int N = iconList.size();  
  39.     int viewIndex = 0;  
  40.     for (int i=0; i<N; i++) {  
  41.         StatusBarI