Android源码笔记--SystemUIVisibility

SystemUIVisibility     java

       最近在学习SystemUI时,涉及到了SystemUIVisibility,在此记录一下。虽然StatusBarManager以及StatusBarManagerService为应用程序以及系统服务提供了操做状态栏与导航栏的全部接口,可是这些接口并不适用于那些没有系统签名的普通应用程序。若是普通应用程序但愿对状态栏以及导航栏进行操做,就须要使用SystemUIVisibility机制。session

    View.java
    //隐藏导航栏
    public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
    //隐藏状态栏
    public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;app

       常见设置SystemUIVisibility的方式有两种。一是在任意一个已经显示在窗口上的控件调用View.setSystemUiVisibility(),二是直接在窗口的LayoutParams.systemUiVisibility上进行设置并经过WindowManager.updateViewLayout()方法使其生效。ide

       SystemUIVisibility在系统中存在的地方布局

        SystemUIVisibility主要涉及状态栏和导航栏的行为以及窗口布局两个方面。所以它的消费者包含SystemUI中BaseStatusBar以及负责窗口布局的PhoneWindowManger。学习

 1  控件树中的SystemUIVisibilitythis

View.setSystemUiVisibility()的实现spa

        View.java
     
        public void setSystemUiVisibility(int visibility) {
            if (visibility != mSystemUiVisibility) {
               //(1) 保存在View本身的成员变量mSystemUiVisibility.
                mSystemUiVisibility = visibility;
                //(2)通知父控件这一变化
                if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
                    mParent.recomputeViewAttributes(this);
                }
            }
        }.net

    ViewRootImpl.java
        
          @Override
        public void recomputeViewAttributes(View child) {
       // 须要在窗口的主线程中调用
            checkThread();
            if (mView == child) {
        // 2  标记须要处理SystemUIVisibility的变化
               mAttachInfo.mRecomputeGlobalAttributes = true;
                if (!mWillDrawSoon) {
        // 3 触发一次“遍历”动做
                    scheduleTraversals();
                }
            }
        }线程

分析:遍历过程当中会执行ViewRootImpl.collectViewAttributes()方法收集控件树中每一个View所保存的SystemUIVisibility. 以下:

    private boolean collectViewAttributes() {
            if (mAttachInfo.mRecomputeGlobalAttributes) {
                //Log.i(mTag, "Computing view hierarchy attributes!");
                mAttachInfo.mRecomputeGlobalAttributes = false;
                boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
                mAttachInfo.mKeepScreenOn = false;
            //清空所保存的SystemUiVisibility
               mAttachInfo.mSystemUiVisibility = 0;
                mAttachInfo.mHasSystemUiListeners = false;
            //遍历整个控件树
                mView.dispatchCollectViewAttributes(mAttachInfo, 0);
            //移除被禁用的SystemUiVisibility标记    
               mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
                WindowManager.LayoutParams params = mWindowAttributes;
                mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
                if (mAttachInfo.mKeepScreenOn != oldScreenOn
                        || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
                        || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
                    applyKeepScreenOnFlag(params);
            //将SystemUiVisibility保存到窗口的LayoutParams
                   params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
                    params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
                    mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
                    return true;
                }
            }
            return false;
        }

     分析:当ViewRootImpl经过WMS.reLayoutWindow()方法对窗口进行从新布局时,本窗口所指望的SUV会伴随着LayoutParams

.subtreeSystemUiVisibility以及LayoutParams.sytemUiVisibility两个字段进入WMS.

     WindowManagerService.java
     
             public int relayoutWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int requestedWidth,
                int requestedHeight, int viewVisibility, int flags,
                Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
                Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
                Configuration outConfig, Surface outSurface) {
                
                .................
                
                   synchronized(mWindowMap) {
                WindowState win = windowForClientLocked(session, client, false);
                if (win == null) {
                    return 0;
                }
     
                WindowStateAnimator winAnimator = win.mWinAnimator;
                if (viewVisibility != View.GONE) {
                    win.setRequestedSize(requestedWidth, requestedHeight);
                }
     
                int attrChanges = 0;
                int flagChanges = 0;
                if (attrs != null) {
                    mPolicy.adjustWindowParamsLw(attrs);
                    // if they don't have the permission, mask out the status bar bits
                    if (seq == win.mSeq) {
                        int systemUiVisibility = attrs.systemUiVisibility
                                | attrs.subtreeSystemUiVisibility;
                        if ((systemUiVisibility & DISABLE_MASK) != 0) {
                            if (!hasStatusBarPermission) {
                                systemUiVisibility &= ~DISABLE_MASK;
                            }
                        }
                        //保存到WindowState.mSystemUiVisibility
                        win.mSystemUiVisibility = systemUiVisibility;
                    }
                    if (win.mAttrs.type != attrs.type) {
                        throw new IllegalArgumentException(
                                "Window type can not be changed after the window is added.");
                    }
                
                ........
                }

        在此,PhoneWindowManager能够经过WindowState.getSystemUiVisibility获取这一信息并据此对窗口进行布局,或设置状态栏与导航栏的可见性。  

相关文章
相关标签/搜索