WMS->窗口管理statusbar和navbar管理

要想读懂窗口布局管理,必须了解status bar 和nav bar ,要了解这两个bar 更要了解相关的flags,下面就会这些flags做一些说明

View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR  //高亮状态栏

View.STATUS_BAR_TRANSLUCENT //半透明状态栏
View.STATUS_BAR_TRANSPARENT //透明状态栏,一般指定WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS系统会设置成全透明

View.SYSTEM_UI_FLAG_FULLSCREEN // 全屏显示,隐藏状态栏和状态栏
View.STATUS_BAR_UNHIDE     // 显示状态栏,用于传递给systemui处理

View.NAVIGATION_BAR_TRANSPARENT //半透明导航栏
View.NAVIGATION_BAR_TRANSLUCENT //透明导航栏,一般指定WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS系统会设置成全透明

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // 隐藏导航栏
View.NAVIGATION_BAR_UNHIDE      // 显示状态栏,传递给systemui处理

View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY //身临其境的感觉,和SYSTEM_UI_FLAG_LIGHT_STATUS_BAR一起使用会隐藏状态栏和导航栏,从上面/下面滑出状态栏和导航栏,过几秒自动消失
View.SYSTEM_UI_FLAG_IMMERSIVE //身临其境的感觉,自动隐藏状态栏和导航栏,出上部/下部滑动状态栏出现,不自动隐藏


View.STATUS_BAR_TRANSIENT  //进入瞬态,状态栏出来和隐藏的过程
View.NAVIGATION_BAR_TRANSIENT //进入瞬态,导航栏出来和隐藏的过程



WindowManager.LayoutParams.FLAG_FULLSCREEN //全屏显示,隐藏状态栏
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS //导航栏状态栏透明,客户端渲染状态栏导航栏背景
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND //强制导航栏状态栏透明,客户端渲染状态栏导航栏背景
WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR  //当此窗口到达顶部的时候保持前一个窗口的透明状态

WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS //指定半透明status bar 
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION //指定半透明nav bar 

WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND 强制渲染背景色

下面这几个状态用于status bar 和nav bar 切换时候的瞬态过程
private static final int TRANSIENT_BAR_NONE = 0; //无任何状态,当隐藏完成时候设置
private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1; // 请求显示
private static final int TRANSIENT_BAR_SHOWING = 2; //正在显示的过程
private static final int TRANSIENT_BAR_HIDING = 3; //正在隐藏的过程,隐藏完成window变成不可见,设置TRANSIENT_BAR_NONE

还要记住,分屏模式不允许隐藏bar

另外管理的还要注意几个状态,包括状态栏展开,锁屏和锁屏被阻断,以及正常的全屏activity在前台的几种情况。
状态栏管理在wms这端的核心函数是PhoneWindowManager中的updateSystemUiVisibilityLw()函数

private int updateSystemUiVisibilityLw() {
        // If there is no window focused, there will be nobody to handle the events
        // anyway, so just hang on in whatever state we're in until things settle down.
        //1 获取焦点的window也就是能接收input事件的window
        WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
                : mTopFullscreenOpaqueWindowState;
        if (winCandidate == null) {
            return 0;
        }
        //2 如果当前焦点的window是ImmersiveModeConfirmation弹出的window不做处理,直接返回
        if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
            // The immersive mode confirmation should never affect the system bar visibility,
            // otherwise it will unhide the navigation bar and hide itself.
            winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
            if (winCandidate == null) {
                return 0;
            }
        }
        final WindowState win = winCandidate;
        //3 焦点window是keygurd,但是keygurd被阻断,不处理直接返回
        if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
            // We are updating at a point where the keyguard has gotten
            // focus, but we were last in a state where the top window is
            // hiding it.  This is probably because the keyguard as been
            // shown while the top window was displayed, so we want to ignore
            // it here because this is just a very transient change and it
            // will quickly lose focus once it correctly gets hidden.
            return 0;
        }
        //4 获取win的标志,处理rest flags
        int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
                & ~mResettingSystemUiFlags
                & ~mForceClearedSystemUiFlags;
        if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
            tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
        }
        //5 根据当前状态处理SYSTEM_UI_FLAG_LIGHT_STATUS_BAR标志(也就是status bar高亮状态)
        final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
                mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
        //6 导航栏高亮状态处理
        final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
                mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
        //7 获取home stack和dock stack的大小
        mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
        mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
        //8 更新status bar 的属性
        final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
        final int diff = visibility ^ mLastSystemUiFlags;
        final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
        final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
        //9 更新各属性
        final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
        if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
                && mFocusedApp == win.getAppToken()
                && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
                && mLastDockedStackBounds.equals(mDockedStackBounds)) {
            return 0;
        }
        mLastSystemUiFlags = visibility;
        mLastFullscreenStackSysUiFlags = fullscreenVisibility;
        mLastDockedStackSysUiFlags = dockedVisibility;
        mLastFocusNeedsMenu = needsMenu;
        mFocusedApp = win.getAppToken();
        final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
        final Rect dockedStackBounds = new Rect(mDockedStackBounds);
        //10请求StatusBarManager处理(最终请求status bar 处理)
        mHandler.post(new Runnable() {
                @Override
                public void run() {
                    StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
                    if (statusbar != null) {
                        statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
                                dockedVisibility, 0xffffffff, fullscreenStackBounds,
                                dockedStackBounds, win.toString());
                        statusbar.topAppWindowChanged(needsMenu);
                    }
                }
            });
        return diff;
    }

我们这里对以上10个步骤进行解释
1获取候选的window,也就是接收事件的window,这里可能有集中情况
(1)status bar 被展开或者keygurd的情况statusbar window是焦点的window
(2) 在分屏状态下,接收事件的那个window
(3) 在没有分屏状态下全屏的activity就是焦点
对于这里选择的候选window,默认以焦点为主,没有焦点时则使用mTopFullscreenOpaqueWindowState作为候选window,候选window用于使用它的flags处理系统bar的状态。 如果没有找到候选window 就直接返回。这里解释下mTopFullscreenOpaqueWindowState代表在full workspace stack上的activity
2 这里处理的情况是当前的焦点window 是如下这个window
这里写图片描述
当处于身临其境的模式,也就是设置了View.SYSTEM_UI_FLAG_IMMERSIVE |View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION标志的时候,防止用户恐慌,提示如何划出状态栏导航栏,这种状态不需要处理状态栏属性,直接等到用户退出帮助页面后再去操作
3 当有一个window设置了WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED标志的时候这个界面会在锁屏上面显示,这时候mHideLockScreen为真,注意这个标志在8.0里面改了这变量名,其实是一样的。这种情况马上焦点window就不是keygurd了,这只是焦点窗口切换的中间状态,这种情况直接不处理,等状态变了后再去处理
4 PolicyControl.getSystemUiVisibility(win, null)函数我们暂时怎为是直接获取到win的systemUiVisibility变量所描述的关于该window设置的systemui的一些flags。
另外对于mResettingSystemUiFlags的解释,当设置了View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_FULLSCREEN这连个标志而没有设置IMMERSIVE相关标志的时候,会隐藏掉状态栏和导航栏,这时候要求点击屏幕任意地方,状态栏和导航栏都出出来,这个功能的实现是创建一个全屏的事件消费者去接收屏幕点击事件,当用户点击后这个事件消费者会处理事件,事件消费者注册的地方是在PhoneWindowManager的beginLayoutLw()函数中,事件的处理是在PhoneWindowManager的内部类HideNavInputEventReceiver的onInputEvent()方法中,读者不妨自己去读一下,主要是通过给mResettingSystemUiFlags设置View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN 这三个标志,使status bar 出现来实现的。这个过程我们最后用一个情景栈去分析.
5 第五步是最终要的一步,前面的步骤都,用于更新systemui的一些标志,由于函数比较长,我们稍后分析.
6 在一些场景下要对高亮标志进行修正,我们这里只拿statusbar 作为例子说明

  private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
        WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
                ? mStatusBar
                : opaqueOrDimming;

        if (statusColorWin != null) {
            if (statusColorWin == opaque) {
                // If the top fullscreen-or-dimming window is also the top fullscreen, respect
                // its light flag.
                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
                vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
                        & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
            } else if (statusColorWin != null && statusColorWin.isDimming()) {
                // Otherwise if it's dimming, clear the light flag.
                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
            }
        }
        return vis;
    }

代码很简单,首先选择statusColorWin,规则是如果是keygurd且不被其他window覆盖则选择statusbar 作为statusColorWin,否则就是使用参数opaqueOrDimming(放在full stack中的), 当statusColorWin为opaque的window的时候(也就是full stack中不透明的window),这时候状态栏的高亮状态由opaque window决定. 如果不是full stack中的opaque window 则由window自身的Dimming状态决定
7 获取Home stack 和docker stack的大小保存在mNonDockedStackBounds,mDockedStackBounds变量中
8,9 更新我们计算好的systemui相关的属性
10请求StatusBarManager处理(最终请求Systemui 处理)

这里第五条和第十条我们分别展开说明
首先第五步骤更新systemuiFlags的过程,这个过程主要参考焦点window,mTopFullscreenOpaqueWindowState和mTopDockedOpaqueWindowState去计算bar的属性

private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
        final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID);
        final boolean freeformStackVisible =
                mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID);
        final boolean resizing = mWindowManagerInternal.isDockedDividerResizing();

        // We need to force system bars when the docked stack is visible, when the freeform stack
        // is visible but also when we are resizing for the transitions when docked stack
        // visibility changes.
        //1 判断是否强制显示system bar
        mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
        final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;

        //2 计算fullscreenTransWin用于计算bar 的透明情况
        // apply translucent bar vis flags
        WindowState fullscreenTransWin = isStatusBarKeyguard() && !mHideLockScreen
                ? mStatusBar
                : mTopFullscreenOpaqueWindowState;
        //3 计算状态栏透明flags
        vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
        //4 计算导航栏透明情况
        vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
        //5 计算docker导航栏透明度
        final int dockedVis = mStatusBarController.applyTranslucentFlagLw(
                mTopDockedOpaqueWindowState, 0, 0);
    //6 根据mTopFullscreenOpaqueWindowState计算fullscreen stack的FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS标志
        final boolean fullscreenDrawsStatusBarBackground =
                (drawsSystemBarBackground(mTopFullscreenOpaqueWindowState)
                        && (vis & View.STATUS_BAR_TRANSLUCENT) == 0)
                || forcesDrawStatusBarBackground(mTopFullscreenOpaqueWindowState);
       //7 根据dockedDrawsStatusBarBackground计算docker stack的FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS标志
        final boolean dockedDrawsStatusBarBackground =
                (drawsSystemBarBackground(mTopDockedOpaqueWindowState)
                        && (dockedVis & View.STATUS_BAR_TRANSLUCENT) == 0)
                || forcesDrawStatusBarBackground(mTopDockedOpaqueWindowState);

        // prevent status bar interaction from clearing certain flags
        int type = win.getAttrs().type;
        boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
        //8 根据status 是否展开清除一些属性
        if (statusBarHasFocus && !isStatusBarKeyguard()) {
            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
            if (mHideLockScreen) {
                flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
            }
            vis = (vis & ~flags) | (oldVis & flags);
        }
        //9 根据FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS设置一些属性
        if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
            vis |= View.STATUS_BAR_TRANSPARENT;
            vis &= ~View.STATUS_BAR_TRANSLUCENT;
        } else if ((!areTranslucentBarsAllowed() && fullscreenTransWin != mStatusBar)
                || forceOpaqueStatusBar) {
            vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
        }
        //10 设置导航栏的透明度                                           
        vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);

        // update status bar
        boolean immersiveSticky =
                (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
        final boolean hideStatusBarWM =
                mTopFullscreenOpaqueWindowState != null
                && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
                        & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
        final boolean hideStatusBarSysui =
                (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
        final boolean hideNavBarSysui =
                (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;

        final boolean transientStatusBarAllowed = mStatusBar != null
                && (statusBarHasFocus || (!mForceShowSystemBars
                        && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));

        final boolean transientNavBarAllowed = mNavigationBar != null
                && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
        //11 根据用户是否进入恐慌状态显示bar 
        final long now = SystemClock.uptimeMillis();
        final boolean pendingPanic = mPendingPanicGestureUptime != 0
                && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
        if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard() && mKeyguardDrawComplete) {
            // The user performed the panic gesture recently, we're about to hide the bars,
            // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
            mPendingPanicGestureUptime = 0;
            mStatusBarController.showTransient();
            if (!isNavBarEmpty(vis)) {
                mNavigationBarController.showTransient();
            }
        }

        final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
                && !transientStatusBarAllowed && hideStatusBarSysui;
        final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
                && !transientNavBarAllowed;
        //12 不能隐藏bar 设置flags
        if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
            // clear the clearable flags instead
            clearClearableFlagsLw();
            vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
        }

        final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
        immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
        final boolean navAllowedHidden = immersive || immersiveSticky;
        //13 根据window类型显示导航栏
        if (hideNavBarSysui && !navAllowedHidden && windowTypeToLayerLw(win.getBaseType())
                > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
            // We can't hide the navbar from this window otherwise the input consumer would not get
            // the input events.
            vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        }
        //14 更新status bar 可见性
        vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);

        // update navigation bar
        boolean oldImmersiveMode = isImmersiveMode(oldVis);
        boolean newImmersiveMode = isImmersiveMode(vis);
        //15 身临其境状态发生变化,处理
        if (win != null && oldImmersiveMode != newImmersiveMode) {
            final String pkg = win.getOwningPackage();
            mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
                    isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()));
        }
        //16 更系导航栏可见性
        vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);

        return vis;
    }

1 判断是否强制显示system bar ,当freedom stack和docker stack存在或者正在拖拽改变大小的情况,强制显示system bar
2 计算fullscreenTransWin用于计算bar 的透明情况,这里可以看出来总是以statusbar window 和mTopFullscreenOpaqueWindowState计算全局的bar 状态
3 使用fullscreenTransWin计算状态栏透明标志

  public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
        if (mWin != null) {
            if (win != null && (win.getAttrs().privateFlags
                    & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
                int fl = PolicyControl.getWindowFlags(win, null);
                if ((fl & mTranslucentWmFlag) != 0) {
                    vis |= mTranslucentFlag;
                } else {
                    vis &= ~mTranslucentFlag;
                }
                if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
                    vis |= mTransparentFlag;
                } else {
                    vis &= ~mTransparentFlag;
                }
            } else {
                vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
                vis = (vis & ~mTransparentFlag) | (oldVis & mTransparentFlag);
            }
        }
        return vis;
    }

这里如果PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR标志被设置则继承之前的标志,对于status bar 这里主要根据WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS设置View.STATUS_BAR_TRANSLUCENT(看来是为了兼容老版本) ,根据WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS设置View.STATUS_BAR_TRANSPARENT状态. 一个代表半透明,一个代表透明.

4 计算导航栏透明情况,这里和3是很相似的就不去介绍了
5 计算docker导航栏透明度
6 根据mTopFullscreenOpaqueWindowState 和FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS标志计算fullscreen stack是否允许客户端自己绘制状态栏的颜色,这里可以看出如果设置了状态栏半透明,是不允许客户端绘制状态栏颜色的,注意客户端如果设置了WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS就会设置View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,这时候状态栏就应该隐藏,所以不需要使用客户端渲染状态栏背景色. 除非客户端强制渲染背景色,也就是PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND标志成立
7 和6类似,只不过是计算docker stack的状态
8 如果当前status bar 获取焦点,要去掉一些标志

 int type = win.getAttrs().type;
        boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
        if (statusBarHasFocus && !isStatusBarKeyguard()) {
            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
            if (mHideLockScreen) {
                flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
            }
            vis = (vis & ~flags) | (oldVis & flags);
        }

这里可以看出,对于这些标志不做更改,还是使用之前的标志.所以status bar 设置这些标志是不生效的.
9 在步骤6中计算出来docker stack和full stack是否需要使用客户端渲染status bar 背景色,如果二者都需要客户端渲染背景色,设置状态栏背景为透明的,去掉办透明的设置,如果status bar 只能设置为不透明的话,其掉View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT标志. 所以记住这里View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT是有可能并存的
10 设置导航栏的透明度

    private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
            boolean freeformStackVisible, boolean isDockedDividerResizing) {
        if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
            if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
                visibility = setNavBarOpaqueFlag(visibility);
            }
        } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
            if (isDockedDividerResizing) {
                visibility = setNavBarOpaqueFlag(visibility);
            } else if (freeformStackVisible) {
                visibility = setNavBarTranslucentFlag(visibility);
            } else {
                visibility = setNavBarOpaqueFlag(visibility);
            }
        }

        if (!areTranslucentBarsAllowed()) {
            visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
        }
        return visibility;
    }

这里主要根据一些配置的属性设置导航兰透明情况
11 根据用户是否进入恐慌状态显示bar

      boolean immersiveSticky =
                (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
        final boolean hideStatusBarWM =
                mTopFullscreenOpaqueWindowState != null
                && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
                        & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
        final boolean hideStatusBarSysui =
                (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
        final boolean hideNavBarSysui =
                (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;

        final boolean transientStatusBarAllowed = mStatusBar != null
                && (statusBarHasFocus || (!mForceShowSystemBars
                        && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));

        final boolean transientNavBarAllowed = mNavigationBar != null
                && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;

介绍11 之前先看看这些变量的含义. SYSTEM_UI_FLAG_IMMERSIVE_STICKY标志的含义我们最开始已经看到了,hideStatusBarWM代表full stack中不透明的window是否设置了FLAG_FULLSCREEN标志,用于隐藏状态栏
hideStatusBarSysui代表full stack中不透明的window是否设置了SYSTEM_UI_FLAG_FULLSCREEN,用于隐藏状态栏
hideNavBarSysui代表是否要隐藏导航栏目,通过View.SYSTEM_UI_FLAG_HIDE_NAVIGATION标志确定
transientStatusBarAllowed代表status bar 是否允许进入到顺态,也就是从隐藏到显示的一个切换状态. 这里有一下几种情况可以进入瞬态

  • 1 status bar 为焦点window
  • 2不强制显示status bar 并且设置了WindowManager.LayoutParams.FLAG_FULLSCREEN标志
  • 3不强制显示status bar 并且设置了View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN

看来2和3标志所产生的效果是一样的
在来看11,当用户5s内连续按power键,先熄灭屏幕,再点亮屏幕,有可能是由于状态看和导航来都关闭了,引起用户的恐慌,这里如果发现是这种情况,使状态栏和导航栏进入舜态,从屏幕两端移出来,showTransient()函数我们一会分析,这里注意引起恐慌的还是应该为导航栏不可见,如果导航兰可见也不会使状态栏进入舜态,另外11这种情况不会管transientStatusBarAllowed和transientNavBarAllowed条件是否成立

12 不能隐藏bar 设置flags

 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
                && !transientStatusBarAllowed && hideStatusBarSysui;
        final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
                && !transientNavBarAllowed;

这里前面计算了两个变量,如果已经请求了进入瞬态,或者允许进入瞬态,这两种情况都不为真,就不允许进入瞬态,就会设置denyTransientStatus,denyTransientNav,不能进入瞬态,要设置mResettingSystemUiFlags|=SYSTEM_UI_CLEARABLE_FLAGS,通知客户端清除这些标志,然后也清除我们要通知给systemui的这些标志

13 不允许隐藏状态栏,清除View.SYSTEM_UI_FLAG_HIDE_NAVIGATION标志
14 更新状态栏显示状态mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);我们一会分析
15 View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 标志发生变化,使用 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()))更新状态,mImmersiveModeConfirmation只是用于控制下面window的显示
这里写图片描述

16 mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis)更新状态栏显示状态

到这里看完了全局visible的更新,我们就来看下StatusBarController的使用,目前位置我们基本上遇到的就两个函数
1mStatusBarController.showTransient(); 使请求status bar 进入瞬态
2 mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis) 更新显示状态

 public void showTransient() {
        if (mWin != null) {
            setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
        }
    }
       private void setTransientBarState(int state) {
        if (mWin != null && state != mTransientBarState) {
            if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
                mLastTranslucent = SystemClock.uptimeMillis();
            }
            mTransientBarState = state;
            if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
        }
    }

函数很简单,只是把mTransientBarState设置为TRANSIENT_BAR_SHOW_REQUESTED状态,表示请求瞬态

再来看下updateVisibilityLw函数

 public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
        //1 status bar 对应的window不存在,直接返回
        if (mWin == null) return vis;
        //2 需要进入舜态的处理
        if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
            if (transientAllowed) { //3 允许进入瞬态
                vis |= mTransientFlag; //4 设置View.STATUS_BAR_TRANSIENT状态表示进入瞬态
                if ((oldVis & mTransientFlag) == 0) { 
                //5首次设置View.STATUS_BAR_TRANSIENT告诉systemui 
                //准备好了显示,设置View.STATUS_BAR_UNHIDE标志
                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
                }
                //6 更新为TRANSIENT_BAR_SHOWING状态
                setTransientBarState(TRANSIENT_BAR_SHOWING);  // request accepted
            } else {
                //7 不允许进入瞬态,设置为TRANSIENT_BAR_NONE状态
                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
            }
        }
        if (mShowTransparent) { //8 设置status bar 可见,注意这里不一定是瞬态的
            vis |= mTransparentFlag;
            if (mSetUnHideFlagWhenNextTransparent) {
                vis |= mUnhideFlag;
                mSetUnHideFlagWhenNextTransparent = false;
            }
        }
        if (mTransientBarState != TRANSIENT_BAR_NONE) { //9 如果状态不是NONE不允许LOW_PROFILE(淡化)模式显示
            vis |= mTransientFlag;  // ignore clear requests until transition completes
            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
        }
        //10 更新最后不是半透明的时间
        if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
                ((vis | oldVis) & mTransparentFlag) != 0) {
            mLastTranslucent = SystemClock.uptimeMillis();
        }
        return vis;
    }

准备了这么多标志,最终都是要作用在客户端和System ui上,我们这里就看看如何通知给system ui

statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
dockedVisibility, 0xffffffff, fullscreenStackBounds,
dockedStackBounds, win.toString());
statusbar.topAppWindowChanged(needsMenu);
该方法在StatusBarManagerService中实现

    private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
            Rect fullscreenBounds, Rect dockedBounds, String cause) {
        // also allows calls from window manager which is in this process.
        //1 检查权限
        enforceStatusBarService();

        if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");

        synchronized (mLock) {
            //2 更新SystemUI 
            updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
                    fullscreenBounds, dockedBounds);
            //3 更新system ui disable 状态(DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
            //| DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
           // | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
           // | DISABLE_SEARCH;) 我们不关心这些不作分析
            disableLocked(
                    mCurrentUserId,
                    vis & StatusBarManager.DISABLE_MASK,
                    mSysUiVisToken,
                    cause, 1);
        }
    }
     private void updateUiVisibilityLocked(final int vis,
            final int fullscreenStackVis, final int dockedStackVis, final int mask,
            final Rect fullscreenBounds, final Rect dockedBounds) {
        //1 判断状态是否发生变化
        if (mSystemUiVisibility != vis
                || mFullscreenStackSysUiVisibility != fullscreenStackVis
                || mDockedStackSysUiVisibility != dockedStackVis
                || !mFullscreenStackBounds.equals(fullscreenBounds)
                || !mDockedStackBounds.equals(dockedBounds)) {
            //2 记录最终状态,方便下一次比较状态是否发生变化
            mSystemUiVisibility = vis;
            mFullscreenStackSysUiVisibility = fullscreenStackVis;
            mDockedStackSysUiVisibility = dockedStackVis;
            mFullscreenStackBounds.set(fullscreenBounds);
            mDockedStackBounds.set(dockedBounds);
            mHandler.post(new Runnable() {
                    public void run() {
                        if (mBar != null) {
                            try {
                                //3 通知systemui 状态变化
                                mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
                                        mask, fullscreenBounds, dockedBounds);
                            } catch (RemoteException ex) {
                            }
                        }
                    }
                });
        }
    }

函数有七个参数,其中
vis表示计算出来的全局的bar的flags,fullscreenStackVis表示full stactk决定的SYSTEM_UI_FLAG_LIGHT_STATUS_BAR状态
dockedStackVis则表示dock stack的SYSTEM_UI_FLAG_LIGHT_STATUS_BAR状态
Rect fullscreenBounds, Rect dockedBounds分别表示full stack大小和docker stack大小
函数在上面代码的注释中已经分析清楚,我们重点来看Systemui 中的处理

mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
                                        mask, fullscreenBounds, dockedBounds);

函数在SystemUI的PhoneStatusBar中,8.0这个类已经去掉,在哪我没有看,这里参数和StatusBarManagerService类中的同名函数几乎是一致的,这里不再详细说明

 @Override // CommandQueue
    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
        //1 只计算mask影响的位的变化
        final int oldVal = mSystemUiVisibility;
        final int newVal = (oldVal&~mask) | (vis&mask);
        final int diff = newVal ^ oldVal;
        if (DEBUG) Log.d(TAG, String.format(
                "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
                Integer.toHexString(vis), Integer.toHexString(mask),
                Integer.toHexString(oldVal), Integer.toHexString(newVal),
                Integer.toHexString(diff)));
        boolean sbModeChanged = false;
        if (diff != 0) {//2 发生变化做处理
            //3 更新标志
            mSystemUiVisibility = newVal;

            //3 更新low profile的状态,其实就是更新id为notification_lights_out的view的alpha
            // update low profile
            if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
                setAreThereNotifications();
            }

            // ready to unhide
            //4 设置STATUS_BAR_UNHIDE标志
            if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
                mNoAnimationOnNextBarModeChange = true;
            }
            //5计算bar显示的属性
            // update status bar mode
            final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
                    View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,
                    View.STATUS_BAR_TRANSPARENT);

            //6 计算导航栏模式
            // update navigation bar mode
            final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
                    oldVal, newVal, mNavigationBarView.getBarTransitions(),
                    View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
                    View.NAVIGATION_BAR_TRANSPARENT);
            sbModeChanged = sbMode != -1;
            final boolean nbModeChanged = nbMode != -1;
            boolean checkBarModes = false;
            //7 更新status bar 模式
            if (sbModeChanged && sbMode != mStatusBarMode) {
                mStatusBarMode = sbMode;
                checkBarModes = true;
            }
            //8 跟新nav bar 模式
            if (nbModeChanged && nbMode != mNavigationBarMode) {
                mNavigationBarMode = nbMode;
                checkBarModes = true;
            }
            //9 导航栏或者状态栏模式发生变化,切换模式
            if (checkBarModes) {
                checkBarModes();
            }
            //10 模式发生变化
            if (sbModeChanged || nbModeChanged) {
                // update transient bar autohide
                if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
                    //11 三秒后移动隐藏
                    scheduleAutohide();
                } else {
                    //12 取消自动隐藏
                    cancelAutohide();
                }
            }

            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
            }
            //13 通知状态栏状态发生变化
            // send updated sysui visibility to window manager
            notifyUiVisibilityChanged(mSystemUiVisibility);
        }

        mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
                mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
    }

5 计算bar 显示的属性

 private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
        int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
        return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
                : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
                : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
                : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
                : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
                : MODE_OPAQUE;
    }

这里主要有五个属性
1 MODE_SEMI_TRANSPARENT由不显示到显示的过程中,这种是完全透明的status bar ,不影响应用的content显示
2 MODE_TRANSLUCENT 半透明的,这种应该隐藏状态栏
3 View.SYSTEM_UI_FLAG_LOW_PROFILE | View.STATUS_BAR_TRANSPARENT 低亮度但是状态栏透明,客户端渲染颜色,这种情况并不覆盖在应用的content上
4 MODE_TRANSPARENT 透明,客户端渲染背景
5 MODE_LIGHTS_OUT 低亮
6 不透明

知道这些后systemui 这边的设计也非常简单的理解了. 那么我们再来看看 notifyUiVisibilityChanged(mSystemUiVisibility);通知给WMS后会做什么
在WindowManagerService中的statusBarVisibilityChanged函数中处理

 @Override
    public void statusBarVisibilityChanged(int visibility) {
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Caller does not hold permission "
                    + android.Manifest.permission.STATUS_BAR);
        }

        synchronized (mWindowMap) {
            //1 更新最终状态
            mLastStatusBarVisibility = visibility;
            //2 计算PhoneWindowMananger中的状态
            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
            //3 更新客户端状态
            updateStatusBarVisibilityLocked(visibility);
        }
    }

我们就来按照上面三步去分析
步骤1很简单就不说了
2 PhoneWindowMananger->adjustSystemUiVisibilityLw

 @Override
    public int adjustSystemUiVisibilityLw(int visibility) {
        //1 更新status bar 属性
        mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
        mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);

        // Reset any bits in mForceClearingStatusBarVisibility that
        // are now clear.
        mResettingSystemUiFlags &= visibility;
        // Clear any bits in the new visibility that are currently being
        // force cleared, before reporting it.
        //3 清除visibility中包含的mResettingSystemUiFlags|mForceClearedSystemUiFlags属性
        return visibility & ~mResettingSystemUiFlags
                & ~mForceClearedSystemUiFlags;
    }
  • 1 adjustSystemUiVisibilityLw 这个函数只是向status bar的另一个状态切换,请参考最前面说明的瞬态状态
  • 2 清除已经设置好的mResettingSystemUiFlags中的标志
  • 3 清除那些无用要清除的标志返回

    3 WindowManagerService->updateStatusBarVisibilityLocked(visibility)函数

 boolean updateStatusBarVisibilityLocked(int visibility) {
        //1 没有变化直接返回
        if (mLastDispatchedSystemUiVisibility == visibility) {
            return false;
        }
        //2 变化的标志
        final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
                // We are only interested in differences of one of the
                // clearable flags...
                & View.SYSTEM_UI_CLEARABLE_FLAGS
                // ...if it has actually been cleared.
                & ~visibility;

        mLastDispatchedSystemUiVisibility = visibility;
        mInputManager.setSystemUiVisibility(visibility);
        //3 获取主屏幕上的window 
        final WindowList windows = getDefaultWindowListLocked();
        final int N = windows.size();
        for (int i = 0; i < N; i++) {
            WindowState ws = windows.get(i);
            try {
                int curValue = ws.mSystemUiVisibility;
                int diff = (curValue ^ visibility) & globalDiff;
                int newValue = (curValue&~diff) | (visibility&diff);
                if (newValue != curValue) {
                    ws.mSeq++;
                    ws.mSystemUiVisibility = newValue;
                }
                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
                    //4 标志发生变化,通知客户端变化
                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
                            visibility, newValue, diff);
                }
            } catch (RemoteException e) {
                // so sorry
            }
        }
        return true;
    }

函数也很简单,我们直接看客户端如何处理,客户端的处理在
ViewRootImpl的 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj)函数中完成

 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
        if (mSeq != args.seq) {
            // The sequence has changed, so we need to update our value and make
            // sure to do a traversal afterward so the window manager is given our
            // most recent data.
            //1 更新seq,注意当systemflags变化的时候seq值会加1
            mSeq = args.seq;
            //2 设置mForceReportNewAttributes就会触发reLayoutWindow函数请求WMS重新layout
            mAttachInfo.mForceReportNewAttributes = true;
            //3 请求遍历
            scheduleTraversals();
        }
        //4 decor view 不存在直接返回
        if (mView == null) return;
        if (args.localChanges != 0) {
            //5 localChanges发生了变化,更新systemuiVisibility属性
            mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
        }
        //6 SYSTEM_UI_CLEARABLE_FLAGS包含的三个属性变化,通知注册的监听者
        int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
        if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
            mAttachInfo.mGlobalSystemUiVisibility = visibility;
            mView.dispatchSystemUiVisibilityChanged(visibility);
        }
    }

我们这里只看第五步,这里是针对DecorView设置的

   boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
        int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges);
        if (val != mSystemUiVisibility) {
            setSystemUiVisibility(val);
            return true;
        }
        return false;
    }

调用函数setSystemUiVisibility设置了新的标志,这和我们设置systemui 属性是一样的

 if (isDefaultDisplay) {
                    mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
                    for (int i = windows.size() - 1; i >= 0; i--) {
                        WindowState w = windows.get(i);
                        if (w.mHasSurface) {
                            mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs,
                                    w.mAttachedWindow);
                        }
                    }
                    displayContent.pendingLayoutChanges |=
                            mService.mPolicy.finishPostLayoutPolicyLw();
                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishPostLayoutPolicyLw",
                            displayContent.pendingLayoutChanges);
                }

在每次WMS layout完成之后都会调用PhoneWindowManager的beginPostLayoutPolicyLw,applyPostLayoutPolicyLw和finishPostLayoutPolicyLw三个函数,也是设置mTopFullscreenOpaqueWindowState等变量的位置,我们稍微也分析一下

@Override
    public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
        mTopFullscreenOpaqueWindowState = null; //full stack 不透明window
        mTopFullscreenOpaqueOrDimmingWindowState = null; //full stack不透明或者dimming状态的window
        mTopDockedOpaqueWindowState = null; // docker stack不透明window
        mTopDockedOpaqueOrDimmingWindowState = null; //docker stack不透明或者Dimming 的window
        mAppsToBeHidden.clear(); //即将被隐藏数AppWindowToken集合
        mAppsThatDismissKeyguard.clear();
        mForceStatusBar = false;// FLAG_FORCE_NOT_FULLSCREEN时候强制显示status bar 
        mForceStatusBarFromKeyguard = false; //强制在keygurd上显示status bar 
        mForceStatusBarTransparent = false;//强制status bar 透明
        mForcingShowNavBar = false; //强制显示导航栏
        mForcingShowNavBarLayer = -1; // 强制显示导航栏

        mHideLockScreen = false;// 当window显示在keygurd上,该值为真
        mAllowLockscreenWhenOn = false;//允许亮屏时候锁屏
        mDismissKeyguard = DISMISS_KEYGUARD_NONE; //消除keygurd
        mShowingLockscreen = false;  //keygurd 显示
        mShowingDream = false; //显示在dream模式
        mWinShowWhenLocked = null; //在锁屏上显示的window
        mKeyguardSecure = isKeyguardSecure(mCurrentUserId); //keygurd 需要密码解锁
        mKeyguardSecureIncludingHidden = mKeyguardSecure //需要密码解锁,但是keygurd没显示
                && (mKeyguardDelegate != null && mKeyguardDelegate.isShowing());
    }

beginPostLayoutPolicyLw比较简单,只是初始化上面的一些变量

 /** {@inheritDoc} */
    @Override
    public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
            WindowState attached) {
        if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
                + win.isVisibleOrBehindKeyguardLw());
        final int fl = PolicyControl.getWindowFlags(win, attrs);
        if (mTopFullscreenOpaqueWindowState == null
                && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
            //1 输入法上上面,强制显示nav bar
            mForcingShowNavBar = true;
            mForcingShowNavBarLayer = win.getSurfaceLayer();
        }
        if (attrs.type == TYPE_STATUS_BAR) {
            if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                //2key guran显示.设置强制显示status bar 
                mForceStatusBarFromKeyguard = true;
                mShowingLockscreen = true;
            }
            if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
                //3 强制status bar 透明
                mForceStatusBarTransparent = true;
            }
        }

        boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
                && attrs.type < FIRST_SYSTEM_WINDOW;
        final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
        final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
        final int stackId = win.getStackId();
        //4 可见的或者keygurd后面的窗口
        if (mTopFullscreenOpaqueWindowState == null &&
                win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
            //5 强制非全屏,设置mForceStatusBarFromKeyguard或者mForceStatusBar,其实就是对
            //FLAG_FORCE_NOT_FULLSCREEN标志的处理
            if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
                if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                    mForceStatusBarFromKeyguard = true;
                } else {
                    mForceStatusBar = true;
                }
            }
            if (attrs.type == TYPE_DREAM) {
            //6 window的类型为TYPE_DREAM如果不是在锁屏发生dream或者已经绘制出,设置mShowingDream
                // If the lockscreen was showing when the dream started then wait
                // for the dream to draw before hiding the lockscreen.
                if (!mDreamingLockscreen
                        || (win.isVisibleLw() && win.hasDrawnLw())) {
                    mShowingDream = true;
                    appWindow = true;
                }
            }

            final IApplicationToken appToken = win.getAppToken();

            // For app windows that are not attached, we decide if all windows in the app they
            // represent should be hidden or if we should hide the lockscreen. For attached app
            // windows we defer the decision to the window it is attached to.
            //7 是一个appwindow 并且不是子window
            if (appWindow && attached == null) {
                if (showWhenLocked) {//8 设置了FLAG_SHOW_WHEN_LOCKED标志,可以显示在keygurd上
                    // Remove any previous windows with the same appToken.
                    mAppsToBeHidden.remove(appToken);
                    mAppsThatDismissKeyguard.remove(appToken);
                    if (mAppsToBeHidden.isEmpty()) {
                        if (dismissKeyguard && !mKeyguardSecure) {
                            //9 可以解除锁屏,放在mAppsThatDismissKeyguard处理
                            mAppsThatDismissKeyguard.add(appToken);
                        } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
                            //10 已经绘制出来,设置下面三个变量
                            mWinShowWhenLocked = win;
                            mHideLockScreen = true;
                            mForceStatusBarFromKeyguard = false;
                        }
                    }
                } else if (dismissKeyguard) {//11 设置FLAG_DISMISS_KEYGUARD标志,但是不能显示在keygurd上
                    if (mKeyguardSecure) { 
                    //12需要解锁解除keygurd,放到 mAppsToBeHidden中
                        mAppsToBeHidden.add(appToken);
                    } else {
                        //12不需要解锁,移除
                        mAppsToBeHidden.remove(appToken);
                    }
                    //13 添加到mAppsThatDismissKeyguard中稍后处理
                    mAppsThatDismissKeyguard.add(appToken);
                } else {
                    //14 不能显示,放到mAppsToBeHidden中稍后处理
                    mAppsToBeHidden.add(appToken);
                }
                //15 全屏的window并且放在full stack中,(这里是指full work space stack和home stack)
                if (isFullscreen(attrs) && StackId.normallyFullscreenWindows(stackId)) {
                    if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                    //16 设置mTopFullscreenOpaqueWindowState,设置mTopFullscreenOpaqueOrDimmingWindowState
                    mTopFullscreenOpaqueWindowState = win;
                    if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
                        mTopFullscreenOpaqueOrDimmingWindowState = win;
                    }
                    //17 如果设置FLAG_DISMISS_KEYGUARD标志的window存在,并且现在是锁屏状态
                    if (!mAppsThatDismissKeyguard.isEmpty() &&
                            mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                        if (DEBUG_LAYOUT) Slog.v(TAG,
                                "Setting mDismissKeyguard true by win " + win);
                        //解除keygurd的状态,需要密码为DISMISS_KEYGUARD_CONTINUE,否则为
                        //DISMISS_KEYGUARD_START
                        mDismissKeyguard = (mWinDismissingKeyguard == win
                                && mSecureDismissingKeyguard == mKeyguardSecure)
                                ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                        //1 设置要解除锁屏的activity为win
                        mWinDismissingKeyguard = win;
                        //2 要消除的锁屏状态是需要密码解锁的
                        mSecureDismissingKeyguard = mKeyguardSecure;
                        mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
                            && (win.isDrawnLw() || win.hasAppShownWindows())) {
                        //18 需要显示在keygurd上面的window
                        if (DEBUG_LAYOUT) Slog.v(TAG,
                                "Setting mHideLockScreen to true by win " + win);
                        mHideLockScreen = true;
                        mForceStatusBarFromKeyguard = false;
                    }
                    if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                        //19 允许亮屏时锁屏,60s没操作锁屏,也就是最上面的全屏activity控制
                        mAllowLockscreenWhenOn = true;
                    }
                }
                //20 不允许在锁屏显示hide window
                if (!mKeyguardHidden && mWinShowWhenLocked != null &&
                        mWinShowWhenLocked.getAppToken() != win.getAppToken() &&
                        (attrs.flags & FLAG_SHOW_WHEN_LOCKED) == 0) {
                    win.hideLw(false);
                }
            }
        } else if (mTopFullscreenOpaqueWindowState == null && mWinShowWhenLocked == null) {
            // No TopFullscreenOpaqueWindow is showing, but we found a SHOW_WHEN_LOCKED window
            // that is being hidden in an animation - keep the
            // keyguard hidden until the new window shows up and
            // we know whether to show the keyguard or not.
            //21 没有TopFullscreenOpaqueWindow,但是一个可以在锁屏上显示的window
                //(设置了FLAG_SHOW_WHEN_LOCKED标志),并且之歌window正在执行动画,记录下锁屏状态和
                //mWinShowWhenLocked
            if (win.isAnimatingLw() && appWindow && showWhenLocked && mKeyguardHidden) {
                mHideLockScreen = true;
                mWinShowWhenLocked = win;
            }
        }
        //22 window真的可见
        final boolean reallyVisible = win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw();

        //23 语音助手在所有window之上
        // Voice interaction overrides both top fullscreen and top docked.
        if (reallyVisible && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
            if (mTopFullscreenOpaqueWindowState == null) {
                mTopFullscreenOpaqueWindowState = win;
                if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
                    mTopFullscreenOpaqueOrDimmingWindowState = win;
                }
            }
            if (mTopDockedOpaqueWindowState == null) {
                mTopDockedOpaqueWindowState = win;
                if (mTopDockedOpaqueOrDimmingWindowState == null) {
                    mTopDockedOpaqueOrDimmingWindowState = win;
                }
            }
        }
        //24 如果不存在mTopFullscreenOpaqueOrDimmingWindowState,非全屏的Dimming也可以设置
        // Keep track of the window if it's dimming but not necessarily fullscreen.
        if (mTopFullscreenOpaqueOrDimmingWindowState == null && reallyVisible
                && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) {
            mTopFullscreenOpaqueOrDimmingWindowState = win;
        }

        // We need to keep track of the top "fullscreen" opaque window for the docked stack
        // separately, because both the "real fullscreen" opaque window and the one for the docked
        // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
        //25 设置docker stack的全屏window
        if (mTopDockedOpaqueWindowState == null && reallyVisible && appWindow && attached == null
                && isFullscreen(attrs) && stackId == DOCKED_STACK_ID) {
            mTopDockedOpaqueWindowState = win;
            if (mTopDockedOpaqueOrDimmingWindowState == null) {
                mTopDockedOpaqueOrDimmingWindowState = win;
            }
        }

        // Also keep track of any windows that are dimming but not necessarily fullscreen in the
        // docked stack.
        //26 设置docker stack中的mTopDockedOpaqueOrDimmingWindowState
        if (mTopDockedOpaqueOrDimmingWindowState == null && reallyVisible && win.isDimming()
                && stackId == DOCKED_STACK_ID) {
            mTopDockedOpaqueOrDimmingWindowState = win;
        }
    }

函数不太复杂下面分析finishPostLayoutPolicyLw

   /** {@inheritDoc} */
    @Override
    public int finishPostLayoutPolicyLw() {
        if (mWinShowWhenLocked != null && mTopFullscreenOpaqueWindowState != null &&
                mWinShowWhenLocked.getAppToken() != mTopFullscreenOpaqueWindowState.getAppToken()
                && isKeyguardLocked()) {
            //1 锁屏上有window,并且是不是一个全屏app window的情况,这种情况有可能是是一个透明的dialog,所以
            //添加一个FLAG_SHOW_WALLPAPER标志,强制显示wallPaper,另外使
            //mTopFullscreenOpaqueWindowState隐藏,设置mTopFullscreenOpaqueWindowState为这个window
            //为mTopFullscreenOpaqueWindowState
            // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the
            // fullscreen window.
            // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not.
            mWinShowWhenLocked.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
            mTopFullscreenOpaqueWindowState.hideLw(false);
            mTopFullscreenOpaqueWindowState = mWinShowWhenLocked;
        }

        int changes = 0;
        boolean topIsFullscreen = false;
        //2 获取mTopFullscreenOpaqueWindowState的LayoutParams
        final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
                ? mTopFullscreenOpaqueWindowState.getAttrs()
                : null;

        // If we are not currently showing a dream then remember the current
        // lockscreen state.  We will use this to determine whether the dream
        // started while the lockscreen was showing and remember this state
        // while the dream is showing.
        //3 dream 模式这里先不管
        if (!mShowingDream) {
            mDreamingLockscreen = mShowingLockscreen;
            if (mDreamingSleepTokenNeeded) {
                mDreamingSleepTokenNeeded = false;
                mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
            }
        } else {
            if (!mDreamingSleepTokenNeeded) {
                mDreamingSleepTokenNeeded = true;
                mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
            }
        }

        if (mStatusBar != null) {
            if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
                    + " forcefkg=" + mForceStatusBarFromKeyguard
                    + " top=" + mTopFullscreenOpaqueWindowState);
            boolean shouldBeTransparent = mForceStatusBarTransparent
                    && !mForceStatusBar
                    && !mForceStatusBarFromKeyguard;
            if (!shouldBeTransparent) {
                //3 status bar 不需要透明
                mStatusBarController.setShowTransparent(false /* transparent */);
            } else if (!mStatusBar.isVisibleLw()) {
                //4 强制status bar 透明
                mStatusBarController.setShowTransparent(true /* transparent */);
            }

            WindowManager.LayoutParams statusBarAttrs = mStatusBar.getAttrs();
            //5 status bar 是展开的状态
            boolean statusBarExpanded = statusBarAttrs.height == MATCH_PARENT
                    && statusBarAttrs.width == MATCH_PARENT;
            //6 以下为显示status bar 的状态        
            if (mForceStatusBar /*FLAG_FORCE_NOT_FULLSCREEN*/
            || mForceStatusBarFromKeyguard/*keygurd 显示*/ 
            || mForceStatusBarTransparent /**强制透明/
                    || statusBarExpanded/*status bar 展开*/) {
                if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
                if (mStatusBarController.setBarShowingLw(true)) {
                //7 设置显示status bar ,通知WMS需要重新layout
                    changes |= FINISH_LAYOUT_REDO_LAYOUT;
                }
                // Maintain fullscreen layout until incoming animation is complete.
                //8 保持全屏布局知道动画完成
                topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
                // Transient status bar on the lockscreen is not allowed
                if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
                    //9 在keygurd上 设置不允许进入瞬态
                    mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
                            mLastSystemUiFlags, mLastSystemUiFlags);
                }
                //10 状态栏展开设置导航栏可见
                if (statusBarExpanded && mNavigationBar != null) {
                    if (mNavigationBarController.setBarShowingLw(true)) {
                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
                    }
                }
            } else if (mTopFullscreenOpaqueWindowState != null) {
            //11 mTopFullscreenOpaqueWindowState存在
                final int fl = PolicyControl.getWindowFlags(null, lp);
                if (localLOGV) {
                    Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
                            + " shown position: "
                            + mTopFullscreenOpaqueWindowState.getShownPositionLw());
                    Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
                            + " lp.flags=0x" + Integer.toHexString(fl));
                }
                //12 全屏的mTopFullscreenOpaqueWindowState
                topIsFullscreen = (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
                        || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
                // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
                // case though.
                //13 正在瞬态可见过程中,设置可见
                if (mStatusBarController.isTransientShowing()) {
                    if (mStatusBarController.setBarShowingLw(true)) {
                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
                    }
                } else if (topIsFullscreen
                        && !mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID)
                        && !mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID)) {
                    if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
                    //14 全屏不在瞬态过程中,设置为不可见
                    if (mStatusBarController.setBarShowingLw(false)) {
                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
                    } else {
                        if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
                    }
                } else {
                       //15 非全屏包含分屏窗口,设置为可见
                    if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
                    if (mStatusBarController.setBarShowingLw(true)) {
                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
                    }
                }
            }
        }
        //16 TopIsFullscreen发生变化更新
        if (mTopIsFullscreen != topIsFullscreen) {
            if (!topIsFullscreen) {
                // Force another layout when status bar becomes fully shown.
                changes |= FINISH_LAYOUT_REDO_LAYOUT;
            }
            mTopIsFullscreen = topIsFullscreen;
        }

        // Hide the key guard if a visible window explicitly specifies that it wants to be
        // displayed when the screen is locked.
        if (mKeyguardDelegate != null && mStatusBar != null) {
            if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
                    + mHideLockScreen);
            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardSecure) {
                mKeyguardHidden = true;
                //17 需要关闭keygurd
                if (setKeyguardOccludedLw(true)) {
                    changes |= FINISH_LAYOUT_REDO_LAYOUT
                            | FINISH_LAYOUT_REDO_CONFIG
                            | FINISH_LAYOUT_REDO_WALLPAPER;
                }
                if (mKeyguardDelegate.isShowing()) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mKeyguardDelegate.keyguardDone(false, false);
                        }
                    });
                }
            } else if (mHideLockScreen) { //18 window显示在keygurd上
                mKeyguardHidden = true;
                mWinDismissingKeyguard = null;
                if (setKeyguardOccludedLw(true)) {
                    changes |= FINISH_LAYOUT_REDO_LAYOUT
                            | FINISH_LAYOUT_REDO_CONFIG
                            | FINISH_LAYOUT_REDO_WALLPAPER;
                }
            } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
                mKeyguardHidden = false;
                if (setKeyguardOccludedLw(false)) {
                    changes |= FINISH_LAYOUT_REDO_LAYOUT
                            | FINISH_LAYOUT_REDO_CONFIG
                            | FINISH_LAYOUT_REDO_WALLPAPER;
                }
                if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
                    // Only launch the next keyguard unlock window once per window.
                    //19 结束keygurd
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mKeyguardDelegate.dismiss();
                        }
                    });
                }
            } else {
                //20
                mWinDismissingKeyguard = null;
                mSecureDismissingKeyguard = false;
                mKeyguardHidden = false;

                if (setKeyguardOccludedLw(false)) {
                    changes |= FINISH_LAYOUT_REDO_LAYOUT
                            | FINISH_LAYOUT_REDO_CONFIG
                            | FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }
        }
        //21 更新system ui 属性
        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
            // If the navigation bar has been hidden or shown, we need to do another
            // layout pass to update that window.
            changes |= FINISH_LAYOUT_REDO_LAYOUT;
        }
        //22更新锁屏超时时间
        // update since mAllowLockscreenWhenOn might have changed
        updateLockScreenTimeout();
        return changes;
    }

最后总结一下大概流程是这样的
这里写图片描述

1app客户端请求relayoutWindow
2 WMS处理SystemUI相关的LayoutParams变化,WMS计算好全局SystemUI相关flags,通知SystemUI更新
3 SystemUI更新完成后通知WMS新的systemui flags
4WMS接收到新的标志后通知app客户端systemui布局发生变化,app端更新LayoutParams
5app客户端请求relayoutWindow

最后周而复始知道SystemUI标志不再改变

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
仓库管理系统(WMS)是一种用于管理仓库操作和流程的软件系统。它通过自动化和优化仓库流程,提高了仓库的效率和准确性。 WMS系统可以帮助企业实现对仓库的全面掌控和监管。它提供了实时的库存信息、调度规划、收货、上架、拣货、打包、出货等功能。用户可以通过WMS系统对仓库作业进行统一调度和管理,减少了人为因素对仓库作业的影响。 WMS系统的核心功能包括库存管理和作业管理。库存管理功能包括库存查询、库存调整、库存盘点等,通过对库存信息的准确记录和实时更新,可以避免库存过多或不足的情况。作业管理功能包括入库作业、出库作业、移库作业等,通过对各项作业进行计划、分派和跟踪,提高了作业效率和准确性。 WMS系统还提供了一些高级功能,如货物跟踪、批次管理、质量管理等。货物跟踪功能可以帮助用户实时了解货物的流向和位置,提高了货物配送的准确性。批次管理功能可以对货物进行批次的管理和追溯,方便了企业对产品质量的控制和追踪。质量管理功能可以对货物的质量信息进行记录和追踪,保证了产品质量的可追溯性。 总之,WMS系统是一种能够提高仓库效率、准确性和可控性的管理工具。通过实时监控和跟踪仓库的各项作业和库存信息,可以帮助企业降低成本、提高服务水平,提高了企业的竞争力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值