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