So,继上篇我们大致看到了图标的记载的xml布局,不过有人会问,这有个吊用啊? 是的,我也问过我自己,不过还真有点吊用,因为这帮我解决问题了
假象我们要分析锁屏界面的battery_level为什么会在充电的时候才显示,我们现在在布局中找到了对应的ID,那么不就很轻易找到上下文 。
OK,今天我们看下Status Bar的图标是如何加载到布局中的,当然会更加详细。
还是那句话,我们往往是站在巨人的JJ上的,我参考了一篇博客Android 4.0 ICS SystemUI浅析——StatusBar加载流程分析
SystemServer.java -> main() - > run()
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); } }
我们看到我们获取了StatusBarManagerService,然后把它加入到了ServiceManager中,其中以Context.STATUS_BAR_SERVIER为标志,
为方便了后面的获取
现在看看StatusBarManagerService是什么叼玩意
StatusBarManagerService.java
StatusBarManagerService.java public StatusBarManagerService(Context context, WindowManagerService windowManager) { mContext = context; mWindowManager = windowManager; final Resources res = context.getResources(); //private StatusBarIconList mIcons = new StatusBarIconList(); //这里把com.android.internal.R.array.config_statusBarIcons 序列化存储 mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons)); LocalServices.addService(StatusBarManagerInternal.class, mInternalService); /// M: DM Lock Feature. registerDMLock(); }
mIcons = new StatusBarIconList(); 这个StatusBarIconList 实现 Parcelable 接口 ,也就是序列化数据 ,用于序列化存储和传递数据
和Java中的Serializable的某些情况下要高效,推荐一篇博客Android中Parcelable接口用法
这里我就不贴出StatusBarIconList的外码了,总之就是存储和读取数据,知道Java序列化的应该就明白。
现在看下com.android.internal.R.array.config_statusBarIcons
<string-array name="config_statusBarIcons"> <item><xliff:g id="id">ime</xliff:g></item> <item><xliff:g id="id">sync_failing</xliff:g></item> <item><xliff:g id="id">sync_active</xliff:g></item> <item><xliff:g id="id">cast</xliff:g></item> <item><xliff:g id="id">hotspot</xliff:g></item> <item><xliff:g id="id">location</xliff:g></item> <item><xliff:g id="id">bluetooth</xliff:g></item> <item><xliff:g id="id">nfc</xliff:g></item> <!-- M: Support "SystemUI Headset icon" feature. --> <item><xliff:g id="id">headset</xliff:g></item> <item><xliff:g id="id">tty</xliff:g></item> <item><xliff:g id="id">speakerphone</xliff:g></item> <item><xliff:g id="id">zen</xliff:g></item> <item><xliff:g id="id">mute</xliff:g></item> <item><xliff:g id="id">volume</xliff:g></item> <item><xliff:g id="id">wifi</xliff:g></item> <item><xliff:g id="id">cdma_eri</xliff:g></item> <item><xliff:g id="id">data_connection</xliff:g></item> <item><xliff:g id="id">phone_evdo_signal</xliff:g></item> <item><xliff:g id="id">phone_signal</xliff:g></item> <item><xliff:g id="id">battery</xliff:g></item> <item><xliff:g id="id">alarm_clock</xliff:g></item> <item><xliff:g id="id">secure</xliff:g></item> <item><xliff:g id="id">clock</xliff:g></item> </string-array>
在上篇文章中,加载status bar的入口就是PhoneStatusBar.java
PhoneStatusBar.java
@Override public void start() { //... super.start(); // calls createAndAddWindows() //... addNavigationBar(); // Lastly, call to the icon policy to install/update all the icons. //注释上看,最终调用这个PhoneStatusBarPolicy.java来安装或者更新Icon mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController); }
public void start() { //... mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); //.. // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); //传入了this,也就是说这个类或者子类实现了接口 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++; } } }
public interface Callbacks { public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon); public void updateIcon(String slot, int index, int viewIndex, StatusBarIcon old, StatusBarIcon icon); public void removeIcon(String slot, int index, int viewIndex); public void disable(int state, boolean animate); public void animateExpandNotificationsPanel(); public void animateCollapsePanels(int flags); public void animateExpandSettingsPanel(); public void setSystemUiVisibility(int vis, int mask); public void topAppWindowChanged(boolean visible); public void setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher); public void showRecentApps(boolean triggeredFromAltTab); public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); public void toggleRecentApps(); public void preloadRecentApps(); public void cancelPreloadRecentApps(); public void showSearchPanel(); public void hideSearchPanel(); public void setWindowState(int window, int state); public void buzzBeepBlinked(); public void notificationLightOff(); public void notificationLightPulse(int argb, int onMillis, int offMillis); public void showScreenPinningRequest(); /// M: [SystemUI] Support "SIM indicator". @{ public void showSimIndicator(String businessType); public void hideSimIndicator(); /// @} /// M: [SystemUI] Support Smartbook Feature. @{ public void dispatchStatusBarKeyEvent(KeyEvent event); /// @} ///M:BMW public void showRestoreButton(boolean flag); } public CommandQueue(Callbacks callbacks, StatusBarIconList list) { mCallbacks = callbacks; mList = list; }
mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders); 这个mBarService就是StatusBarManagerService对象
StatusBarManagerService.java
@Override public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList, int switches[], List<IBinder> binders) { enforceStatusBarService(); Slog.i(TAG, "registerStatusBar bar=" + bar); mBar = bar; synchronized (mIcons) { //把mIcons的index和icon拷贝到iconList中 iconList.copyFrom(mIcons); } synchronized (mLock) { switches[0] = gatherDisableActionsLocked(mCurrentUserId); switches[1] = mSystemUiVisibility; switches[2] = mMenuVisible ? 1 : 0; switches[3] = mImeWindowVis; switches[4] = mImeBackDisposition; switches[5] = mShowImeSwitcher ? 1 : 0; binders.add(mImeToken); } }
// 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++; } }看注释这里只是对初始化Icon state,为什么这样说呢,因为我们还是没有设置icon, 我们只设置了图标的名字,但是我们还没有设置对应的图片,所以这里你只要明白是初始化的加载就行了,
public class PhoneStatusBarPolicy { private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Xlog.d(TAG, "onReceive:" + action); if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) { updateAlarm(); } else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) { updateSyncState(intent); } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) || action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { updateBluetooth(); } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) { updateVolumeZen(); } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { updateSimState(intent); } else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) { int currentTtyMode = intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE, TelecomManager.TTY_MODE_OFF); updateTTY(currentTtyMode); } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { updateAlarm(); /// M: [Multi-User] register Alarm intent by user @{ int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); registerAlarmClockChanged(newUserId, true); /// M: [Multi-User] register Alarm intent by user @} } /// M: [SystemUI] Support "Headset icon". @{ else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { updateHeadSet(intent); } /// @} } }; public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot) { mContext = context; mCast = cast; mHotspot = hotspot; mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); // listen for broadcasts IntentFilter filter = new IntentFilter(); //filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); filter.addAction(Intent.ACTION_USER_SWITCHED); /// M: [SystemUI] Support "Headset icon". @{ filter.addAction(Intent.ACTION_HEADSET_PLUG); /// @} mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); /// M: [Multi-User] register Alarm intent by user registerAlarmClockChanged(UserHandle.USER_OWNER, false); // TTY status mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0, null); mService.setIconVisibility(SLOT_TTY, false); /// M: [ALPS01870707] Get the TTY status when power on @{ int settingsTtyMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.TTY_MODE_ENABLED, TelecomManager.TTY_MODE_OFF); updateTTY(settingsTtyMode); /// M: [ALPS01870707] Get the TTY status when power on @} // Cdma Roaming Indicator, ERI mService.setIcon(SLOT_CDMA_ERI, R.drawable.stat_sys_roaming_cdma_0, 0, null); mService.setIconVisibility(SLOT_CDMA_ERI, false); // bluetooth status updateBluetooth(); // Alarm clock mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null); mService.setIconVisibility(SLOT_ALARM_CLOCK, false); // Sync state mService.setIcon(SLOT_SYNC_ACTIVE, R.drawable.stat_sys_sync, 0, null); mService.setIconVisibility(SLOT_SYNC_ACTIVE, false); // "sync_failing" is obsolete: b/1297963 // zen mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null); mService.setIconVisibility(SLOT_ZEN, false); // volume mService.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, 0, null); mService.setIconVisibility(SLOT_VOLUME, false); updateVolumeZen(); // cast // M: Remove CastTile when WFD is not support in quicksetting if (mCast != null) { mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null); mService.setIconVisibility(SLOT_CAST, false); mCast.addCallback(mCastCallback); } // hotspot mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null); mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); mHotspot.addCallback(mHotspotCallback); /// M: [SystemUI] Support "Headset icon". @{ mService.setIcon(SLOT_HEADSET, R.drawable.stat_sys_headset_with_mic, 0, null); mService.setIconVisibility(SLOT_HEADSET, false); /// @} } }
public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) { try { final IStatusBarService svc = getService(); if (svc != null) { svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel, contentDescription); } } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); } } private synchronized IStatusBarService getService() { if (mService == null) { mService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); if (mService == null) { Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE"); } } return mService; }
@Override public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription) { enforceStatusBar(); synchronized (mIcons) { int index = mIcons.getSlotIndex(slot); if (index < 0) { throw new SecurityException("invalid status bar icon slot: " + slot); } StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.OWNER, iconId, iconLevel, 0, contentDescription); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); mIcons.setIcon(index, icon); if (mBar != null) { try { //加载到布局中 mBar.setIcon(index, icon); } catch (RemoteException ex) { } } } }
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + " icon=" + icon); StatusBarIconView view = new StatusBarIconView(mContext, slot, null); view.set(icon); //add in mStatusIcons mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, mIconSize)); view = new StatusBarIconView(mContext, slot, null); view.set(icon); mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, mIconSize)); }