android 6.0 SystemUI原始碼分析(4)-StatusBar顯示流程
阿新 • • 發佈:2019-02-09
1.StatusBar啟動
StatusBar繼承於SystemUI,在SystemUIApplication會啟動SysteBar.
mServices[i].start();
SystemBar.java在start函式會例項化ServiceMonitor以及start ServieMonitor。 ServiceMonitor.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 }
這個函式主要做兩件事情: 1)監聽apk的安裝解除安裝,即apk變化事件 2)傳送MSG_START_SERVICE,啟動service ServiceMonitor.javapublic 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); }
當ServiceName為NULL時,會call到callbacks的onNoService函式。 不等於NULL,在下面的Handler訊息也會call到callBacks的onNoService函式。 從SystemBars.java的繼承關係可以看到: public class SystemBars extends SystemUI implements ServiceMonitor.Callbacksprivate 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); } }
最終會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