ps:Android4.2
首先介绍什么是SystemUI:
对于Phone来说SystemUI指的是:StatusBar、NavigationBar.而对于平板或是TV来说SystemUI指的是CombineBar.
SystemUI也就是我们Phone的信号、蓝牙、WIFI标志等等这些状态,当我们的设备开机后首先呈现给用户的就是各种界面(包括SystemUI)。
下面介绍SystemUI的启动流程:
首先来看看SystemUI的代码结构,如下图:
在android4.2中,谷歌整合了phone和平板(TV)的SystemUI,也就是说可以根据设备的类型可以自动匹配相关的SystemUI。
分析应用程序我们一般从AndroidManifest.xml开始,SystemUI也是如此,我们打开AndroidManifest,有如下相关代码:
我们发现SystemUIService,他是在一开机就启动的服务。而SystemUIService是在SystemServer.java中真正启动的,如下代码: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); }而这里的startSystemUi是在android系统启动过程中的ServerThread的run方法中调用的。在SystemServer中,初始化了Android系统中的Java层服务,如PowerManagerService、WindowManagerService等等,当然也包括了SystemUIService,它们通过ServiceManager的addService()方法,添加到ServiceManager的管理中。而我们要关注的就是StatusBarManagerService 代码如下:... StatusBarManagerService statusBar = null;...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); }...try { Slog.i(TAG, "Notification Manager"); notification = new NotificationManagerService(context, statusBar, lights); ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); networkPolicy.bindNotificationManager(notification); } catch (Throwable e) { reportWtf("starting Notification Manager", e); }...既然到这里SystemUIService已经启动,那么我们就继续跟踪该Service吧。在SystemUIService的onCreate中: @Override public void onCreate() { // Tell the accessibility layer that this process will // run as the current user, i.e. run across users. AccessibilityManager.createAsSharedAcrossUsers(this); // Pick status bar or system bar. IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); try { SERVICES[0] = wm.hasSystemNavBar() ? R.string.config_systemBarComponent : R.string.config_statusBarComponent; } catch (RemoteException e) { Slog.w(TAG, "Failing checking whether status bar can hide", e); } final int N = SERVICES.length; mServices = new SystemUI[N]; for (int i=0; i<N; i++) { Class cl = chooseClass(SERVICES[i]); Slog.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; Slog.d(TAG, "running: " + mServices[i]); mServices[i].start(); } }在这段代码中,通过AIDL的方式获取了WindowManager的对象wm,并调用其方法hasSystemNavBar()来判断当前设备的类型,也就是说如果我们使用的Phone那么后续就会加载StatusBar和NivagationBar;而如果我们设备类型是Tablet(TV)之类的(可以在配置文档里面配置),就会加载CombiedBar。而对于平板 R.string.config_systemBarComponent 在config.xml中的值为:com.android.systemui.statusbar.tablet.TabletStatusBar ,我们继续跟踪,在TabletStatusBar中根据函数名我们可以判断在makeStatusBarView() 中对statusbar进行绘制。见代码: ........ final TabletStatusBarView sb = (TabletStatusBarView)View.inflate( context, R.layout.system_bar, null); mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);......... mNotificationArea = sb.findViewById(R.id.notificationArea);mBackButton = (ImageView)sb.findViewById(R.id.back); mNavigationArea = (ViewGroup) sb.findViewById(R.id.navigationArea); mHomeButton = mNavigationArea.findViewById(R.id.home); mMenuButton = mNavigationArea.findViewById(R.id.menu);mVolumeDownButton = mNavigationArea.findViewById(R.id.volume_down);mVolumeUpButton = mNavigationArea.findViewById(R.id.volume_up); mRecentButton = mNavigationArea.findViewById(R.id.recent_apps);......由此可以看出状态栏所有相关的东东在这里都体现出来了。下面我们进入布局system_bar中看看:<!-- notification icons & panel access --> <include layout="@layout/system_bar_notification_area" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_marginTop="1dp" />而在system_bar_notification_area中有: <LinearLayout android:id="@+id/notificationTrigger" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" > <com.android.systemui.statusbar.policy.Clock android:id="@+id/clock" android:textAppearance="@style/TextAppearance.StatusBar.Clock" android:layout_width="wrap_content" android:layout_height="match_parent" android:singleLine="true" android:paddingLeft="6dip" android:layout_marginRight="8dip" android:gravity="center_vertical|left" />对此我们进入到com.android.systemui.statusbar.policy.Clock中进一步查看:final void updateClock() { mCalendar.setTimeInMillis(System.currentTimeMillis()); setText(getSmallTime()); }private final CharSequence getSmallTime() { Context context = getContext(); boolean b24 = DateFormat.is24HourFormat(context); int res; if (b24) { res = R.string.twenty_four_hour_time_format; } else { res = R.string.twelve_hour_time_format; }...String result = sdf.format(mCalendar.getTime());if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { int magic1 = result.indexOf(MAGIC1); int magic2 = result.indexOf(MAGIC2); if (magic1 >= 0 && magic2 > magic1) { SpannableStringBuilder formatted = new SpannableStringBuilder(result); if (AM_PM_STYLE == AM_PM_STYLE_GONE) { formatted.delete(magic1, magic2+1); } else { if (AM_PM_STYLE == AM_PM_STYLE_SMALL) { CharacterStyle style = new RelativeSizeSpan(0.7f); formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } formatted.delete(magic2, magic2 + 1); formatted.delete(magic1, magic1 + 1); } return formatted; } }return result;}所以我们只要在getSmallTime中返回之前对其返回指进行处理即可达到我们的目地:比如修改显示方式等。