该系列文章总纲链接:专题分纲目录 Android SystemUI组件
本章关键点总结 & 说明:
说明:本章节持续迭代之前章节的思维导图,主要关注下方 SystemBars分析部分即可。主要解读了SystemBars的启动流程以及如何调用到 状态栏和导航栏的创建函数。
1 SystemBars start 启动分析
分析SystemBars的start方法,代码实现如下:
public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
//...
private ServiceMonitor mServiceMonitor;
@Override
public void start() {
mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
// will call onNoService if no remote service is found
mServiceMonitor.start();
}
//...
}
这里继续分析关键代码mServiceMonitor.start()的实现,如下所示:
public class ServiceMonitor {
//...
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.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
mHandler.sendEmptyMessage(MSG_START_SERVICE);
}
//...
}
这里最后通过handler发送了消息MSG_START_SERVICE,对于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;
//...
}
}
};
对消息的处理主要是执行startService方法,实现如下:
private void startService() {
mServiceName = getComponentNameFromSetting();
if (mServiceName == null) {
mBound = false;
//这个mCallbacks对象就是之前传入进来的SystemBar类型的
mCallbacks.onNoService();
} else {
long delay = mCallbacks.onServiceStartAttempt();
mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
}
}
对于第一次启动的服务会走上面的分支,SystemBar的onNoService代码实现如下:
@Override
public void onNoService() {
// fallback to using an in-process implementation
createStatusBarFromConfig();
}
继续分析createStatusBarFromConfig的实现,代码如下所示:
private void createStatusBarFromConfig() {
final String clsName = mContext.getString(R.string.config_statusBarComponent);
//...
//通过类加载器实例化类
Class<?> cls = null;
//...
cls = mContext.getClassLoader().loadClass(clsName);
//...
mStatusBar = (BaseStatusBar) cls.newInstance();
//...
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mComponents;
mStatusBar.start();
}
当远程服务没有启动时,首先从xml文件读取要启动的类名,我们来查看这个xml文件 res\values\config.xml,内容如下:
<resources>
...
<!-- Component to be used as the status bar service. Must implement the IStatusBar
interface. This name is in the ComponentName flattened format (package/class) -->
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
...
</resources>
由上可知,这个StatusBar实际上是PhoneStatusBar,从这里开始将进入到PhoneStatusBar的启动流程,在这里我们开始探寻导航栏和状态的创建方法的探寻。
2 导航栏创建方法探寻
实例化PhoneStatusBar类后会调用start方法,我们就从PhoneStatusBar的start方法开始分析,start方法代码实现如下:
@Override
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
updateDisplaySize();
//src绘图模式
mScrimSrcModeEnabled = mContext.getResources().getBoolean(
R.bool.config_status_bar_scrim_behind_use_src);
//调用父类BaseStatusBar的start方法
super.start(); // calls createAndAddWindows()
mMediaSessionManager
= (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
//创建导航栏
addNavigationBar();
//更新状态栏图标
mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController);
mSettingsObserver.onChange(false); // set up
mHeadsUpObserver.onChange(true); // set up
if (ENABLE_HEADS_UP) {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
mHeadsUpObserver);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
mHeadsUpObserver);
}
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
mUnlockMethodCache.addListener(this);
//启动锁屏
startKeyguard();
mDozeServiceHost = new DozeServiceHost();
putComponent(DozeHost.class, mDozeServiceHost);
putComponent(PhoneStatusBar.class, this);
setControllerUsers();
notifyUserAboutHiddenNotifications();
mScreenPinningRequest = new ScreenPinningRequest(mContext);
}
这里我们看到了导航栏创建的关键方法:addNavigationBar(),接下来我们继续探寻 状态栏的创建方法。
3 状态栏创建方法探寻
PhoneStatusBar的start方法中调用了父类(BaseStatusBar类型)的start()方法,代码实现如下:
public void start() {
//状态栏的窗口需要使用WM进行窗口的创建,因为不属于Activity
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
mDisplay = mWindowManager.getDefaultDisplay();
mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
mNotificationData = new NotificationData(this);
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE));
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
//监听设备归属状态的变化,以禁用或启用某些功能
mSettingsObserver.onChange(false); // set up
//监听设置文件的改变,以便更新ContenProvider数据库
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
mSettingsObserver);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
mSettingsObserver);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
mSettingsObserver,
UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
true,
mLockscreenSettingsObserver,
UserHandle.USER_ALL);
//获取statusbarService服务,于SystemUI而言是一个代理,它会将操作状态栏的请求发送给SystemUI,并由后者来完成请求。
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
//设置recents回调函数
mRecents = getComponent(RecentsComponent.class);
mRecents.setCallback(this);
final Configuration currentConfig = mContext.getResources().getConfiguration();
mLocale = currentConfig.locale;
mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
mFontScale = currentConfig.fontScale;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
//动画相关
mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,android.R.interpolator.linear_out_slow_in);
mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,android.R.interpolator.fast_out_linear_in);
// 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>();
//...
//经过一系列对象的创建与初始化后,开始向StatusBarService进行注册。
mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
//...
//关键点:创建 状态栏和导航栏窗口。由于创建状态栏和导航栏 窗口涉及到控件树的创建,因此它由子类PhoneStatusBar或TabletStatusBar实现,以根据不同的布局方案选择创建不同的窗口与控件树。
createAndAddWindows();
/*应用来自IStatusBarService中所获取的信息。mCommandQueue已经注册到IStatusBarService中,状态栏与导航栏的窗口与控件树也都创建完毕。接下来是应用从IStatusBarService中所获取的信息 */
disable(switches[0], false /* animate */);
// 设置SystemUIVisibility
setSystemUiVisibility(switches[1], 0xffffffff);
// 设置菜单键的可见性
topAppWindowChanged(switches[2] != 0);
// 根据输入法窗口的可见性调整导航栏的样式
setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
// 依次向系统状态区添加状态图标
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++;
}
}
// Set up the initial notification state.
//...
mNotificationListener.registerAsSystemService(mContext,
new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),UserHandle.USER_ALL);
//...
mCurrentUserId = ActivityManager.getCurrentUser();
setHeadsUpUser(mCurrentUserId);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(BANNER_ACTION_CANCEL);
filter.addAction(BANNER_ACTION_SETUP);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, filter);
updateCurrentProfilesCache();
}
BaseStatusBar.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中的createAndAddWindows,代码实现如下:
@Override
public void createAndAddWindows() {
addStatusBarWindow();
}
致此,经过前面的分析,我们了解到,通过SystemBars的start启动,最终执行到了两个关键函数:
- addNavigationBar(); //创建导航栏(PhoneStatusbar)
- addStatusBarWindow();//创建状态栏(BaseStatusbar)
下一章节开始,我们从创建流程开始分析 状态栏和导航栏。