平台
Android 7.1 + RK3288
概述
从Android 4.4开始支持沉浸式全屏体验,在沉浸式全屏模式下,状态栏、 虚拟按键动态隐藏,应用可以使用完整的屏幕空间,按照 Google 的说法,给用户一种 “身临其境” 的体验。
增加了 IMMERSIVE 和 IMMERSIVE_STICKY 标记,可以用这两个标记与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 一起使用, 来实现沉 浸模式。
全屏的是通过隐藏状态栏和导航栏实现, 服务之间的交互如下:
关键函数
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进制字符串.
如:
隐藏->显示:
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 沉浸式状态栏