systemUI之statusbar

systemUI之statusbar

         看标题应该能猜出来这会是一个系列,不管写的咋样,就当是小结吧。因为是第一篇,所以会先说下systemUI是嘛,然后从view的角度认识一下systemUI的各个部件,重点分析一下statusbar的布局结构;最后是statusbar的加载流程。

一,文件目录

systemUI相对锁屏什么的它算是很规矩了,标准的android工程,安静的待在:

.\frameworks\base\packages\SystemUI目录下,可以直接单编译成apk,注意要push到system/app下面重启验证效果。


二,视图部件

 

 上面的图简单的表示了systemUI的结构,其实这个从我们的代码目录也可以知道个大概,那么啥是systemUI,干嘛独独要把这些放在一起弄个番号呢?个人本着细心学习,大胆推测的精神得到以下证据:1,它们都非常勤快,至少都是赶在launcher前面打卡;2不知疲倦,常驻内存,随时可以响应用户的使唤.有这些共性说它们是一奶同胞也就有论据了,如果你够耐心看下去会发现确实都是由一个systemUI服务孵化的。

因为该文的主角是statusbar,所以我们多花些笔墨解析一下它。statusbar在手机上其实分两个view:StatusBar和StatusBarExpanded,就拿StatusBar作典型进行分析吧:

从上面的层次图可以看出icon和ticker是两个平行frameLayout,一般时候都是icon布局显示,当有notification进来时ticker显示,为了方便研究分别给它们加了background color:


三,statusbar启动流程

我们知道了statusbar是啥,混了个脸熟后就可以对它的生平以及来龙去脉考究一番。为了描述方便,我试着把一个连贯的过程分成以下四步:

1,  systemUI是个服务

看一个android工程我们都会从AndroidManifest.xml文件开始分析,这个也不例外。从manifest文件中我们找到SystemUIService这个重要的服务,整个systemUI就是由它而起。通过简单的find命令,在systemserver.java里面找到了SystemUIService的启动代码。

2,  systemServer相关

systemServer的水其实非常深,它起于Zygote,负责Android系统所有的service注册登记,生和死。系统的分析需要另起篇幅,这里我们使用查找直接找到systemUIService的启动代码:


3,  systemUIservice

接上面,我们直接看onCreate方法,主要作用就是根据机器硬件配置决定是实例化statusbar还是systembar。并启动相应的start方法。

  1. public void onCreate() {  
  2.         // Pick status bar or system bar.  
  3.         //1.aidl远程调用windowmanager实例  
  4.         IWindowManager wm = IWindowManager.Stub.asInterface(  
  5.                 ServiceManager.getService(Context.WINDOW_SERVICE));  
  6.         try {  
  7.         //2.在PhoneWindowManager里面进行判定是phone还是tablet或其他。  
  8.             SERVICES[0] = wm.canStatusBarHide()  
  9.                     ? R.string.config_statusBarComponent  
  10.                     : R.string.config_systemBarComponent;  
  11.         } catch (RemoteException e) {  
  12.             Slog.w(TAG, "Failing checking whether status bar can hide", e);  
  13.         }  
  14.         //3.实例化statusbar。  
  15.         final int N = SERVICES.length;  
  16.         mServices = new SystemUI[N];  
  17.         for (int i=0; i<N; i++) {  
  18.             Class cl = chooseClass(SERVICES[i]);  
  19.             Slog.d(TAG, "loading: " + cl);  
  20.             try {  
  21.                 mServices[i] = (SystemUI)cl.newInstance();  
  22.             } catch (IllegalAccessException ex) {  
  23.                 throw new RuntimeException(ex);  
  24.             } catch (InstantiationException ex) {  
  25.                 throw new RuntimeException(ex);  
  26.             }  
  27.         //4.启动statusbar。  
  28.             mServices[i].mContext = this;  
  29.             Slog.d(TAG, "running: " + mServices[i]);  
  30.             mServices[i].start();  
  31.         }  
  32.     }  

通过查看systemUI的资源文件找到以下定义

  1. <!-- Component to be usedas the status bar service.  Mustimplement the IStatusBar  
  2.      interface. This name is in the ComponentName flattened format (package/class)  -->  
  3.     <string name="config_statusBarComponent"translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>  
  4.    
  5.     <!--Component to be used as the system bar service. Must implement the IStatusBar  
  6.      interface. This name is in the ComponentName flattened format (package/class)  -->  
  7. <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>  

所以实际上起的是PhoneStatusBar.java的start()。

4,PhoneStatusBar

前面的都是铺垫,到这里终于要来实际的了。分析的顺序是PhoneStatusBar.start() => StatusBar.start()=>PhoneStatusBar.makeStatusBarView()。

  1. public void start() {  
  2.         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))  
  3.                 .getDefaultDisplay();  
  4.         mWindowManager = IWindowManager.Stub.asInterface(  
  5.                 ServiceManager.getService(Context.WINDOW_SERVICE));  
  6. //调用父类statusBar的start方法。  
  7.  super.start();  
  8. //加载导航条。  
  9.         addNavigationBar();  
  10.         //addIntruderView();  
  11.         // 最后调用policy加载更新图标  
  12.         mIconPolicy = new PhoneStatusBarPolicy(mContext);  
  13. }  

我们进入statusBar.start()一探究竟:

  1. public void start(){  
  2.         // 1.First set up our views and stuff.  
  3.         View sb = makeStatusBarView();  
  4.    
  5.         // 2.Connect in to the status bar manager service  
  6.        。。。。。。  
  7.         try {  
  8.             mBarService.registerStatusBar(mCommandQueue, iconList,notificationKeys, notifications,  
  9.                     switches, binders);  
  10.         } catch (RemoteException ex) {  
  11.         // 3.If the system process isn't there we're doomed anyway.  
  12.         }  
  13.         disable(switches[0]);  
  14.         setSystemUiVisibility(switches[1]);  
  15.         topAppWindowChanged(switches[2] != 0);  
  16.         // 4.StatusBarManagerService has a back up of IME token and it's restoredhere.  
  17.         setImeWindowStatus(binders.get(0),switches[3], switches[4]);  
  18.         setHardKeyboardStatus(switches[5] != 0,switches[6] != 0);  
  19.    
  20.         // 5.Set up the initial icon state  
  21.         int N = iconList.size();  
  22.         int viewIndex = 0;  
  23.         for (int i=0; i<N; i++) {  
  24.             StatusBarIcon icon =iconList.getIcon(i);  
  25.             if (icon != null) {  
  26.                 addIcon(iconList.getSlot(i), i,viewIndex, icon);  
  27.                 viewIndex++;  
  28.             }  
  29.         }  
  30.    
  31.         // 6.Set up the initial notification state  
  32.         N = notificationKeys.size();  
  33.         if (N == notifications.size()) {  
  34.             for (int i=0; i<N; i++) {  
  35.                addNotification(notificationKeys.get(i), notifications.get(i));  
  36.             }  
  37.         } else {  
  38.             Log.wtf(TAG, "Notification list length mismatch: keys=" + N  
  39.                     + " notifications=" +notifications.size());  
  40.         }  
  41.    
  42.         // 7.Put up the view  
  43.         final int height = getStatusBarHeight();  
  44.    
  45.         final WindowManager.LayoutParams lp = newWindowManager.LayoutParams(  
  46.                 ViewGroup.LayoutParams.MATCH_PARENT,  
  47.                 height,  
  48.                 WindowManager.LayoutParams.TYPE_STATUS_BAR,  
  49.                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
  50.                     |WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING  
  51.                     |WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,  
  52.                 PixelFormat.OPAQUE);  
  53.          
  54.         // 8.the status bar should be in an overlay if possible  
  55.         final Display defaultDisplay  
  56.             = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))  
  57.                 .getDefaultDisplay();  
  58.         if (ActivityManager.isHighEndGfx(defaultDisplay)){  
  59.             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;  
  60.         }  
  61.    
  62.         lp.gravity = getStatusBarGravity();  
  63.         lp.setTitle("StatusBar");  
  64.         lp.packageName = mContext.getPackageName();  
  65.         lp.windowAnimations = R.style.Animation_StatusBar;  
  66.         WindowManagerImpl.getDefault().addView(sb,lp);  
  67.    
  68.         if (SPEW) {  
  69.             Slog.d(TAG, "Added status bar view: gravity=0x" + Integer.toHexString(lp.gravity)  
  70.                    + " icons=" + iconList.size()  
  71.                    + " disabled=0x" + Integer.toHexString(switches[0])  
  72.                    + " lights=" + switches[1]  
  73.                    + " menu=" + switches[2]  
  74.                    + " imeButton=" + switches[3]  
  75.                    );  
  76.         }  
  77.    
  78.         mDoNotDisturb = new DoNotDisturb(mContext);  
  79. }  

statusBar乃至整个systemUI的view是怎么创建起来的,我们必须进入第一步的makeStatusBarView()方法细看一下。

  1. protected View makeStatusBarView() {  
  2.      。。。。  
  3. //1.加载ExpandedView。  
  4.         ExpandedView expanded = (ExpandedView)View.inflate(context,  
  5.                 R.layout.status_bar_expanded, null);  
  6.         if (DEBUG) {  
  7.             expanded.setBackgroundColor(0x6000FF80);  
  8.         }  
  9.         expanded.mService = this;  
  10. //2.加载PhoneStatusBarView。  
  11.         PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,  
  12.                 R.layout.status_bar, null);  
  13.         sb.mService = this;  
  14.         mStatusBarView = sb;  
  15. //3.决定是否加载NavigationBarView。  
  16.         try {  
  17.             boolean showNav = mWindowManager.hasNavigationBar();  
  18.             if (showNav) {  
  19.                 mNavigationBarView =   
  20.                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);  
  21.   
  22.                 mNavigationBarView.setDisabledFlags(mDisabled);  
  23.             }  
  24.         } catch (RemoteException ex) {  
  25.             // no window manager? good luck with that  
  26.         }  
  27. //4.加载statusBar的各个具体控件。  
  28.         // figure out which pixel-format to use for the status bar.  
  29.         mPixelFormat = PixelFormat.OPAQUE;  
  30.         mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);  
  31.         mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);  
  32.         mIcons = (LinearLayout)sb.findViewById(R.id.icons);  
  33.         mTickerView = sb.findViewById(R.id.ticker);  
  34. //4.实例化各种控制器。  
  35.         mLocationController = new LocationController(mContext); // will post a notification  
  36.         mBatteryController = new BatteryController(mContext);  
  37.         mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));  
  38.         mNetworkController = new NetworkController(mContext);  
  39. //5.加载并更新RecentsPanelView。  
  40.         // RecentsPanel  
  41.         mRecentTasksLoader = new RecentTasksLoader(context);  
  42.         updateRecentsPanel();  
  43. //6.注册定制的监听器。  
  44.         // receive broadcasts  
  45.         IntentFilter filter = new IntentFilter();  
  46.         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);  
  47.         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);  
  48.         filter.addAction(Intent.ACTION_SCREEN_OFF);  
  49.         context.registerReceiver(mBroadcastReceiver, filter);  
  50.   
  51.         return sb;  
  52.     }  

以上大概就是就是整个systemUI的加载流程,主线就是statusBar,在加载它的时候顺便也把RecentsPanel,NavigationBarView等看起来没啥联系的东西也一块加载好,私以为这里的代码结构还可以更好,4.1可能会有所改善吧。

小结:

         这些东西其实一个月前就想写了,断断续续的一直没有开始着手,一来总有很多琐事或看起来更重要的事来打扰,二来是总觉得自己看的肤浅,不敢写,也不想写。不过总算是写出第一篇了。systemUI这块是整个系统UI风格的关键也最大程度地影响着用户的日常体验,无论是优化还是现有的usb处理挂载流程都有很多东西值得去挖掘,日后陆续放出吧。

版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值