1. 程式人生 > >SystemUI原始碼分析三(StatusBar的載入流程)

SystemUI原始碼分析三(StatusBar的載入流程)

SystemServer中呼叫startsystemui函式啟動SystemUIService,在SystemUIService的onCreate()函式中執行一下這個語句

((SystemUIApplication) getApplication()).startServicesIfNeeded();

SystemBar繼承SystemUI,因此被啟動了。

那接下來就進入SystemBar這個類中看onStart()函式

public void start(){
    if(DEBUG)Log.d(TAG,"start");
    //建立監聽器物件
    mServiceMonitor = new
ServiceMonitor(TAG,DEBUG,mContext,Settings.Secure.BAR_SERVICE_COMPONENT,this); //開始監聽 mServiceMonitor.start(); }

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); //傳送訊息給主執行緒,啟動Service mHandler.sendEmptyMessage(MSG_START_SERVICE); } /*處理接收到的訊息*/ private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch(msg.what) { case MSG_START_SERVICE: startService(); break; case MSG_CONTINUE_START_SERVICE: continueStartService(); break; case MSG_STOP_SERVICE: stopService(); break; case MSG_PACKAGE_INTENT: packageIntent((Intent)msg.obj); break; case MSG_CHECK_BOUND: checkBound(); break; case MSG_SERVICE_DISCONNECTED: serviceDisconnected((ComponentName)msg.obj); break; } } }; 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); } }

先獲取Service的componentName,如果為null則回撥onNoService方法。如果不為null,則通過mHandler傳送訊息給主執行緒。

private void continueStartService() {
    if (mDebug) Log.d(mTag, "continueStartService");
    Intent intent = new Intent().setComponent(mServiceName);
    try {
        mServiceConnection = new SC();
        mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        if (mDebug) Log.d(mTag, "mBound: " + mBound);
    } catch (Throwable t) {
        Log.w(mTag, "Error binding to service: " + mServiceName, t);
    }
    if (!mBound) {
        mCallbacks.onNoService();
    }
}

獲取的componentName不管是不是空,最終都會回撥onNoService()。

public void onNoService() {
    if (DEBUG) Log.d(TAG, "onNoService");
    createStatusBarFromConfig();  // fallback to using an in-process implementation
}

private void createStatusBarFromConfig() {
    if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
    //取出className
    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 {
        //動態載入class檔案
        cls = mContext.getClassLoader().loadClass(clsName);
    } catch (Throwable t) {
        throw andLog("Error loading status bar component: " + clsName, t);
    }
    try {
        //建立BaseStatusBar例項
        mStatusBar = (BaseStatusBar) cls.newInstance();
    } catch (Throwable t) {
        throw andLog("Error creating status bar component: " + clsName, t);
    }
    mStatusBar.mContext = mContext;
    mStatusBar.mComponents = mComponents;
    //啟動BaseStatusBar
    mStatusBar.start();
    if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}

frameworks\base\packages\SystemUI\res\values\config.xml
R.string.config_statusBarComponent的值是:

<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>

PhoneStatusBar繼承自BaseStatusBar

啟動BaseStatusBar,那就接著來看BaseStatusBar.java,這個類繼承自SystemUI

public void start(){
    createAndAddWindows();
}

/**
 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
 * and add them to the window manager.
 */
protected abstract void createAndAddWindows();

是個抽象函式,PhoneStatusBar繼承自BaseStatusBar,那我們來看下PhoneStatusBar

 public void start() {
    ……
    super.start(); // calls createAndAddWindows()
}

果然是PhoneStatusBar啟動時呼叫了父類(BaseStatusBar)的createAndAddWindows(),這裡PhoneStatusBar實現了父類的抽象方法。主要是新增狀態列、新增導航欄、更新圖示

一、新增狀態列

@Override
public void createAndAddWindows() {
    addStatusBarWindow();
}

private void addStatusBawWindow(){
    makeStatusBarView();
    mStatusBarWindowManager = new StatusBarWindowManager(mContext);
    mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}

這個函式做了兩件事

(1)建立PhoneStatusBarView並初始化PhoneStatusBarView中的控制元件。

(2)建立StatusBarWindowManager物件,呼叫它的add()函式為PhoneStatusBarView建立視窗,包括視窗的大小、位置、是否透明等屬性。

先來分析makeStatusBarView()函式。

protected PhoneStatusBarView makeStatusBarView() {
    final Context context = mContext;

    Resources res = context.getResources();

    //獲取螢幕引數
    updateDisplaySize(); // populates mDisplayMetrics
    //更新Panels資源資料,statusbar包含很多panel,在建立PhoneStatusBarView時需要更新panel資料
    updateResources();

    //引入StatusBarWindowView佈局
    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
            R.layout.super_status_bar, null);
    //statusbarwindow
    mStatusBarWindow.setService(this);
    //設定觸控事件監聽器
    mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            checkUserAutohide(v, event);
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                if (mExpandedVisible) {
                    animateCollapsePanels();
                }
            }
            return mStatusBarWindow.onTouchEvent(event);
        }
    });

    //初始化statusbarview
    mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
    mStatusBarView.setBar(this);

    //初始化panelholder
    PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
    mStatusBarView.setPanelHolder(holder);

    //初始化通知panel
    mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
            R.id.notification_panel);
    mNotificationPanel.setStatusBar(this);


    if (!mHighEnd) {
        mStatusBarWindow.setBackground(null);
        //設定notificationpanel背景
        mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
                R.color.notification_panel_solid_background)));
    }

    //通知樣式
    mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
    mHeadsUpManager.setBar(this);
    mHeadsUpManager.addListener(this);
    mHeadsUpManager.addListener(mNotificationPanel);
    mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
    mNotificationData.setHeadsUpManager(mHeadsUpManager);

    if (MULTIUSER_DEBUG) {
        mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
                R.id.header_debug_info);
        mNotificationPanelDebugText.setVisibility(View.VISIBLE);
    }

    try {
        boolean showNav = mWindowManagerService.hasNavigationBar();
        //檢查是否顯示導航欄
        if (showNav) {
            //引入導航欄navigationbarview的佈局
            mNavigationBarView =
                (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);

            mNavigationBarView.setDisabledFlags(mDisabled1);
            mNavigationBarView.setBar(this);
            mNavigationBarView.setOnVerticalChangedListener(
                    new NavigationBarView.OnVerticalChangedListener() {
                @Override
                public void onVerticalChanged(boolean isVertical) {
                    if (mAssistManager != null) {
                        mAssistManager.onConfigurationChanged();
                    }
                    mNotificationPanel.setQsScrimEnabled(!isVertical);
                }
            });、
            //設定導航欄的觸控監聽事件
            mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    checkUserAutohide(v, event);
                    return false;
                }});
        }
    } catch (RemoteException ex) {
        // no window manager? good luck with that
    }

    mAssistManager = new AssistManager(this, context);

    // figure out which pixel-format to use for the status bar.
    //狀態列使用的畫素格式
    mPixelFormat = PixelFormat.OPAQUE;

    //status_bar_expanded.xml佈局的控制元件
    mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
            R.id.notification_stack_scroller);
    mStackScroller.setLongPressListener(getNotificationLongClicker());
    mStackScroller.setPhoneStatusBar(this);
    mStackScroller.setGroupManager(mGroupManager);
    mStackScroller.setHeadsUpManager(mHeadsUpManager);
    mGroupManager.setOnGroupChangeListener(mStackScroller);

    //引入NotificationOverflowContainer的佈局
    mKeyguardIconOverflowContainer =
            (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
                    R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
    mKeyguardIconOverflowContainer.setOnActivatedListener(this);
    mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
    mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);

    //引入SpeedBump的佈局
    SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
                    R.layout.status_bar_notification_speed_bump, mStackScroller, false);
    mStackScroller.setSpeedBumpView(speedBump);

    //引入EmptyShadeView的佈局
    mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
            R.layout.status_bar_no_notifications, mStackScroller, false);
    mStackScroller.setEmptyShadeView(mEmptyShadeView);

    //引入DismissView的佈局
    mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
            R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
    mDismissView.setOnButtonClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
            clearAllNotifications();
        }
    });
    mStackScroller.setDismissView(mDismissView);
    mExpandedContents = mStackScroller;

    //初始化控制元件
    mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
    mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
    mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);

    ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
    ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
    View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
    mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
            mScrimSrcModeEnabled);


    mHeadsUpManager.addListener(mScrimController);
    mStackScroller.setScrimController(mScrimController);
    mScrimController.setBackDropView(mBackdrop);
    mStatusBarView.setScrimController(mScrimController);
    mDozeScrimController = new DozeScrimController(mScrimController, context);

    mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
    mHeader.setActivityStarter(this);
    mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
    mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
    mKeyguardBottomArea =
            (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
    mKeyguardBottomArea.setActivityStarter(this);
    mKeyguardBottomArea.setAssistManager(mAssistManager);
    mKeyguardIndicationController = new KeyguardIndicationController(mContext,
            (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                    R.id.keyguard_indication_text));
    mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);

    // set the inital view visibility
    setAreThereNotifications();

    //建立IconController物件
    mIconController = new StatusBarIconController(
            mContext, mStatusBarView, mKeyguardStatusBar, this);

    // Background thread for any controllers that need it.
    //建立執行緒並啟動執行緒
    mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
    mHandlerThread.start();

    // Other icons
    //位置控制器
    mLocationController = new LocationControllerImpl(mContext,
            mHandlerThread.getLooper()); // will post a notification

    //電池控制器
    mBatteryController = new BatteryController(mContext);
    mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
        @Override
        public void onPowerSaveChanged() {
            mHandler.post(mCheckBarModes);
            if (mDozeServiceHost != null) {
                mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
            }
        }
        @Override
        public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
            // noop
        }
    });

    //網路控制器
    mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
    //熱點控制器
    mHotspotController = new HotspotControllerImpl(mContext);
    //藍芽控制器
    mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());

    mBluetoothController.setbar(this);

    mHotspotController.setbar(this);
    //安全控制器
    mSecurityController = new SecurityControllerImpl(mContext);
    if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
        //旋轉鎖控制?
        mRotationLockController = new RotationLockControllerImpl(mContext);
    }
    //使用者資訊控制器
    mUserInfoController = new UserInfoController(mContext);
    mVolumeComponent = getComponent(VolumeComponent.class);
    if (mVolumeComponent != null) {
        //
        mZenModeController = mVolumeComponent.getZenController();
    }
    //投射控制器
    mCastController = new CastControllerImpl(mContext);
    final SignalClusterView signalCluster =
            (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
    final SignalClusterView signalClusterKeyguard =
            (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
    final SignalClusterView signalClusterQs =
            (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
    mNetworkController.addSignalCallback(signalCluster);
    mNetworkController.addSignalCallback(signalClusterKeyguard);
    mNetworkController.addSignalCallback(signalClusterQs);
    signalCluster.setSecurityController(mSecurityController);
    signalCluster.setNetworkController(mNetworkController);
    signalClusterKeyguard.setSecurityController(mSecurityController);
    signalClusterKeyguard.setNetworkController(mNetworkController);
    signalClusterQs.setSecurityController(mSecurityController);
    signalClusterQs.setNetworkController(mNetworkController);
    final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
    if (isAPhone) {
        mNetworkController.addEmergencyListener(mHeader);
    }


    mCarrierLabel = (LinearLayout) mStatusBarWindow.findViewById(R.id.carrier_label_group_ex);
    //手電筒控制器
    mFlashlightController = new FlashlightController(mContext);
    mKeyguardBottomArea.setFlashlightController(mFlashlightController);
    mKeyguardBottomArea.setPhoneStatusBar(this);
    mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
    mAccessibilityController = new AccessibilityController(mContext);
    mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
    mNextAlarmController = new NextAlarmController(mContext);
    //建立鎖屏監聽器
    mKeyguardMonitor = new KeyguardMonitor(mContext);
    if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
        mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
                mHandler);
    }
    mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
            (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
            mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);


    // Set up the quick settings tile panel
    mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
    if (mQSPanel != null) {
        final QSTileHost qsh = new QSTileHost(mContext, this,
                mBluetoothController, mLocationController, mRotationLockController,
                mNetworkController, mZenModeController, mHotspotController,
                mCastController, mFlashlightController,
                mUserSwitcherController, mKeyguardMonitor,
                mSecurityController);
        mQSPanel.setHost(qsh);
        mQSPanel.setTiles(qsh.getTiles());
        mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
        mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
        mHeader.setQSPanel(mQSPanel);
        qsh.setCallback(new QSTileHost.Callback() {
            @Override
            public void onTilesChanged() {
                mQSPanel.setTiles(qsh.getTiles());
            }
        });
    }

    // User info. Trigger first load.
    mHeader.setUserInfoController(mUserInfoController);
    mKeyguardStatusBar.setUserInfoController(mUserInfoController);
    mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
    mUserInfoController.reloadUserInfo();

    mHeader.setBatteryController(mBatteryController);
    ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
            mBatteryController);
    mKeyguardStatusBar.setBatteryController(mBatteryController);
    mHeader.setNextAlarmController(mNextAlarmController);

    PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    mBroadcastReceiver.onReceive(mContext,
            new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));


    // receive broadcasts
    //註冊廣播接收者,接收關閉系統對話方塊、screen on/off訊息
    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);

    IntentFilter demoFilter = new IntentFilter();
    if (DEBUG_MEDIA_FAKE_ARTWORK) {
        demoFilter.addAction(ACTION_FAKE_ARTWORK);
    }
    demoFilter.addAction(ACTION_DEMO);
    context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
            android.Manifest.permission.DUMP, null);

    // listen for USER_SETUP_COMPLETE setting (per-user)
    resetUserSetupObserver();

    // disable profiling bars, since they overlap and clutter the output on app windows
    ThreadedRenderer.overrideProperty("disableProfileBars", "true");

    // Private API call to make the shadows look better for Recents
    ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));

    return mStatusBarView;
}

插入分析載入的佈局super_status_bar.xml

mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
        R.layout.super_status_bar, null);

1、include layout = “@layout/status_bar”

status_bar.xml

這裡寫圖片描述

notification包括Usb、T卡等通知項

這裡寫圖片描述

system_icons.xml包括wifi、SIM卡、電池、時間等

這裡寫圖片描述

2、include layout=”@layout/quick_settings_brightness_dialog”亮度調節對話方塊

3、panelholder:include layout=”@layout/status_bar_expanded”

這裡寫圖片描述

NotificationPanelView

3.1、include layout=”@layout/keyguard_status_view” gone

鎖屏時顯示的是時間和日期部分以及owner_info

這裡寫圖片描述

3.2、NotificationsQuickSettingsContainer

3.2.1、include layout=”@layout/qs_panel”

這裡寫圖片描述

3.2.2、include layout=”@layout/keyguard_user_switcher”

3.2.3、include layout=”@layout/keyguard_status_bar” invisible

顯示的是鎖屏時多使用者MultiUserSwitch、system_icons battery_level、(CarrierText、CarriersTextLayout gone)

這裡寫圖片描述

3.3、include layout=”@layout/keyguard_bottom_area” gone

這裡寫圖片描述

3.4、include layout=”@layout/status_bar_expanded_header”

這裡寫圖片描述

佈局就分析到這裡吧,大概瞭解了各個模組對應的佈局檔案。

二、新增導航欄

// For small-screen devices (read: phones) that lack hardware navigation buttons
private void addNavigationBar() {
    if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
    if (mNavigationBarView == null) return;

    prepareNavigationBarView();

    mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}

1、判斷mNavigationBarView為空就不返回不再繼續執行。

2、導航欄佈局分析及載入;

private void prepareNavigationBarView() {
    mNavigationBarView.reorient();

    mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
    mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
    mNavigationBarView.getRecentsButton().setLongClickable(true);
    mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
    mNavigationBarView.getBackButton().setLongClickable(true);
    mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
    mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
    mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
    mAssistManager.onConfigurationChanged();
}
public void reorient() {
    //獲取螢幕方向(橫向、豎向)
    final int rot = mDisplay.getRotation();
    //隱藏導航欄佈局
    for (int i=0; i<4; i++) {
        mRotatedViews[i].setVisibility(View.GONE);
    }
    //根據螢幕方向顯示導航欄佈局
    mCurrentView = mRotatedViews[rot];
    mCurrentView.setVisibility(View.VISIBLE);
    setLayoutTransitionsEnabled(mLayoutTransitionsEnabled);

    getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);

    mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);

    // force the low profile & disabled states into compliance
    mBarTransitions.init();
    setDisabledFlags(mDisabledFlags, true /* force */);
    setMenuVisibility(mShowMenu, true /* force */);

    if (DEBUG) {
        Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
    }

    updateTaskSwitchHelper();

    setNavigationIconHints(mNavigationIconHints, true);
}

設定最近應用、後退鍵、Home鍵監聽事件。RotatedViews代表的是不同方向的導航欄佈局,有4種

View[] mRotatedViews = new View[4];
/*佈局載入完成後會呼叫這個方法*/
@Override
public void onFinishInflate() {
    mRotatedViews[Surface.ROTATION_0] =
    mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);

    mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);

    mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];

    mCurrentView = mRotatedViews[Surface.ROTATION_0];

    getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);

    updateRTLOrder();
}

3、把導航欄新增到視窗。LayoutParames決定了導航欄在窗體的大小(受父佈局影響)和顯示的位置效果。

三、最終呼叫PhoneStatusBarPolicy這個類來安裝或更新icon,那icon的初始化是什麼時候完成的呢,我們在上面分析PhoneStatusBar的構造方法中有提到呼叫了它的父類BaseStatusBar的start()方法,那麼我們再來看一次BaseStatusBar的start()方法中與icon相關的程式碼。

public void start(){
    ……
    // Connect in to the status bar manager service
    StatusBarIconList iconList = new StatusBarIconList();
    mCommandQueue = new CommandQueue(this, iconList);

    int[] switches = new int[8];
    ArrayList<IBinder> binders = new ArrayList<IBinder>();
    try {
        mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
    } catch (RemoteException ex) {
        // If the system process isn't there we're doomed anyway.
    }
    ……
    // Set up the initial icon state
    int N = iconList.size();
    int viewIndex = 0;
    for (int i=0; i<N; i++) {
        StatusBarIcon icon = iconList.getIcon(i);
        if (icon != null) {
            addIcon(iconList.getSlot(i), i, viewIndex, icon);
            viewIndex++;
        }
    }
}

BaseStatusBar實現了CommandQueue.Callbacks介面,CommandQueue繼承自IStatusBar.Stub,是一個IBinder物件。PhoneStatusBar實現了BaseStatusBar這個抽象類並真正實現了CommandQueue.Callbacks介面定義的方法。mBarService是StatusBarService的物件,通過registerStatusBar函式將CommandQueue註冊到了StatusBarManagerSerivice中

@Override
public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
        int switches[], List<IBinder> binders) {
    enforceStatusBarService();

    Slog.i(TAG, "registerStatusBar bar=" + bar);
    mBar = bar;
    synchronized (mIcons) {
        //把icon拷貝到傳入的引數iconList中
        iconList.copyFrom(mIcons);
    }
    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);
        binders.add(mImeToken);
    }
}

把StatusBarManager中的mIcons複製到傳入的引數iconList中之後,在BaseStatusBar中就可以初始化icon state了

// Set up the initial icon state
int N = iconList.size();
int viewIndex = 0;
for (int i=0; i<N; i++) {
    StatusBarIcon icon = iconList.getIcon(i);
    if (icon != null) {
        addIcon(iconList.getSlot(i), i, viewIndex, icon);
        viewIndex++;
    }
}

回撥PhoneStatusBar的addIcon()函式,載入圖示的佈局

public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
    mIconController.addSystemIcon(slot, index, viewIndex, icon);
}

StatusBarIconController.java

public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
    boolean blocked = mIconBlacklist.contains(slot);
    StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked);
    view.set(icon);
    mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
    view = new StatusBarIconView(mContext, slot, null, blocked);
    view.set(icon);
    mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
    applyIconTint();
}

mStatusBarIcons的初始化是在StatusBarIconController的構造方法中初始化的

public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
        PhoneStatusBar phoneStatusBar) {
    mContext = context;
    mPhoneStatusBar = phoneStatusBar;
    mNotificationColorUtil = NotificationColorUtil.getInstance(context);
    mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area);
    mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
    mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
    mNotificationIconArea = statusBar.findViewById(R.id.notification_icon_area_inner);
    mNotificationIcons = (IconMerger) statusBar.findViewById(R.id.notificationIcons);
    mMoreIcon = (ImageView) statusBar.findViewById(R.id.moreIcon);
    mNotificationIcons.setOverflowIndicator(mMoreIcon);
    mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons);
    mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery);
    mClock = (TextView) statusBar.findViewById(R.id.clock);
    mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
            android.R.interpolator.linear_out_slow_in);
    mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
            android.R.interpolator.fast_out_slow_in);
    mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
    mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
    mHandler = new Handler();
    updateResources();

    TunerService.get(mContext).addTunable(this, ICON_BLACKLIST);
}

而StatusBarIconController的初始化是在PhoneStatusBar這個類的makeStatusBarView中初始化的

protected PhoneStatusBarView makeStatusBarView() {
    ……
    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);
    mIconController = new StatusBarIconController(
                mContext, mStatusBarView, mKeyguardStatusBar, this);
    ……
}

那麼上面提到的mStatusIcons控制元件就是從R.layout.super_status_bar.xml中取出來的。這就是icon佈局的載入過程了。

現在繼續分析PhoneStatusBar.java中的 mIconPolicy = new
PhoneStatusBarPolicy(mContext, mCastController, mHotspotController)。

PhoneStatusBarPolicy.java

public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot,
        UserInfoController userInfoController, BluetoothController bluetooth) {
    mContext = context;
    mCast = cast;
    mHotspot = hotspot;
    mBluetooth = bluetooth;
    mBluetooth.addStateChangedCallback(this);
    mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
    mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    mUserInfoController = userInfoController;

    // listen for broadcasts
    IntentFilter filter = new IntentFilter();
    filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
    filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
    filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
    filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
    filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
    // add headset icon in statusbar
    filter.addAction(Intent.ACTION_HEADSET_PLUG);
    mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);

    // listen for user / profile change.
    try {
        ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener);
    } catch (RemoteException e) {
        // Ignore
    }

    // TTY status
    mService.setIcon(SLOT_TTY,  R.drawable.stat_sys_tty_mode, 0, null);
    mService.setIconVisibility(SLOT_TTY, false)