//----------------------------StatusBarManagerService托管CommandQueue--------------------------------
开机后在com.android.server.SystemServer的initAndLoop中
if (!disableSystemUI) {
try {
Slog.i(TAG, "Status Bar");
statusBar = new StatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e);
}
}
在其他地方可以通过
IStatusBarService getStatusBarService() {
synchronized (mServiceAquireLock) {
if (mStatusBarService == null) {
mStatusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService("statusbar"));
}
return mStatusBarService;
}
}
得到com.android.server.StatusBarManagerService对象,StatusBarManagerService托管IStatusBar对象,IStatusBar为CommandQueue通过registerStatusBar传递进来
// ================================================================================
// Callbacks from the status bar service.
// ================================================================================
public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
List notificationKeys, List notifications,
int switches[], List binders) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
mBar = bar;
synchronized (mIcons) {
iconList.copyFrom(mIcons);
}
synchronized (mNotifications) {
for (Map.Entry e: mNotifications.entrySet()) {
notificationKeys.add(e.getKey());
notifications.add(e.getValue());
}
}
synchronized (mLock) {
switches[0] = gatherDisableActionsLocked(mCurrentUserId);
switches[1] = mSystemUiVisibility;
switches[2] = mMenuVisible ? 1 : 0;
switches[3] = mImeWindowVis;
switches[4] = mImeBackDisposition;
binders.add(mImeToken);
}
switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
switches[6] = mWindowManager.isHardKeyboardEnabled() ? 1 : 0;
}
在com.android.systemui.statusbar.BaseStatusBar的start()方法中对这个StatusBarManagerService进行了registerStatusBar,把registerStatusBar传递进去。BaseStatusBar被PhoneStatusBar继承了.
//-------------------------------------SystemUI的各项服务启动-------------------------------------
在Systemserver的ActivityManagerService的systemReady()回调中调用了startSystemUi()方法启动SystemUIService
static final void startSystemUi(Context context) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}
SystemUIService中对如下Service进行了构造,并且启动了start方法
private final Class>[] SERVICES = new Class[] {
com.android.systemui.recent.Recents.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class,
com.android.systemui.settings.SettingsUI.class,
com.android.systemui.sim.SimDetectorUI.class,
com.android.systemui.storage.DataProtect.class,
};
/**
* Hold a reference on the stuff we start.
*/
private final SystemUI[] mServices = new SystemUI[SERVICES.length];
@Override
public void onCreate() {
HashMap, Object> components = new HashMap, Object>();
final int N = SERVICES.length;
for (int i=0; i cl = SERVICES[i];
Log.d(TAG, "loading: " + cl);
try {
mServices[i] = (SystemUI)cl.newInstance();
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
mServices[i].mContext = this;
mServices[i].mComponents = components;
Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
for (SystemUI ui: mServices) {
ui.onConfigurationChanged(newConfig);
}
}
如上PowerUI中的start方法内对电池电量变化以及屏幕亮灭进行了注册监听.
//-----------------------------------------通知栏、状态栏-----------------------------------------------------
SystemBars内构造了PhoneStatusBar并调用start方法。
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());
}
下面看PhoneStatusBar的start方法
@Override
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
updateDisplaySize();
CustomTheme currentTheme = mContext.getResources().getConfiguration().customTheme;
if (currentTheme != null) {
mCurrentTheme = (CustomTheme)currentTheme.clone();
}
super.start(); // calls createAndAddWindows()
addNavigationBar();
SettingsObserver observer = new SettingsObserver(mHandler);
observer.observe();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
}
super.start()中调用了抽象方法createAndAddWindows(),createAndAddWindows()中
@Override
public void createAndAddWindows() {
addStatusBarWindow();
}
private void addStatusBarWindow() {
// Put up the view
final int height = getStatusBarHeight();
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
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,
PixelFormat.TRANSLUCENT);
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
lp.gravity = getStatusBarGravity();
lp.setTitle("StatusBar");
lp.packageName = mContext.getPackageName();
makeStatusBarView();
mStatusBarContainer.addView(mStatusBarWindow);
mWindowManager.addView(mStatusBarContainer, lp);
}
在makeStatusBarView()中开始构建状态栏与通知栏,使用布局文件super_status_bar.xml,status_bar.xml是状态栏的布局,包含了顶上显示的电源、信号、跳动通知等信息或者图标,super_status_bar中include的status_bar_expanded.xml为下拉展开的布局里面包含ribbon_settings.xml为快捷设置栏,super_status_bar.xml中所include的布局文件quick_settings.xml为切换到所有显示的快捷设置栏。
//-------------------------------------------快捷方式按钮流程-----------------------------------------------------
以网格快捷设置栏为例,在makeStatusBarView()方法中
mQS = new QuickSettingsController(mContext, mSettingsContainer, this,
Settings.System.QUICK_SETTINGS_TILES, false);
如上第4个参数是从Settings.System中取条目的key值,第5个参数决定是哪种模式的快捷设置。QuickSettingsController控制了整个设置的加载,其主要方法
protected void setupQuickSettings() {
shutdown();
mReceiver = new QSBroadcastReceiver();
mReceiverMap.clear();
mObserver = new QuickSettingsObserver(mHandler);
mObserverMap.clear();
mTileStatusUris.clear();
loadTiles();
setupBroadcastReceiver();
setupContentObserver();
if (mRibbonMode) {
for (QuickSettingsTile t : mQuickSettingsTiles) {
t.switchToRibbonMode();
}
}
}
loadTiles()加载条目
String tiles = Settings.System.getStringForUser(resolver,
mSettingsKey, UserHandle.USER_CURRENT);
if (tiles == null) {
Log.i(TAG, "Default tiles being loaded");
tiles = TextUtils.join(TILE_DELIMITER, TILES_DEFAULT);
}
初始条目由Setting应用中进行设置,默认是QSConstants的静态对象。
对于每个Tile,在构造后都进行了初始化
for (String tile : tiles.split("\\|")) {
QuickSettingsTile qs = null;
if (tile.equals(TILE_BLUETOOTH)) {
qs = new BluetoothTile(mContext, this, mStatusBarService.mBluetoothController);
} else if (tile.equals(TILE_AUTOROTATE)) {
qs = new AutoRotateTile(mContext, this, mHandler);
} else if (tile.equals(TILE_AIRPLANE)) {
qs = new AirplaneModeTile(mContext, this, mStatusBarService.mNetworkController);
} else if (tile.equals(TILE_GPS)) {
qs = new GPSTile(mContext, this);
} else if (tile.equals(TILE_MOBILEDATA) && mobileDataSupported) {
qs = new MobileNetworkTile(mContext, this, mStatusBarService.mNetworkController);
} else if (tile.equals(TILE_WIFI)) {
qs = new WiFiTile(mContext, this, mStatusBarService.mNetworkController);
} else if (tile.equals(TILE_RINGER)) {
qs = new RingerModeTile(mContext, this);
} else if (tile.equals(TILE_TORCH)) {
qs = new TorchTile(mContext,this);
}
if (qs != null) {
qs.setupQuickSettingsTile(inflater, mContainerView);
mQuickSettingsTiles.add(qs);
}
}
setupBroadcastReceiver()方法为注册监听广播,当收到广播时对所有Tile都调用了onReceive方法进行更新。
如何新增一个Tile?
1、在QSConstants中增加一条对应的String,并且在static方法中add你要增加的。
2、在com.android.systemui.quicksettings内新建一个类继承QuickSettingsTile并实现方法。
3、在QuickSettingsController的loadTiles()方法中for循环内的if判断中增加你要新增的。
4、在Setting App中的QuickSettingsUtil.java中static中register你新增的条目对应的名称以及图标。
主要,由于值是保存在全局数据库内,所以修改后是看不到结果的,如果要看结果,方法一:重新刷版本。方法二:让手机从默认设置中读取值
public static String getCurrentTiles(Context context, boolean isRibbon) {
String tiles = Settings.System.getString(context.getContentResolver(),
isRibbon ? Settings.System.QUICK_SETTINGS_RIBBON_TILES
: Settings.System.QUICK_SETTINGS_TILES);
if (tiles == null) {
tiles = getDefaultTiles(context);
}
return tiles;
}
比如把上面这个方法内的if判断去掉,让手机把默认值改了后再改回来就行了。