天天看點

android(cm11)狀态欄源碼分析(一)

版權聲明:您好,轉載請留下本人部落格的位址,謝謝 https://blog.csdn.net/hongbochen1223/article/details/50216563

(一):寫在前面

最近由于工作需要,需要了解CM11中的有關于StatusBar相關的内容。總的來說,剛開始閱讀其源碼的時候,是有點困難,不過通過建構相關代碼的腦圖和流程圖,幾天下來,我已經對其源碼有了一個大體的了解,不過其内部細節還有很多不是很明白,但是這對于我的工作來說就已經足夠了。

在android系統中,有關于系統狀态欄有關的代碼位于/framework/base/packages/SystemUI/中,很明顯,該SystemUI是一個app源碼,當系統進行編譯的時候,就會生成SystemUI.apk。是以我們對待它就像是對待普通app程式一樣。

好了,現在開始我們的代碼分析。

(二):StatusBar流程分析

對于android系統來說,SystemUI的啟動是有位于packages下面的android系統launcher啟動器啟動的,啟動方式其實是通過java的反射機制實作的。其啟動SystemUI的SystemUIService,該SystemUIService是Service的一個子類,同時,在該類中通過反射機制同時啟動6個和系統UI相關的類,這個我們後面再分析。

這6個和系統UI相關的類都繼承自SystemUI類,在SystemUIService中執行個體化這6個類的時候同時啟動該類對應的start()方法來啟動服務。而他們的start()函數中主要是啟動相關ServiceMonitor的start方法,在該ServiceMonitor中主要是啟動相關的包的服務,即調用startService()函數。在啟動服務的時候,就會執行個體化StatusBar,并且調用其onStart()函數。這個就是StatusBar的啟動流程,這樣說的話可能了解起來比較繁瑣,下面的這張圖就是系統狀态欄的啟動過程的流程圖:

(三):SystemUIService源碼分析

下面我們來分析一下SystemUIService的源碼。

該SystemUIService類繼承自Service類,說明該類是一個服務類,在該類中都是幹了什麼工作呢?我們先找到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循環将數組SERVICES中儲存的類執行個體化,即調用newInstance()函數,執行個體化完成之後,對其對象中的屬性進行指派,最後再調用相應的start()函數。

下面我們來看一下SERVICES數組中的儲存的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,
        };
           

當然,在這個類裡面也存有其他相關的函數,包括配置發生改變的函數,銷毀函數等,下面我們來看一下該類的腦圖:

由于在這裡啟動了6個相關的類,但是我們在這篇文章中,我們先分析SystemBars.class類。

(四):SystemBars源碼分析

在上面的流程圖中,我們知道,啟動的6個類都是繼承自SystemUI類,我們先來看一下SystemUI類:

SystemUI類是一個抽象類,在該類中定義了一些方法,其中包括啟動方法,配置發生改變的函數,銷毀函數等。下面我們先來看一下該類的代碼:

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對象,該對象就是儲存相關類的元件。下面我們來看一下腦圖:

下面我們來看SystemBars的源碼,在這裡我們主要檢視的是其start()函數:

mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
        mServiceMonitor.start();  // will call onNoService if no remote service is found
           

在這裡,主要是初始化ServiceMonitor對象,并且調用其start()函數。

但是對于ServiceMonitor類的對象來說,其start()函數,最終都要調用位于SystemBars類中的createStatusBarFromConfig()函數,在該函數中,主要是調用BaseStatusBar對象的start()函數。

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中的資訊類來進行包服務管理,其中有啟動服務,繼續服務,暫停服務,停止服務等函數,在這裡輾轉反側最終還是回歸到SystemBars中的StatusBars的啟動:

(六):最終流程分析

上面我們提到了,最終還是要啟動StatusBar,而這裡啟動的StatusBar并不是其真正的StatusBar,而是他的子類,也就是位于com/android/systemui/statusbar/phone/PhoneStatusBar.java,下面我們來看一下他的start()函數:

@Override
    public 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 bar
        try {
            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 up
        if (ENABLE_HEADS_UP) {
            mContext.getContentResolver().registerContentObserver(
                    Settings.System.getUriFor(Settings.System.HEADS_UP_NOTIFICATION), true,
                    mHeadsUpObserver, mCurrentUserId);
        }
    }
           

在這個代碼中,我們看到代碼中,有一個類PhoneStatusBarPolicy類,該類就是向狀态欄中添加圖示的管理類。下面我們來看一下該類的構造方法:

public PhoneStatusBarPolicy(Context context) {
        mContext = context;
        mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);

        // listen for broadcasts
        IntentFilter 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 status
        mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0, null);
        mService.setIconVisibility("tty", false);

        // Cdma Roaming Indicator, ERI
        mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0, null);
        mService.setIconVisibility("cdma_eri", false);

        // bluetooth status
        BluetoothAdapter 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 clock
        mService.setIcon("alarm_clock", R.drawable.stat_sys_alarm, 0, null);
        mService.setIconVisibility("alarm_clock", false);

        // Sync state
        mService.setIcon("sync_active", R.drawable.stat_sys_sync, 0, null);
        mService.setIconVisibility("sync_active", false);
        // "sync_failing" is obsolete: b/1297963

        // volume
        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);
        mService.setIconVisibility("volume", false);
        updateVolume();
    }           

而這裡主要是添加監聽廣播,并且添加其他相關圖示。

還有有些圖示是在布局檔案中添加的,其中于StatusBar相關的布局檔案是在下面幾個檔案中的:

  • SystemUI/res/layout/status_bar.xml
  • SystemUI/res/layout/super_status_bar.xml

以及其内部include的相關檔案。

好了,至此,有關與android系統狀态欄相關的代碼已經了解的差不多了,通過這個,我們可以向狀态欄中添加圖示或者是删除圖示,這個是比較簡單了。

好了,有關與狀态欄的代碼我們就分析到此,後面我們再來分析QuickSettings的相關的代碼。

上一篇: GTK+重拾--03
下一篇: 基于塊的OTA

繼續閱讀