Android 4.0 ICS SystemUI浅析——StatusBar加载流程分析
本文来自:http://blog.****.net/yihongyuelan欢迎转载 请务必注明出处!
在《Android 4.0 ICS SystemUI浅析——SystemUI启动流程》中,我们提到了在Phone中,整个StatusBar和NavigationBar都是在/SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java的start()方法中,完成初始化并显示到界面上的。因此,我们回到这段代码中查看:
- @Override
- publicvoidstart(){
- mDisplay=((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
- mWindowManager=IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
- super.start();//callsmakeStatusBarView()这里会调用父类StatusBar.java中的start()方法
- addNavigationBar();//加载导航栏,本文因以StatusBar为主,因此暂不分析NavigationBar
- //addIntruderView();
- //Lastly,calltotheiconpolicytoinstall/updatealltheicons.
- mIconPolicy=newPhoneStatusBarPolicy(mContext);//用于初始化以及更新StatusBar上的icons
- }
我们继续跟踪super.start()方法,来到/SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java的start()方法中,如代码所示:
- publicvoidstart(){
- //Firstsetupourviewsandstuff.首先准备我们需要显示的view以及原材料
- //我们先跟踪这里的makeStatusBarView
- Viewsb=makeStatusBarView();
- //Connectintothestatusbarmanagerservice
- StatusBarIconListiconList=newStatusBarIconList();
- ArrayList<IBinder>notificationKeys=newArrayList<IBinder>();
- ArrayList<StatusBarNotification>notifications=newArrayList<StatusBarNotification>();
- ......
通过Open Implementation跳转到makeStatusBarView的实现,因为我们是针对Phone来分析的,因此选择PhoneStatusBar,代码如下:
- //================================================================================
- //Constructingtheview
- //================================================================================
- protectedViewmakeStatusBarView(){
- finalContextcontext=mContext;
- Resourcesres=context.getResources();
- //获取ExpandedView的尺寸
- updateDisplaySize();//populatesmDisplayMetrics
- //定义icon的大小,缩放率和彼此间距
- loadDimens();
- mIconSize=res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
- //设置ExpandedView的布局
- ExpandedViewexpanded=(ExpandedView)View.inflate(context,
- R.layout.status_bar_expanded,null);
- if(DEBUG){
- expanded.setBackgroundColor(0x6000FF80);
- }
- expanded.mService=this;
- //前面已注释,以下三段代码没有用到
- mIntruderAlertView=View.inflate(context,R.layout.intruder_alert,null);
- mIntruderAlertView.setVisibility(View.GONE);
- mIntruderAlertView.setClickable(true);
- PhoneStatusBarViewsb;
- //这里根据是否是双卡来加载不同的布局文件
- if(TelephonyManager.getDefault().isMultiSimEnabled()){
- sb=(PhoneStatusBarView)View.inflate(context,
- R.layout.msim_status_bar,null);
- }else{
- sb=(PhoneStatusBarView)View.inflate(context,
- R.layout.status_bar,null);
- }
- sb.mService=this;
- mStatusBarView=sb;
- //是否显示NavigationBar
- try{
- booleanshowNav=mWindowManager.hasNavigationBar();
- if(showNav){
- mNavigationBarView=
- (NavigationBarView)View.inflate(context,R.layout.navigation_bar,null);
- mNavigationBarView.setDisabledFlags(mDisabled);
- }
- }catch(RemoteExceptionex){
- //nowindowmanager?goodluckwiththat
- }
- //figureoutwhichpixel-formattouseforthestatusbar.
- mPixelFormat=PixelFormat.OPAQUE;
- //系统状态图标布局初始化
- mStatusIcons=(LinearLayout)sb.findViewById(R.id.statusIcons);
- //通知图标布局初始化
- mNotificationIcons=(IconMerger)sb.findViewById(R.id.notificationIcons);
- mMoreIcon=sb.findViewById(R.id.moreIcon);
- mNotificationIcons.setOverflowIndicator(mMoreIcon);
- //icons布局初始化,该布局用于装载除开tiker外的所有控件
- mIcons=(LinearLayout)sb.findViewById(R.id.icons);
- //ticker布局初始化
- mTickerView=sb.findViewById(R.id.ticker);
- //以上几个重要布局的关系在上一篇文章有详细分析
- //以下几段代码是在设置ExpandedView,ExpandedDialog通过加载ExpandedView显示,其中包括了ExpanedView上的清除按钮,
- //设置按钮,滚动条,日期显示等等
- mExpandedDialog=newExpandedDialog(context);
- mExpandedView=expanded;
- mPile=(NotificationRowLayout)expanded.findViewById(R.id.latestItems);
- mExpandedContents=mPile;//was:expanded.findViewById(R.id.notificationLinearLayout);
- mNoNotificationsTitle=(TextView)expanded.findViewById(R.id.noNotificationsTitle);
- mNoNotificationsTitle.setVisibility(View.GONE);//disablingfornow
- mClearButton=expanded.findViewById(R.id.clear_all_button);
- mClearButton.setOnClickListener(mClearButtonListener);
- mClearButton.setAlpha(0f);
- mClearButton.setEnabled(false);
- mDateView=(DateView)expanded.findViewById(R.id.date);
- mSettingsButton=expanded.findViewById(R.id.settings_button);
- mSettingsButton.setOnClickListener(mSettingsButtonListener);
- mScrollView=(ScrollView)expanded.findViewById(R.id.scroll);
- //tickerView的初始化
- mTicker=newMyTicker(context,sb);
- TickerViewtickerView=(TickerView)sb.findViewById(R.id.tickerText);
- tickerView.mTicker=mTicker;
- //TrackingView初始化
- mTrackingView=(TrackingView)View.inflate(context,R.layout.status_bar_tracking,null);
- mTrackingView.mService=this;
- mCloseView=(CloseDragHandle)mTrackingView.findViewById(R.id.close);
- mCloseView.mService=this;
- mEdgeBorder=res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
- //settheinitalviewvisibility
- setAreThereNotifications();
- //Othericons
- //以下是对其他icons的加载(信号及电量图标的加载)
- mLocationController=newLocationController(mContext);//willpostanotification
- mBatteryController=newBatteryController(mContext);
- mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
- SignalClusterViewsignalCluster;
- LinearLayoutmSimSignalView;
- //根据是否是双卡加载不同的布局文件
- if(TelephonyManager.getDefault().isMultiSimEnabled()){
- mMSimNetworkController=newMSimNetworkController(mContext);
- mSimSignalView=(LinearLayout)sb.findViewById(R.id.msim_signal_cluster);
- if(FeatureQuery.FEATURE_ANNUCIATOR_NEW_STATUSBAR_STYLE){
- CUMSimSignalClusterViewcuMSimSignalCluster=(CUMSimSignalClusterView)View.inflate(context,R.layout.msim_signal_cluster_view_cu,null);
- mSimSignalView.addView(cuMSimSignalCluster);
- for(inti=0;i<TelephonyManager.getDefault().getPhoneCount();i++){
- mMSimNetworkController.addSignalCluster(cuMSimSignalCluster,i);
- }
- cuMSimSignalCluster.setNetworkController(mMSimNetworkController);
- }else{
- MSimSignalClusterViewmSimSignalCluster=(MSimSignalClusterView)View.inflate(context,R.layout.msim_signal_cluster_view,null);
- mSimSignalView.addView(mSimSignalCluster);
- for(inti=0;i<TelephonyManager.getDefault().getPhoneCount();i++){
- mMSimNetworkController.addSignalCluster(mSimSignalCluster,i);
- }
- mSimSignalCluster.setNetworkController(mMSimNetworkController);
- }
- }else{
- mNetworkController=newNetworkController(mContext);
- signalCluster=(SignalClusterView)sb.findViewById(R.id.signal_cluster);
- mNetworkController.addSignalCluster(signalCluster);
- signalCluster.setNetworkController(mNetworkController);
- //finalImageViewwimaxRSSI=
- //(ImageView)sb.findViewById(R.id.wimax_signal);
- //if(wimaxRSSI!=null){
- //mNetworkController.addWimaxIconView(wimaxRSSI);
- //}
- }
- //RecentsPanel
- //最近使用界面初始化
- mRecentTasksLoader=newRecentTasksLoader(context);
- updateRecentsPanel();
- //receivebroadcasts
- //注册广播监听器
- IntentFilterfilter=newIntentFilter();
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- context.registerReceiver(mBroadcastReceiver,filter);
- returnsb;
- }
通过makeStatusBarView()我们可以看到,在该方法中整个StatusBar根据获取的设备配置信息进行了布局,就好比我们去吃饭,先要安排好座位和桌子,最后才上菜,我们需要加载的icons——就是菜!!:D
我们回到StatusBar.java的start()方法中继续分析,代码如下:
- publicvoidstart(){
- //Firstsetupourviewsandstuff.首先准备我们需要显示的view以及原材料
- //我们先跟踪这里的makeStatusBarView
- Viewsb=makeStatusBarView();
- //Connectintothestatusbarmanagerservice
- //初始化各个存储器,用于存储各类信息,这些信息通过StatusBarManagerService获取
- //iconsList用于存放icons
- StatusBarIconListiconList=newStatusBarIconList();
- //nodificationKeys保存以Binder为Key的notification
- ArrayList<IBinder>notificationKeys=newArrayList<IBinder>();
- //保存StatusBarNotification类型的notifications
- ArrayList<StatusBarNotification>notifications=newArrayList<StatusBarNotification>();
- //mCommandQueue是和IStatusBarService进行交互的IBinder
- mCommandQueue=newCommandQueue(this,iconList);
- //这里实际上获取的是StatusBarManagerService
- mBarService=IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- int[]switches=newint[7];
- ArrayList<IBinder>binders=newArrayList<IBinder>();
- try{
- //通过StatusBarManagerService中的registerStatusBar来获取初始设置
- mBarService.registerStatusBar(mCommandQueue,iconList,notificationKeys,notifications,
- switches,binders);
- }catch(RemoteExceptionex){
- //Ifthesystemprocessisn'ttherewe'redoomedanyway.
- }
- //对SystemUI上像Clock、ExpandedView、NavigationBar等进行初始化设置
- disable(switches[0]);
- setSystemUiVisibility(switches[1]);
- topAppWindowChanged(switches[2]!=0);
- //StatusBarManagerServicehasabackupofIMEtokenandit'srestoredhere.
- setImeWindowStatus(binders.get(0),switches[3],switches[4]);
- setHardKeyboardStatus(switches[5]!=0,switches[6]!=0);
- //Setuptheinitialiconstate
- //icon加载(注:陷阱!!!一不注意就会迷失!!后文详将细分析)
- intN=iconList.size();
- intviewIndex=0;
- for(inti=0;i<N;i++){
- StatusBarIconicon=iconList.getIcon(i);
- if(icon!=null){
- addIcon(iconList.getSlot(i),i,viewIndex,icon);
- viewIndex++;
- }
- }
- //Setuptheinitialnotificationstate
- //加载notifications
- N=notificationKeys.size();
- if(N==notifications.size()){
- for(inti=0;i<N;i++){
- addNotification(notificationKeys.get(i),notifications.get(i));
- }
- }else{
- Log.wtf(TAG,"Notificationlistlengthmismatch:keys="+N
- +"notifications="+notifications.size());
- }
- //Putuptheview
- //获取StatusBar高度
- finalintheight=getStatusBarHeight();
- //设置lp各种属性
- finalWindowManager.LayoutParamslp=newWindowManager.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,
- //WeuseapixelformatofRGB565forthestatusbartosavememorybandwidthand
- //toensurethatthelayercanbehandledbyHWComposer.Onsomedevicesthe
- //HWComposerisunabletohandleSW-renderedRGBX_8888layers.
- PixelFormat.RGB_565);
- //thestatusbarshouldbeinanoverlayifpossible
- finalDisplaydefaultDisplay
- =((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
- //enablehardwareaccelerationbasedondevice
- //使能硬件加速,不过只有Tablet上才有用
- setHardwareAcceleration(lp);
- lp.gravity=getStatusBarGravity();
- lp.setTitle("StatusBar");
- lp.packageName=mContext.getPackageName();
- lp.windowAnimations=R.style.Animation_StatusBar;
- //在Window上显示StatusBar界面
- WindowManagerImpl.getDefault().addView(sb,lp);
- mDoNotDisturb=newDoNotDisturb(mContext);
- }
可能大多数朋友都还是云里雾里的,先别急,我们只是把大致流程走完了,细节还没有去分析,接下来我们再来看看StatusBar到底是如何加载Icons的。
需要分析如何加载Icons,首先我们根据StatusBar.java中的start()方法可以看到,addIcon()方法完成了Icons的加载。那么通过Open Implementation跳转到PhoneStatusBar.java中的addIcon()方法中(因为我们之前传递的Context是PhoneStatusBar的),代码如下:
- publicvoidaddIcon(Stringslot,intindex,intviewIndex,StatusBarIconicon){
- if(SPEW)Slog.d(TAG,"addIconslot="+slot+"index="+index+"viewIndex="+viewIndex
- +"icon="+icon);
- //初始化StatusBarIconView
- StatusBarIconViewview=newStatusBarIconView(mContext,slot,null);
- //加载icon
- view.set(icon);
- //这里的FEATURE_ANNUCIATOR_NEW_STATUSBAR_STYLE是高通自己定义的,默认为true
- if(FeatureQuery.FEATURE_ANNUCIATOR_NEW_STATUSBAR_STYLE){
- //将设置好icon的StatusBarIconView加载到mStatusIcons布局中
- mStatusIcons.addView(view,viewIndex,newLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,mIconSize));
- }else{
- mStatusIcons.addView(view,viewIndex,newLinearLayout.LayoutParams(mIconSize,mIconSize));
- }
- }
整个加载过程从表面上看来只有3步,但从本质上来讲远远不止3步。首先,我们先来看看addIcon(...)方法所传递的值;我将这里Slog中的内容打印出来,结果如下:
- addIconslot=ttyindex=6viewIndex=0icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f02012blevel=0visible=falsenum=0)
- addIconslot=cdma_eriindex=11viewIndex=1icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f0200d8level=0visible=falsenum=0)
- addIconslot=bluetoothindex=4viewIndex=0icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f020073level=0visible=falsenum=0)
- addIconslot=alarm_clockindex=18viewIndex=3icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f020060level=0visible=falsenum=0)
- addIconslot=sync_activeindex=2viewIndex=0icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f020129level=0visible=falsenum=0)
- addIconslot=sync_failingindex=1viewIndex=0icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f02012alevel=0visible=falsenum=0)
- addIconslot=volumeindex=9viewIndex=4icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f0200d6level=0visible=falsenum=0)
- addIconslot=headsetindex=16viewIndex=6icon=StatusBarIcon(pkg=com.android.systemuiid=0x7f02000alevel=0visible=falsenum=0)
- publicStatusBarIconView(Contextcontext,Stringslot,Notificationnotification){
- super(context);
- //获取资源
- finalResourcesres=context.getResources();
- mSlot=slot;
- //画笔初始化
- mNumberPain=newPaint();
- mNumberPain.setTextAlign(Paint.Align.CENTER);
- mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color));
- mNumberPain.setAntiAlias(true);
- mNotification=notification;
- setContentDescription(notification);
- //Wedonotresizeandscalesystemicons(ontheright),onlynotificationicons(onthe
- //left).
- if(notification!=null){
- finalintouterBounds=res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
- finalintimageBounds=res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
- finalfloatscale=(float)imageBounds/(float)outerBounds;
- setScaleX(scale);
- setScaleY(scale);
- finalfloatalpha=res.getFraction(R.dimen.status_bar_icon_drawing_alpha,1,1);
- setAlpha(alpha);
- }
- //按图片原来的size居中显示
- setScaleType(ImageView.ScaleType.CENTER);
- }
通过查看StatusBarIconView的继承关系我们可以发现public class StatusBarIconView extends AnimatedImageView ,继续跟踪可以看到public class AnimatedImageView extends ImageView,也就是说我们的StatusBarIconView其实就是一个封装过的ImageView,这样自然能够盛放我们的Icons了。继续查看StatusBarIconView的set()方法,代码如下:
- /**
- *Returnswhetherthesetsucceeded.
- */
- publicbooleanset(StatusBarIconicon){
- finalbooleaniconEquals=mIcon!=null
- &&streq(mIcon.iconPackage,icon.iconPackage)
- &&mIcon.iconId==icon.iconId;
- finalbooleanlevelEquals=iconEquals
- &&mIcon.iconLevel==icon.iconLevel;
- finalbooleanvisibilityEquals=mIcon!=null
- &&mIcon.visible==icon.visible;
- finalbooleannumberEquals=mIcon!=null
- &&mIcon.number==icon.number;
- //将icon的信息copy到mIcon中
- mIcon=icon.clone();
- setContentDescription(icon.contentDescription);
- //获取icon图片并设置到StatusBarIconView中去
- if(!iconEquals){
- Drawabledrawable=getIcon(icon);
- if(drawable==null){
- Slog.w(StatusBar.TAG,"Noiconforslot"+mSlot);
- returnfalse;
- }
- setImageDrawable(drawable);
- }
- //设置需要显示的图片
- if(!levelEquals){
- setImageLevel(icon.iconLevel);
- }
- //这个不太清楚具体是干嘛的
- if(!numberEquals){
- if(icon.number>0&&mContext.getResources().getBoolean(
- R.bool.config_statusBarShowNumber)){
- if(mNumberBackground==null){
- mNumberBackground=getContext().getResources().getDrawable(
- R.drawable.ic_notification_overlay);
- }
- placeNumber();
- }else{
- mNumberBackground=null;
- mNumberText=null;
- }
- invalidate();
- }
- //设置是否可见
- if(!visibilityEquals){
- setVisibility(icon.visible?VISIBLE:GONE);
- }
- returntrue;
- }
到这一步时,我们已经将系统的Icons设置到了mStatusIcons这个mStatusIcons的LinearLayout上了。
但是,事实真的如此吗?这样就完成icons的初始化了吗?还是那句话,实践是检验真理是否正确的唯一标准!那么我们在PhoneStatusBar.java的addIcon()方法中,加入代码,将程序调用栈打印出来,结果一看便知(当然,也可以用Eclipse的远程调试)!加入代码如下:
- StackTraceElementst[]=Thread.currentThread().getStackTrace();
- for(inti=0;i<st.length;i++)
- System.out.println(i+":"+st[i]);
- I/System.out(420):0:dalvik.system.VMStack.getThreadStackTrace(NativeMethod)
- I/System.out(420):1:java.lang.Thread.getStackTrace(Thread.java:591)
- I/System.out(420):2:com.android.systemui.statusbar.phone.PhoneStatusBar.addIcon(PhoneStatusBar.java:562)
- I/System.out(420):3:com.android.systemui.statusbar.CommandQueue$H.handleMessage(CommandQueue.java:212)
- I/System.out(420):4:android.os.Handler.dispatchMessage(Handler.java:99)
- I/System.out(420):5:android.os.Looper.loop(Looper.java:137)
- I/System.out(420):6:android.app.ActivityThread.main(ActivityThread.java:4450)
- I/System.out(420):7:java.lang.reflect.Method.invokeNative(NativeMethod)
- I/System.out(420):8:java.lang.reflect.Method.invoke(Method.java:511)
- I/System.out(420):9:com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
- I/System.out(420):10:com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
- I/System.out(420):11:dalvik.system.NativeStart.main(NativeMethod)
- ......
从打印出来的调用栈,我们可以发现,实际条用addIcon()方法的,并不是我们之前分析的StatusBar,而是来自CommandQueue中的handleMessage,这和我们之前的分析大相径庭啊!也就是说实际上addIcon()在CommandQueue中被调用了,那么我们就反过来分析,直接去CommandQueue.java中的handleMessage找到addIcon()。代码如下:
- caseOP_SET_ICON:{
- StatusBarIconicon=(StatusBarIcon)msg.obj;
- StatusBarIconold=mList.getIcon(index);
- if(old==null){
- mList.setIcon(index,icon);
- mCallbacks.addIcon(mList.getSlot(index),index,viewIndex,icon);
- }else{
- mList.setIcon(index,icon);
- mCallbacks.updateIcon(mList.getSlot(index),index,viewIndex,
- old,icon);
- }
- break;
- }
通过case OP_SET_ICON我们可以继续追查,我们可以查到是谁发送的这个message,代码如下:
- publicvoidsetIcon(intindex,StatusBarIconicon){
- synchronized(mList){
- intwhat=MSG_ICON|index;
- mHandler.removeMessages(what);
- mHandler.obtainMessage(what,OP_SET_ICON,0,icon.clone()).sendToTarget();
- }
- }
图 1
其中第一个onTransact是一个IBinder,后两者是StatusBarManagerService中的方法。通过方法名称,我们可以大致猜测,setIcon是设置Icon,setIconVisibility是这是Icon是否可见,我们从逻辑上分析,如果是开机第一次调用我们应该先设置Icon然后再考虑设置其可见性(看完后文就会明白了:D)。我们直接跳转到StatusBarManagerService中的setIcon()方法,代码如下:
- publicvoidsetIcon(Stringslot,StringiconPackage,inticonId,inticonLevel,
- StringcontentDescription){
- enforceStatusBar();
- synchronized(mIcons){
- intindex=mIcons.getSlotIndex(slot);//这里会检查是否是未定义的icon,如果是则抛出异常
- if(index<0){
- thrownewSecurityException("invalidstatusbariconslot:"+slot);
- }
- StatusBarIconicon=newStatusBarIcon(iconPackage,iconId,iconLevel,0,
- contentDescription);
- //Slog.d(TAG,"setIconslot="+slot+"index="+index+"icon="+icon);
- mIcons.setIcon(index,icon);
- if(mBar!=null){
- try{
- mBar.setIcon(index,icon);//这里调用的
- }catch(RemoteExceptionex){
- }
- }
- }
- }
继续用Open Call Hierarchy查找哪里调用的setIcon方法,如图2:
图 2
这里一看就知道应该是StatusBarManager中的setIcon嘛,继续跟踪,代码如下:
- publicvoidsetIcon(Stringslot,inticonId,inticonLevel,StringcontentDescription){
- try{
- finalIStatusBarServicesvc=getService();
- if(svc!=null){
- svc.setIcon(slot,mContext.getPackageName(),iconId,iconLevel,
- contentDescription);//这里调用的
- }
- }catch(RemoteExceptionex){
- //systemprocessisdeadanyway.
- thrownewRuntimeException(ex);
- }
- }
目前看来还不是很清晰,继续查找,如图3:
图 3
看到这里请不要头晕,因为真相就在眼前!那么这里应该是谁在调用呢?在本文的一开始,我们就分析了/SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java的start()方法,在该方法中有如下代码:
- mIconPolicy=newPhoneStatusBarPolicy(mContext);
- publicPhoneStatusBarPolicy(Contextcontext){
- ......
- //listenforbroadcasts
- IntentFilterfilter=newIntentFilter();
- filter.addAction(Intent.ACTION_ALARM_CHANGED);
- filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
- filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
- filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- filter.addAction(Intent.ACTION_HEADSET_PLUG);//tedadd2021-4-24
- filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
- mContext.registerReceiver(mIntentReceiver,filter,null,mHandler);
- ......
- //TTYstatus
- mService.setIcon("tty",R.drawable.stat_sys_tty_mode,0,null);//这里调用
- mService.setIconVisibility("tty",false);
- //CdmaRoamingIndicator,ERI
- mService.setIcon("cdma_eri",R.drawable.stat_sys_roaming_cdma_0,0,null);//这里调用
- mService.setIconVisibility("cdma_eri",false);
- ......
- mService.setIcon("bluetooth",bluetoothIcon,0,null);//这里调用
- mService.setIconVisibility("bluetooth",mBluetoothEnabled);
- //Alarmclock
- mService.setIcon("alarm_clock",R.drawable.stat_sys_alarm,0,null);//这里调用
- mService.setIconVisibility("alarm_clock",false);
- //Syncstate
- mService.setIcon("sync_active",R.drawable.stat_sys_sync,0,null);//这里调用
- mService.setIcon("sync_failing",R.drawable.stat_sys_sync_error,0,null);//这里调用
- mService.setIconVisibility("sync_active",false);
- mService.setIconVisibility("sync_failing",false);
- //volume
- mService.setIcon("volume",R.drawable.stat_sys_ringer_silent,0,null);//这里调用
- mService.setIconVisibility("volume",false);
- updateVolume();
- //headset
- mService.setIcon("headset",R.drawable.ckt_headset_with_mic,0,null);//这里调用
- mService.setIconVisibility("headset",false);
- }
这里也同时验证了我们前面的猜想,即先设置Icon再设置其可见性。也许你会认为本文到这里已经完结了(太长了,一次看不完...o(╯□╰)o),但有个别地方我还得再提一下,Android 启动之后,在SystemServer.java的run方法中,调用了StatusBarManagerService的构造方法,代码如下:
- ......
- try{
- Slog.i(TAG,"StatusBar");
- statusBar=newStatusBarManagerService(context,wm);
- ServiceManager.addService(Context.STATUS_BAR_SERVICE,statusBar);
- }catch(Throwablee){
- reportWtf("startingStatusBarManagerService",e);
- }
- ......
- publicStatusBarManagerService(Contextcontext,WindowManagerServicewindowManager){
- mContext=context;
- mWindowManager=windowManager;
- mWindowManager.setOnHardKeyboardStatusChangeListener(this);
- finalResourcesres=context.getResources();
- //这里加载了系统预置的所有icon,路径在:Sourcecode/framework/base/core/res/res/values/config.xml中
- mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
- }
其中Sourcecode/framework/base/core/res/res/values/config.xml中的预置图标定义如下:
- <string-arrayname="config_statusBarIcons">
- <item><xliff:gid="id">ime</xliff:g></item>
- <item><xliff:gid="id">sync_failing</xliff:g></item>
- <item><xliff:gid="id">sync_active</xliff:g></item>
- <item><xliff:gid="id">gps</xliff:g></item>
- <item><xliff:gid="id">bluetooth</xliff:g></item>
- <item><xliff:gid="id">nfc</xliff:g></item>
- <item><xliff:gid="id">tty</xliff:g></item>
- <item><xliff:gid="id">speakerphone</xliff:g></item>
- <item><xliff:gid="id">mute</xliff:g></item>
- <item><xliff:gid="id">volume</xliff:g></item>
- <item><xliff:gid="id">wifi</xliff:g></item>
- <item><xliff:gid="id">cdma_eri</xliff:g></item>
- <item><xliff:gid="id">phone_signal_second_sub</xliff:g></item>
- <item><xliff:gid="id">data_connection</xliff:g></item>
- <item><xliff:gid="id">phone_evdo_signal</xliff:g></item>
- <item><xliff:gid="id">phone_signal</xliff:g></item>
- <item><xliff:gid="id">headset</xliff:g></item>
- <item><xliff:gid="id">battery</xliff:g></item>
- <item><xliff:gid="id">alarm_clock</xliff:g></item>
- <item><xliff:gid="id">secure</xliff:g></item>
- <item><xliff:gid="id">clock</xliff:g></item>
- </string-array>
这些东西在后文判断时都会用到,在此记录用以备忘。
Update 20120810 时序图和UML图:
图 4
图 5
小结
本文主要是对StatusBar上面的Icons的加载进行了较为细致的分析,后面将继续分析各个部件的加载以及工作流程。其中自己也走了不少弯路,但还是想记录下载,毕竟没有谁从一开始就能做正确吧!将此总结分享出来希望能给各位一些帮助,同时也给自己一些激励,希望自己后面能做的更好。本文主要是枯燥的代码调用与追踪,但对于需要的朋友,我想还是很有帮助的,后面会将相关的时序图以及UML图贴出来,以供参考。