Android源码笔记--SystemUIVisibility

SystemUIVisibility     

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

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

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

       SystemUIVisibility在系统中存在的地方

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

 1  控件树中的SystemUIVisibility

View.setSystemUiVisibility()的实现

        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);
                }
            }
        }

    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获取这一信息并据此对窗口进行布局,或设置状态栏与导航栏的可见性。
 

转载于:https://my.oschina.net/u/920274/blog/3063436

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值