Android 7.0 SystemUI 状态/导航栏的隐藏与显示

简介: Android 7.0 SystemUI 状态/导航栏的隐藏与显示

平台


Android 7.1 + RK3288


概述


从Android 4.4开始支持沉浸式全屏体验,在沉浸式全屏模式下,状态栏、 虚拟按键动态隐藏,应用可以使用完整的屏幕空间,按照 Google 的说法,给用户一种 “身临其境” 的体验。

增加了 IMMERSIVE 和 IMMERSIVE_STICKY 标记,可以用这两个标记与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 一起使用, 来实现沉 浸模式。


全屏的是通过隐藏状态栏和导航栏实现, 服务之间的交互如下:

image.png


关键函数


frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java


//顾名思义, 状态栏的控制器与导航栏的控制器, 设置显示/隐藏, 或临时显示都需要它
    private final StatusBarController mStatusBarController = new StatusBarController();
    private final BarController mNavigationBarController = new BarController("NavigationBar",
            View.NAVIGATION_BAR_TRANSIENT,
            View.NAVIGATION_BAR_UNHIDE,
            View.NAVIGATION_BAR_TRANSLUCENT,
            StatusBarManager.WINDOW_NAVIGATION_BAR,
            WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
            View.NAVIGATION_BAR_TRANSPARENT);
    //WindowManagerService调用
    @Override
    public int adjustSystemUiVisibilityLw(int visibility) {
                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.
                return visibility & ~mResettingSystemUiFlags
                        & ~mForceClearedSystemUiFlags;
            }
    //更新FLAG用, 比如, 会获取APP的指定FLAG, 再与前面的控制器交互并更新当前的系统FLAG
    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.
            WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
                    : mTopFullscreenOpaqueWindowState;
            if (winCandidate == null) {
                return 0;
            }
            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;
            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;
            }
            int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
                    & ~mResettingSystemUiFlags
                    & ~mForceClearedSystemUiFlags;
            if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
                tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
            }
            final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
                    mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
            final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
                    mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
            mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
            mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
            final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
            final int diff = visibility ^ mLastSystemUiFlags;
            final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
            final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
            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);
            mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
                        if (statusbar != null) {
                            //传递给SystemUI
                            statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
                                    dockedVisibility, 0xffffffff, fullscreenStackBounds,
                                    dockedStackBounds, win.toString());
                            statusbar.topAppWindowChanged(needsMenu);
                        }
                    }
                });
            return diff;
        }
        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;
        }
        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.
            mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
            final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
            // apply translucent bar vis flags
            WindowState fullscreenTransWin = isStatusBarKeyguard() && !mHideLockScreen
                    ? mStatusBar
                    : mTopFullscreenOpaqueWindowState;
            vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
            vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
            final int dockedVis = mStatusBarController.applyTranslucentFlagLw(
                    mTopDockedOpaqueWindowState, 0, 0);
            final boolean fullscreenDrawsStatusBarBackground =
                    (drawsSystemBarBackground(mTopFullscreenOpaqueWindowState)
                            && (vis & View.STATUS_BAR_TRANSLUCENT) == 0)
                    || forcesDrawStatusBarBackground(mTopFullscreenOpaqueWindowState);
            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;
            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);
            }
            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);
            }
            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;
            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;
            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;
            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);
            }
            vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
            // update navigation bar
            boolean oldImmersiveMode = isImmersiveMode(oldVis);
            boolean newImmersiveMode = isImmersiveMode(vis);
            if (win != null && oldImmersiveMode != newImmersiveMode) {
                final String pkg = win.getOwningPackage();
                mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
                        isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()));
            }
            vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
            return vis;
    }


frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java


//SystemUI中处理由PWS传过来的FLAG.
    @Override // CommandQueue
    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
        final int oldVal = mSystemUiVisibility;
        final int newVal = (oldVal&~mask) | (vis&mask);
        final int diff = newVal ^ oldVal;
        if (true) 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) {
            mSystemUiVisibility = newVal;
            // update low profile
            if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
                setAreThereNotifications();
            }
            // ready to unhide
            if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
                mNoAnimationOnNextBarModeChange = true;
            }
            // update status bar mode
            final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
                    View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,
                    View.STATUS_BAR_TRANSPARENT);
            // 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;
            if (sbModeChanged && sbMode != mStatusBarMode) {
                mStatusBarMode = sbMode;
                checkBarModes = true;
            }
            if (nbModeChanged && nbMode != mNavigationBarMode) {
                mNavigationBarMode = nbMode;
                checkBarModes = true;
            }
            if (checkBarModes) {
                checkBarModes();
            }
            if (sbModeChanged || nbModeChanged) {
                // update transient bar autohide
                if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
                    scheduleAutohide();
                } else {
                    cancelAutohide();
                }
            }
            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
            }
            //变更新, 传递新的FLAG给WMS.
            // send updated sysui visibility to window manager
            notifyUiVisibilityChanged(mSystemUiVisibility);
        }
        mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
                mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
    }


frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java


@Override
    public void statusBarVisibilityChanged(int visibility) {
        Log.d(TAG, "statusBarVisibilityChanged 0x" + Integer.toHexString(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) {
            mLastStatusBarVisibility = visibility;
            //mPolicy == PhoneWindowManager
            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
            updateStatusBarVisibilityLocked(visibility);
        }
    }


一些常量


frameworks/base/core/java/android/view/View.java


public static final int STATUS_BAR_UNHIDE     = 0x10000000;
public static final int NAVIGATION_BAR_UNHIDE = 0x20000000;
public static final int STATUS_BAR_TRANSIENT     = 0x04000000;
public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000;
public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
public static final int SYSTEM_UI_FLAG_IMMERSIVE       = 0x00000800;
public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY= 0x00001000;
public static final int NAVIGATION_BAR_TRANSPARENT     = 0x00008000;
public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE          = 0x00000100;
public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN      = 0x00000400;
public static final int STATUS_BAR_TRANSPARENT = 0x0000008;


如前面在PhoneStatusBar中打印statusBarVisibilityChanged 0x的16进制字符串.

如:


image.png


隐藏->显示:

D/PhoneStatusBar: setSystemUiVisibility vis=3c009f0f mask=ffffffff oldVal=9f0f newVal=3c009f0f diff=3c000000


显示->隐藏:

D/PhoneStatusBar: setSystemUiVisibility vis=9f0f mask=ffffffff oldVal=c009f0f newVal=9f0f diff=c000000


一些干货


3秒的自动隐藏时间:

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java


//3秒后自动隐藏
    private static final long AUTOHIDE_TIMEOUT_MS = 3000;
    private void scheduleAutohide() {
        cancelAutohide();
        mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
    }


隐藏/显示动画

首先找出动画是SystemUI自己执行还是由WMS去执行, 答案是WMS, 看下打印出来的堆栈信息:

2021-09-08 18:44:51.850 467-1102/system_process W/System.err:     at com.android.server.wm.WindowStateAnimator.setAnimation(WindowStateAnimator.java:275)
2021-09-08 18:44:51.850 467-1102/system_process W/System.err:     at com.android.server.wm.WindowStateAnimator.setAnimation(WindowStateAnimator.java:296)
2021-09-08 18:44:51.852 467-1102/system_process W/System.err:     at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:1938)
2021-09-08 18:44:51.852 467-1102/system_process W/System.err:     at com.android.server.wm.WindowState.showLw(WindowState.java:1926)
2021-09-08 18:44:51.852 467-1102/system_process W/System.err:     at com.android.server.wm.WindowState.showLw(WindowState.java:1890)
2021-09-08 18:44:51.852 467-1102/system_process W/System.err:     at com.android.server.policy.BarController.setBarShowingLw(BarController.java:151)
2021-09-08 18:44:51.853 467-1102/system_process W/System.err:     at com.android.server.policy.BarController.adjustSystemUiVisibilityLw(BarController.java:116)
2021-09-08 18:44:51.853 467-1102/system_process W/System.err:     at com.android.server.policy.PhoneWindowManager.adjustSystemUiVisibilityLw(PhoneWindowManager.java:4124)
2021-09-08 18:44:51.853 467-1102/system_process W/System.err:     at com.android.server.wm.WindowManagerService.statusBarVisibilityChanged(WindowManagerService.java:10951)


动画资源

函数有对状态栏和导航栏对应进出资源的判断.

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java


/** {@inheritDoc} */
@Override
public int selectAnimationLw(WindowState win, int transit) {
    if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
          + ": transit=" + transit);
    if (win == mStatusBar) {
        boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
        if (transit == TRANSIT_EXIT
                || transit == TRANSIT_HIDE) {
            return isKeyguard ? -1 : R.anim.dock_top_exit;
        } else if (transit == TRANSIT_ENTER
                || transit == TRANSIT_SHOW) {
            return isKeyguard ? -1 : R.anim.dock_top_enter;
        }
    } else if (win == mNavigationBar) {
        if (win.getAttrs().windowAnimations != 0) {
            return 0;
        }
        // This can be on either the bottom or the right or the left.
        if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
            if (transit == TRANSIT_EXIT
                    || transit == TRANSIT_HIDE) {
                if (isKeyguardShowingAndNotOccluded()) {
                    return R.anim.dock_bottom_exit_keyguard;
                } else {
                    return R.anim.dock_bottom_exit;
                }
            } else if (transit == TRANSIT_ENTER
                    || transit == TRANSIT_SHOW) {
                return R.anim.dock_bottom_enter;
            }
        } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
            if (transit == TRANSIT_EXIT
                    || transit == TRANSIT_HIDE) {
                return R.anim.dock_right_exit;
            } else if (transit == TRANSIT_ENTER
                    || transit == TRANSIT_SHOW) {
                return R.anim.dock_right_enter;
            }
        } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
            if (transit == TRANSIT_EXIT
                    || transit == TRANSIT_HIDE) {
                return R.anim.dock_left_exit;
            } else if (transit == TRANSIT_ENTER
                    || transit == TRANSIT_SHOW) {
                return R.anim.dock_left_enter;
            }
        }
    } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
        return selectDockedDividerAnimationLw(win, transit);
    }
    if (transit == TRANSIT_PREVIEW_DONE) {
        if (win.hasAppShownWindows()) {
            if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
            return com.android.internal.R.anim.app_starting_exit;
        }
    } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
            && transit == TRANSIT_ENTER) {
        // Special case: we are animating in a dream, while the keyguard
        // is shown.  We don't want an animation on the dream, because
        // we need it shown immediately with the keyguard animating away
        // to reveal it.
        return -1;
    }
    return 0;
}


在后续一些定制修改中, 强制修改了FLAG让状态栏一直显示.

在全屏应用下, 系统会再次使StatusBar隐藏, 原因在于layout完成后,会再确认顶层应用窗口是否全屏, 并对应设置Window是否显示, 此过程无动画

2021-09-09 18:05:05.679 449-562/system_process W/System.err:     at com.android.server.policy.BarController.updateStateLw(BarController.java:194)
2021-09-09 18:05:05.680 449-562/system_process W/System.err:     at com.android.server.policy.BarController.setBarShowingLw(BarController.java:166)
2021-09-09 18:05:05.680 449-562/system_process W/System.err:     at com.android.server.policy.PhoneWindowManager.finishPostLayoutPolicyLw(PhoneWindowManager.java:5511)
2021-09-09 18:05:05.680 449-562/system_process W/System.err:     at com.android.server.wm.WindowSurfacePlacer.applySurfaceChangesTransaction(WindowSurfacePlacer.java:674)
2021-09-09 18:05:05.680 449-562/system_process W/System.err:     at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementInner(WindowSurfacePlacer.java:320)
2021-09-09 18:05:05.680 449-562/system_process W/System.err:     at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:235)
2021-09-09 18:05:05.680 449-562/system_process W/System.err:     at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:184)


finishPostLayoutPolicyLw中调用setBarShowingLw, 把状态栏隐藏了, 若需保持状态栏一直显示, 需处理这部分代码


mStatusBarController.setBarShowingLw(false);


多使用dumpsys

dumpsys window

//实时查看服务的变量状态
mOrientationSensorEnabled=true
 mOverscanScreen=(0,0) 1920x1080
 mRestrictedOverscanScreen=(0,0) 1920x1080
 mUnrestrictedScreen=(0,0) 1920x1080
 mRestrictedScreen=(0,0) 1920x1080
 mStableFullscreen=(0,0)-(1920,1024)
 mStable=(0,24)-(1920,1024)
 mSystem=(0,0)-(1920,1080)
 mCur=(0,24)-(1920,1080)
 mContent=(0,24)-(1920,1080)
 mVoiceContent=(0,24)-(1920,1080)
 mDock=(0,24)-(1920,1080)
//状态栏被mStatusBarController.setBarShowingLw(false);隐藏时:
Window #7 Window{1633372 u0 StatusBar}:
  mDisplayId=0 stackId=0 mSession=Session{f3c2053 644:u0a10018} mClient=android.os.BinderProxy@236987d
  mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
  mAttrs=WM.LayoutParams{(0,0)(fillx24) taskId=-1 gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600}
  Requested w=1920 h=24 mLayoutSeq=85
  mPolicyVisibility=false mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false
mPermanentlyHidden=false
  mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
  WindowStateAnimator{7a4071f StatusBar}:
    Surface: shown=false layer=161000 alpha=1.0 rect=(0.0,0.0) 1920.0 x 24.0
----------------------------------
//状态栏显示时
Window #5 Window{1633372 u0 StatusBar}:
      mDisplayId=0 stackId=0 mSession=Session{f3c2053 644:u0a10018} mClient=android.os.BinderProxy@236987d
      mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
      mAttrs=WM.LayoutParams{(0,0)(fillx24) taskId=-1 gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600}
      Requested w=1920 h=24 mLayoutSeq=163
      mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
      WindowStateAnimator{7a4071f StatusBar}:
        mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1
        Surface: shown=true layer=161000 alpha=1.0 rect=(0.0,0.0) 1920.0 x 24.0
------------------------------------------------------
//状态栏隐藏动画过程
Window #5 Window{16f510e u0 StatusBar}:
          mDisplayId=0 stackId=0 mSession=Session{5e171f4 632:u0a10018} mClient=android.os.BinderProxy@3e87b09
          mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
          mAttrs=WM.LayoutParams{(0,0)(fillx24) taskId=-1 gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600}
          Requested w=1920 h=24 mLayoutSeq=69
          mPolicyVisibility=true mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false
       mPermanentlyHidden=false
          mHasSurface=true mShownPosition=[0,-4] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
          WindowStateAnimator{2214d2c StatusBar}:
            mAnimating=true mLocalAnimating=true mAnimationIsEntrance=false mAnimation=android.view.animation.AnimationSet@5de858d mStackClip=0
            XForm: has=true hasLocal=true {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, -3.5060544][0.0, 0.0, 1.0]}
            Surface: shown=true layer=161000 alpha=1.0 rect=(0.0,-4.0) 1920.0 x 24.0
            mGlobalScale=1.0 mDsDx=1.0 mDtDx=0.0 mDsDy=0.0 mDtDy=1.0


修改了状态栏FLAG后, 窗口布局(大小/位置)不正确可以看看这个函数, 多打打df, vf, cf …的值

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java


public void layoutWindowLw(WindowState win, WindowState attached, int width, int height) {
    // We've already done the navigation bar and status bar. If the status bar can receive
    // input, we need to layout it again to accomodate for the IME window.
    if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) {
        return;
    }
    final WindowManager.LayoutParams attrs = win.getAttrs();
    final boolean isDefaultDisplay = win.isDefaultDisplay();
    final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
            (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
    if (needsToOffsetInputMethodTarget) {
        if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
        offsetInputMethodWindowLw(mLastInputMethodWindow);
    }
    final int fl = PolicyControl.getWindowFlags(win, attrs);
    final int pfl = attrs.privateFlags;
    final int sim = attrs.softInputMode;
    final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
    final Rect pf = mTmpParentFrame;
    final Rect df = mTmpDisplayFrame;
    final Rect of = mTmpOverscanFrame;
    final Rect cf = mTmpContentFrame;
    final Rect vf = mTmpVisibleFrame;
    final Rect dcf = mTmpDecorFrame;
    final Rect sf = mTmpStableFrame;
    //省略N行代码.....
    if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
        + ": sim=#" + Integer.toHexString(sim)
        + " attach=" + attached + " type=" + attrs.type
        + String.format(" flags=0x%08x", fl)
        + " pf=" + pf.toShortString() + " df=" + df.toShortString()
        + " of=" + of.toShortString()
        + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
        + " dcf=" + dcf.toShortString()
        + " sf=" + sf.toShortString()
        + " osf=" + (osf == null ? "null" : osf.toShortString()));
    win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf);
}


扩展


Android 沉浸式状态栏


相关文章
|
4月前
|
API Android开发 开发者
Android经典实战之用WindowInsetsControllerCompat方便的显示和隐藏状态栏和导航栏
本文介绍 `WindowInsetsControllerCompat` 类,它是 Android 提供的一种现代化工具,用于处理窗口插入如状态栏和导航栏的显示与隐藏。此类位于 `androidx.core.view` 包中,增强了跨不同 Android 版本的兼容性。主要功能包括控制状态栏与导航栏的显示、设置系统窗口行为及调整样式。通过 Kotlin 代码示例展示了如何初始化并使用此类,以及如何设置系统栏的颜色样式。
246 2
|
4月前
|
API Android开发 Kotlin
Android实战经验分享之如何获取状态栏和导航栏的高度
在Android开发中,掌握状态栏和导航栏的高度对于优化UI布局至关重要。本文介绍两种主要方法:一是通过资源名称获取,简单且兼容性好;二是利用WindowInsets,适用于新版Android,准确性高。文中提供了Kotlin代码示例,并对比了两者的优缺点及适用场景。
396 1
|
5月前
|
XML Android开发 数据格式
Android面试题之DialogFragment中隐藏导航栏
在Android中展示全屏`DialogFragment`并隐藏状态栏和导航栏,可通过设置系统UI标志实现。 记得在布局文件中添加内容,并使用`show()`方法显示`DialogFragment`。
77 2
|
7月前
|
XML 存储 测试技术
Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单
Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单
1336 1
|
7月前
|
XML Android开发 数据格式
android 9 Systemui 动态隐藏导航栏
android 9 Systemui 动态隐藏导航栏
245 0
|
7月前
|
Android开发
Android SystemUI去掉拖动亮度条QSPanel界面隐藏功能
Android SystemUI去掉拖动亮度条QSPanel界面隐藏功能
161 0
|
7月前
|
XML Java Android开发
Android Studio App开发中工具栏Toolbar、溢出菜单OverflowMenu、标签布局TabLayout的讲解及实战(实现京东App的标签导航栏,附源码)
Android Studio App开发中工具栏Toolbar、溢出菜单OverflowMenu、标签布局TabLayout的讲解及实战(实现京东App的标签导航栏,附源码)
685 0
|
XML Java 测试技术
车载Android应用开发与分析 - SystemUI 「功能」与「源码结构」分析
本期内容开始,我们将介绍原生Android Automotive中车载应用的实现方式和它的原理。首先要介绍的就是车载应用开发中非常重要的一个系统应用,Android系统的UI - SystemUI。
937 1
车载Android应用开发与分析 - SystemUI 「功能」与「源码结构」分析
|
Android开发
Android的Dialog弹出时隐藏导航栏效果,目前认为的最优解
Android的Dialog弹出时隐藏导航栏效果,目前认为的最优解