• 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方法。

    public void onCreate() {
            // Pick status bar or system bar.
    	    //1.aidl远程调用windowmanager实例
            IWindowManager wm = IWindowManager.Stub.asInterface(
                    ServiceManager.getService(Context.WINDOW_SERVICE));
            try {
    		//2.在PhoneWindowManager里面进行判定是phone还是tablet或其他。
                SERVICES[0] = wm.canStatusBarHide()
                        ? R.string.config_statusBarComponent
                        : R.string.config_systemBarComponent;
            } catch (RemoteException e) {
                Slog.w(TAG, "Failing checking whether status bar can hide", e);
            }
    		//3.实例化statusbar。
            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);
                }
    		//4.启动statusbar。
                mServices[i].mContext = this;
                Slog.d(TAG, "running: " + mServices[i]);
                mServices[i].start();
            }
        }
    

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

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

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

    4,PhoneStatusBar

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

    public void start() {
            mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                    .getDefaultDisplay();
            mWindowManager = IWindowManager.Stub.asInterface(
                    ServiceManager.getService(Context.WINDOW_SERVICE));
    //调用父类statusBar的start方法。
     super.start();
    //加载导航条。
            addNavigationBar();
            //addIntruderView();
            // 最后调用policy加载更新图标
            mIconPolicy = new PhoneStatusBarPolicy(mContext);
    }

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

    public void start(){
            // 1.First set up our views and stuff.
            View sb = makeStatusBarView();
     
            // 2.Connect in to the status bar manager service
           。。。。。。
            try {
                mBarService.registerStatusBar(mCommandQueue, iconList,notificationKeys, notifications,
                        switches, binders);
            } catch (RemoteException ex) {
            // 3.If the system process isn't there we're doomed anyway.
            }
            disable(switches[0]);
            setSystemUiVisibility(switches[1]);
            topAppWindowChanged(switches[2] != 0);
            // 4.StatusBarManagerService has a back up of IME token and it's restoredhere.
            setImeWindowStatus(binders.get(0),switches[3], switches[4]);
            setHardKeyboardStatus(switches[5] != 0,switches[6] != 0);
     
            // 5.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++;
                }
            }
     
            // 6.Set up the initial notification state
            N = notificationKeys.size();
            if (N == notifications.size()) {
                for (int i=0; i<N; i++) {
                   addNotification(notificationKeys.get(i), notifications.get(i));
                }
            } else {
                Log.wtf(TAG, "Notification list length mismatch: keys=" + N
                        + " notifications=" +notifications.size());
            }
     
            // 7.Put up the view
            final int height = getStatusBarHeight();
     
            final WindowManager.LayoutParams lp = 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,
                    PixelFormat.OPAQUE);
           
            // 8.the status bar should be in an overlay if possible
            final Display defaultDisplay
                = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                    .getDefaultDisplay();
            if (ActivityManager.isHighEndGfx(defaultDisplay)){
                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
     
            lp.gravity = getStatusBarGravity();
            lp.setTitle("StatusBar");
            lp.packageName = mContext.getPackageName();
            lp.windowAnimations = R.style.Animation_StatusBar;
            WindowManagerImpl.getDefault().addView(sb,lp);
     
            if (SPEW) {
                Slog.d(TAG, "Added status bar view: gravity=0x" + Integer.toHexString(lp.gravity)
                       + " icons=" + iconList.size()
                       + " disabled=0x" + Integer.toHexString(switches[0])
                       + " lights=" + switches[1]
                       + " menu=" + switches[2]
                       + " imeButton=" + switches[3]
                       );
            }
     
            mDoNotDisturb = new DoNotDisturb(mContext);
    }

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

    protected View makeStatusBarView() {
         。。。。
    //1.加载ExpandedView。
            ExpandedView expanded = (ExpandedView)View.inflate(context,
                    R.layout.status_bar_expanded, null);
            if (DEBUG) {
                expanded.setBackgroundColor(0x6000FF80);
            }
            expanded.mService = this;
    //2.加载PhoneStatusBarView。
            PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,
                    R.layout.status_bar, null);
            sb.mService = this;
            mStatusBarView = sb;
    //3.决定是否加载NavigationBarView。
            try {
                boolean showNav = mWindowManager.hasNavigationBar();
                if (showNav) {
                    mNavigationBarView = 
                        (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
    
                    mNavigationBarView.setDisabledFlags(mDisabled);
                }
            } catch (RemoteException ex) {
                // no window manager? good luck with that
            }
    //4.加载statusBar的各个具体控件。
            // figure out which pixel-format to use for the status bar.
            mPixelFormat = PixelFormat.OPAQUE;
            mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
            mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
            mIcons = (LinearLayout)sb.findViewById(R.id.icons);
            mTickerView = sb.findViewById(R.id.ticker);
    //4.实例化各种控制器。
            mLocationController = new LocationController(mContext); // will post a notification
            mBatteryController = new BatteryController(mContext);
            mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
            mNetworkController = new NetworkController(mContext);
    //5.加载并更新RecentsPanelView。
            // RecentsPanel
            mRecentTasksLoader = new RecentTasksLoader(context);
            updateRecentsPanel();
    //6.注册定制的监听器。
            // receive broadcasts
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
            filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            context.registerReceiver(mBroadcastReceiver, filter);
    
            return sb;
        }
    

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

    小结:

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

  • 相关阅读:
    Codeforces Round #107 (Div. 1) D Mission Impassable
    Codeforces Round #107 (Div. 1) C Smart Cheater
    Codeforces Round #104 (Div. 1) D Lucky Pair
    Codeforces Round #104 (Div. 1) C Lucky Subsequence
    拓扑排序&&欧拉(回)路
    复习笔记之矩阵快速幂(不定时更新)
    复习笔记之母函数
    树链剖分来一发
    最短路算法略解
    题目记录
  • 原文地址:https://www.cnblogs.com/aaa2832/p/3594758.html
Copyright © 2020-2023  润新知