android(cm11)状态栏源码分析(一)
(一):寫在前面
最近由于工作需要,需要了解CM11中的有關(guān)于StatusBar相關(guān)的內(nèi)容。總的來說,剛開始閱讀其源碼的時候,是有點困難,不過通過構(gòu)建相關(guān)代碼的腦圖和流程圖,幾天下來,我已經(jīng)對其源碼有了一個大體的了解,不過其內(nèi)部細(xì)節(jié)還有很多不是很明白,但是這對于我的工作來說就已經(jīng)足夠了。
在android系統(tǒng)中,有關(guān)于系統(tǒng)狀態(tài)欄有關(guān)的代碼位于/framework/base/packages/SystemUI/中,很明顯,該SystemUI是一個app源碼,當(dāng)系統(tǒng)進(jìn)行編譯的時候,就會生成SystemUI.apk。所以我們對待它就像是對待普通app程序一樣。
好了,現(xiàn)在開始我們的代碼分析。
(二):StatusBar流程分析
對于android系統(tǒng)來說,SystemUI的啟動是有位于packages下面的android系統(tǒng)launcher啟動器啟動的,啟動方式其實是通過java的反射機(jī)制實現(xiàn)的。其啟動SystemUI的SystemUIService,該SystemUIService是Service的一個子類,同時,在該類中通過反射機(jī)制同時啟動6個和系統(tǒng)UI相關(guān)的類,這個我們后面再分析。
這6個和系統(tǒng)UI相關(guān)的類都繼承自SystemUI類,在SystemUIService中實例化這6個類的時候同時啟動該類對應(yīng)的start()方法來啟動服務(wù)。而他們的start()函數(shù)中主要是啟動相關(guān)ServiceMonitor的start方法,在該ServiceMonitor中主要是啟動相關(guān)的包的服務(wù),即調(diào)用startService()函數(shù)。在啟動服務(wù)的時候,就會實例化StatusBar,并且調(diào)用其onStart()函數(shù)。這個就是StatusBar的啟動流程,這樣說的話可能理解起來比較繁瑣,下面的這張圖就是系統(tǒng)狀態(tài)欄的啟動過程的流程圖:
(三):SystemUIService源碼分析
下面我們來分析一下SystemUIService的源碼。
該SystemUIService類繼承自Service類,說明該類是一個服務(wù)類,在該類中都是干了什么工作呢?我們先找到Service類中的onCreate()方法:
public void onCreate() {HashMap<Class<?>, Object> components = new HashMap<Class<?>, Object>();final int N = SERVICES.length;for (int i=0; i<N; i++) {Class<?> cl = SERVICES[i];Log.d(TAG, "loading: " + cl);try {mServices[i] = (SystemUI)cl.newInstance();} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InstantiationException ex) {throw new RuntimeException(ex);}mServices[i].mContext = this;mServices[i].mComponents = components;Log.d(TAG, "running: " + mServices[i]);mServices[i].start();}}從這里可以看出,通過一個for循環(huán)將數(shù)組SERVICES中保存的類實例化,即調(diào)用newInstance()函數(shù),實例化完成之后,對其對象中的屬性進(jìn)行賦值,最后再調(diào)用相應(yīng)的start()函數(shù)。
下面我們來看一下SERVICES數(shù)組中的保存的6個類:
private final Class<?>[] SERVICES = new Class[] {com.android.systemui.recent.Recents.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,com.android.systemui.settings.SettingsUI.class,};當(dāng)然,在這個類里面也存有其他相關(guān)的函數(shù),包括配置發(fā)生改變的函數(shù),銷毀函數(shù)等,下面我們來看一下該類的腦圖:
由于在這里啟動了6個相關(guān)的類,但是我們在這篇文章中,我們先分析SystemBars.class類。
(四):SystemBars源碼分析
在上面的流程圖中,我們知道,啟動的6個類都是繼承自SystemUI類,我們先來看一下SystemUI類:
SystemUI類是一個抽象類,在該類中定義了一些方法,其中包括啟動方法,配置發(fā)生改變的函數(shù),銷毀函數(shù)等。下面我們先來看一下該類的代碼:
public Context mContext;public Map<Class<?>, Object> mComponents;public abstract void start();protected void onConfigurationChanged(Configuration newConfig) {}public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}@SuppressWarnings("unchecked")public <T> T getComponent(Class<T> interfaceType) {return (T) (mComponents != null ? mComponents.get(interfaceType) : null);}public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {if (mComponents != null) {mComponents.put(interfaceType, component);}}在這個類中,比較有意思的就是Map對象,該對象就是保存相關(guān)類的組件。下面我們來看一下腦圖:
下面我們來看SystemBars的源碼,在這里我們主要查看的是其start()函數(shù):
mServiceMonitor = new ServiceMonitor(TAG, DEBUG,mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);mServiceMonitor.start(); // will call onNoService if no remote service is found在這里,主要是初始化ServiceMonitor對象,并且調(diào)用其start()函數(shù)。
但是對于ServiceMonitor類的對象來說,其start()函數(shù),最終都要調(diào)用位于SystemBars類中的createStatusBarFromConfig()函數(shù),在該函數(shù)中,主要是調(diào)用BaseStatusBar對象的start()函數(shù)。
private void createStatusBarFromConfig() {if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");final String clsName = mContext.getString(R.string.config_statusBarComponent);if (clsName == null || clsName.length() == 0) {throw andLog("No status bar component configured", null);}Class<?> cls = null;try {cls = mContext.getClassLoader().loadClass(clsName);} catch (Throwable t) {throw andLog("Error loading status bar component: " + clsName, t);}try {mStatusBar = (BaseStatusBar) cls.newInstance();} catch (Throwable t) {throw andLog("Error creating status bar component: " + clsName, t);}mStatusBar.mContext = mContext;mStatusBar.mComponents = mComponents;mStatusBar.start();if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());}下面我們來看一下SystemBars類的腦圖:
(五):ServiceMonitor源碼分析
在ServiceMonitor類中主要是使用Handler中的信息類來進(jìn)行包服務(wù)管理,其中有啟動服務(wù),繼續(xù)服務(wù),暫停服務(wù),停止服務(wù)等函數(shù),在這里輾轉(zhuǎn)反側(cè)最終還是回歸到SystemBars中的StatusBars的啟動:
(六):最終流程分析
上面我們提到了,最終還是要啟動StatusBar,而這里啟動的StatusBar并不是其真正的StatusBar,而是他的子類,也就是位于com/android/systemui/statusbar/phone/PhoneStatusBar.java,下面我們來看一下他的start()函數(shù):
@Overridepublic void start() {mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();updateDisplaySize();ThemeConfig currentTheme = mContext.getResources().getConfiguration().themeConfig;if (currentTheme != null) {mCurrentTheme = (ThemeConfig)currentTheme.clone();} else {mCurrentTheme = ThemeConfig.getSystemTheme();}mLocationController = new LocationController(mContext);mBatteryController = new BatteryController(mContext);mDockBatteryController = new DockBatteryController(mContext);mBluetoothController = new BluetoothController(mContext);super.start(); // calls createAndAddWindows()addNavigationBar();SettingsObserver observer = new SettingsObserver(mHandler);observer.observe();// Developer options - Force Navigation bartry {boolean needsNav = mWindowManagerService.needsNavigationBar();if (!needsNav) {mDevForceNavbarObserver = new DevForceNavbarObserver(mHandler);mDevForceNavbarObserver.observe();}} catch (RemoteException ex) {// no window manager? good luck with that}// Lastly, call to the icon policy to install/update all the icons.mIconPolicy = new PhoneStatusBarPolicy(mContext);mHeadsUpObserver.onChange(true); // set upif (ENABLE_HEADS_UP) {mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor(Settings.System.HEADS_UP_NOTIFICATION), true,mHeadsUpObserver, mCurrentUserId);}}在這個代碼中,我們看到代碼中,有一個類PhoneStatusBarPolicy類,該類就是向狀態(tài)欄中添加圖標(biāo)的管理類。下面我們來看一下該類的構(gòu)造方法:
public PhoneStatusBarPolicy(Context context) {mContext = context;mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);// listen for broadcastsIntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_ALARM_CHANGED);filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);int numPhones = MSimTelephonyManager.getDefault().getPhoneCount();mSimState = new IccCardConstants.State[numPhones];for (int i=0; i < numPhones; i++) {mSimState[i] = IccCardConstants.State.READY;}// TTY statusmService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0, null);mService.setIconVisibility("tty", false);// Cdma Roaming Indicator, ERImService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0, null);mService.setIconVisibility("cdma_eri", false);// bluetooth statusBluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();int bluetoothIcon = R.drawable.stat_sys_data_bluetooth;if (adapter != null) {mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON);if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) {bluetoothIcon = R.drawable.stat_sys_data_bluetooth_connected;}}mService.setIcon("bluetooth", bluetoothIcon, 0, null);mService.setIconVisibility("bluetooth", mBluetoothEnabled);// Alarm clockmService.setIcon("alarm_clock", R.drawable.stat_sys_alarm, 0, null);mService.setIconVisibility("alarm_clock", false);// Sync statemService.setIcon("sync_active", R.drawable.stat_sys_sync, 0, null);mService.setIconVisibility("sync_active", false);// "sync_failing" is obsolete: b/1297963// volumemService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);mService.setIconVisibility("volume", false);updateVolume();}而這里主要是添加監(jiān)聽廣播,并且添加其他相關(guān)圖標(biāo)。
還有有些圖標(biāo)是在布局文件中添加的,其中于StatusBar相關(guān)的布局文件是在下面幾個文件中的:
- SystemUI/res/layout/status_bar.xml
- SystemUI/res/layout/super_status_bar.xml
以及其內(nèi)部include的相關(guān)文件。
好了,至此,有關(guān)與android系統(tǒng)狀態(tài)欄相關(guān)的代碼已經(jīng)了解的差不多了,通過這個,我們可以向狀態(tài)欄中添加圖標(biāo)或者是刪除圖標(biāo),這個是比較簡單了。
好了,有關(guān)與狀態(tài)欄的代碼我們就分析到此,后面我們再來分析QuickSettings的相關(guān)的代碼。
總結(jié)
以上是生活随笔為你收集整理的android(cm11)状态栏源码分析(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【小技巧】Xcode7.1中KSImag
- 下一篇: 移动开发:android , IOS h