1. 程式人生 > >android 6.0 SystemUI原始碼分析(4)-StatusBar顯示流程

android 6.0 SystemUI原始碼分析(4)-StatusBar顯示流程

1.StatusBar啟動

StatusBar繼承於SystemUI,在SystemUIApplication會啟動SysteBar.

mServices[i].start();

SystemBar.java
 @Override
    public void start() {
        if (DEBUG) Log.d(TAG, "start");
        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
        mServiceMonitor.start();  // will call onNoService if no remote service is found
    }
在start函式會例項化ServiceMonitor以及start ServieMonitor。 ServiceMonitor.java
  public void start() {
        // listen for setting changes
        ContentResolver cr = mContext.getContentResolver();
        cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
                false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);

        // listen for package/component changes
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");
        mContext.registerReceiver(mBroadcastReceiver, filter);

        mHandler.sendEmptyMessage(MSG_START_SERVICE);
    }
這個函式主要做兩件事情: 1)監聽apk的安裝解除安裝,即apk變化事件 2)傳送MSG_START_SERVICE,啟動service ServiceMonitor.java
 private void startService() {
        mServiceName = getComponentNameFromSetting();
        if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
        if (mServiceName == null) {
            mBound = false;
            mCallbacks.onNoService();
        } else {
            long delay = mCallbacks.onServiceStartAttempt();
            mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
        }
    }
當ServiceName為NULL時,會call到callbacks的onNoService函式。 不等於NULL,在下面的Handler訊息也會call到callBacks的onNoService函式。 從SystemBars.java的繼承關係可以看到: public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks
最終會call到SystemBars.java的onNoService函式 SystemBars.java
 @Override
    public void onNoService() {
        if (DEBUG) Log.d(TAG, "onNoService");
        createStatusBarFromConfig();  // fallback to using an in-process implementation
    }
createStatusBarFromConfig函式實現:
 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());
    }
會call到BaseStatusBar的start函式 BaseStatusBars.java public void start() { ... //各種例項化和初始化 createAndAddWindows(); }

2.StatusBars建立

在BaseStausBars中,createAndAddWindows函式是抽象函式,看來是call到子類的createAndAddWindows函式。 在SysemUI中,繼承BaseStatusBars的類有:PhoneStatusBar和TvStatusBar,其中TvStatusBar是空實現,因此主要看PhoneStatusBar PhoneStatusBar.java
@Override
    public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        makeStatusBarView();
        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
    }
1)makeStatusBarView函式程式碼很長,因為PhoneStatusBarView除了狀態列那一條之外,還包含Notification Panel,Heads up Panel以及包含drag行為。 主要還是例項化PhoneStatusBarView中各種UI控制元件。 2)StatusBarWindowManager類的add函式負責為PhoneStatusBarView新建Window,包括window大小,位置,是否透明等屬性。 這裡先分析一下makeStatusBarView函式,程式碼太長,不全部貼上。
(1)獲取系統顯示引數 updateDisplaySize();
    // called by makeStatusbar and also by PhoneStatusBarView
    void updateDisplaySize() {
        mDisplay.getMetrics(mDisplayMetrics);
        mDisplay.getSize(mCurrentDisplaySize);
        if (DEBUG_GESTURES) {
            mGestureRec.tag("display",
                    String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
        }
    }
獲取系統解析度,螢幕密度,便於根據不同的顯示引數計算響應的值進行顯示。 (2)更新Panels資源資料 StatusBar這個圖層包含很多的Panel,在建立PhoneStatusBarView時需要更新Panels資料。 updateResources();
    /**
     * Reload some of our resources when the configuration changes.
     *
     * We don't reload everything when the configuration changes -- we probably
     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
     * meantime, just update the things that we know change.
     */
    void updateResources() {
        // Update the quick setting tiles
        if (mQSPanel != null) {
            mQSPanel.updateResources();
        }

        loadDimens();

        if (mNotificationPanel != null) {
            mNotificationPanel.updateResources();
        }
        if (mBrightnessMirrorController != null) {
            mBrightnessMirrorController.updateResources();
        }
    }
QSPanel是快捷設定panel,一些主要應用,可以通過點選QSPanel的Button去進入apk,android和iphone都有這樣的設計。 NotificationPanel是通知訊息顯示的Panel,在有訊息(系統或apk傳送Notification),會在Panel裡面顯示,使用者可以刪除,或點選訊息進入apk。 BrightnessMirrorController是控制亮度的Panel
(3)註冊系統的事件廣播  // receive broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
(4)Panels & Views例項化以及事件註冊

3.StatusBar顯示

顯示主要是call StatusBarWindowManager類的add函式。 StatusBarWindowManager.java
 /**
     * Adds the status bar view to the window manager.
     *
     * @param statusBarView The view to add.
     * @param barHeight The height of the status bar in collapsed state.
     */
    public void add(View statusBarView, int barHeight) {

        // Now that the status bar window encompasses the sliding panel and its
        // translucent backdrop, the entire thing is made TRANSLUCENT and is
        // hardware-accelerated.
        mLp = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                barHeight,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                PixelFormat.TRANSLUCENT);
        mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        mLp.gravity = Gravity.TOP;
        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
        mLp.setTitle("StatusBar");
        mLp.packageName = mContext.getPackageName();
        mStatusBarView = statusBarView;
        mBarHeight = barHeight;
        mWindowManager.addView(mStatusBarView, mLp);
        mLpChanged = new WindowManager.LayoutParams();
        mLpChanged.copyFrom(mLp);
    }
barHeight表示狀態列的寬度,在dimen裡面可以配置:  public int getStatusBarHeight() {
        if (mNaturalBarHeight < 0) {
            final Resources res = mContext.getResources();
            mNaturalBarHeight =
                    res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
        }
        return mNaturalBarHeight;
    }
若不想顯示,可以設定為0