Android 7.0 SystemUI 状态/导航栏的隐藏与显示
平台
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调用@Overridepublic 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, 再与前面的控制器交互并更新当前的系统FLAGprivate 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() {@Overridepublic void run() {StatusBarManagerInternal statusbar = getStatusBarManagerInternal();if (statusbar != null) {//传递给SystemUIstatusbar.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 flagsWindowState 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 flagsint 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 barboolean 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 insteadclearClearableFlagsLw();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 barboolean 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 // CommandQueuepublic 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 profileif ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {setAreThereNotifications();}// ready to unhideif ((vis & View.STATUS_BAR_UNHIDE) != 0) {mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;mNoAnimationOnNextBarModeChange = true;}// update status bar modefinal int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,View.STATUS_BAR_TRANSPARENT);// update navigation bar modefinal 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 autohideif (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 managernotifyUiVisibilityChanged(mSystemUiVisibility);}mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);}
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@Overridepublic 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 == PhoneWindowManagervisibility = 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进制字符串.
如:
16进制值 | FLAGS |
---|---|
0x0C0000000 | STATUS_BAR_TRANSIENT + NAVIGATION_BAR_TRANSIENT |
0x9f0a | SYSTEM_UI_FLAG_IMMERSIVE_STICKY+NAVIGATION_BAR_TRANSPARENT+SYSTEM_UI_FLAG_IMMERSIVE+SYSTEM_UI_FLAG_LAYOUT_STABLE+SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION+SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN+SYSTEM_UI_FLAG_HIDE_NAVIGATION +STATUS_BAR_TRANSPARENT |
隐藏->显示:
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=truemOverscanScreen=(0,0) 1920x1080mRestrictedOverscanScreen=(0,0) 1920x1080mUnrestrictedScreen=(0,0) 1920x1080mRestrictedScreen=(0,0) 1920x1080mStableFullscreen=(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@236987dmOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONEmAttrs=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=85mPolicyVisibility=false mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false
mPermanentlyHidden=falsemHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=falseWindowStateAnimator{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@236987dmOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONEmAttrs=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=163mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=falseWindowStateAnimator{7a4071f StatusBar}:mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1Surface: 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@3e87b09mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONEmAttrs=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=69mPolicyVisibility=true mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=falsemPermanentlyHidden=falsemHasSurface=true mShownPosition=[0,-4] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=falseWindowStateAnimator{2214d2c StatusBar}:mAnimating=true mLocalAnimating=true mAnimationIsEntrance=false mAnimation=android.view.animation.AnimationSet@5de858d mStackClip=0XForm: 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.0mGlobalScale=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 沉浸式状态栏
Android 7.0 SystemUI 状态/导航栏的隐藏与显示相关推荐
- Android 5.0状态栏和导航栏
Material Design推出之后,app中也開始沿用这样的风格 今天来说一下状态栏颜色设置,在4.4的时候推出了透明状态栏和导航栏.在不使用第三方库的情况下,4.4还是没有全然解决存在actio ...
- Android 7.0 SystemUI 之启动和状态栏和导航栏简介
Android 7.0 SystemUI 之启动和状态栏和导航栏简介 一.SystemUI 是什么 首先SystemUI 是一个系统应用,apk路径位于/system/priv-app 源码路径位于: ...
- Android 11.0 SystemUI导航栏固定在底部显示的修改
目录 1.概述 2.SystemUI导航栏固定在底部显示的修改的相关代码
- 史上最完美的Android沉浸式状态导航栏攻略
前言 最近我在小破站开发一款新App,叫高能链.我是一个完美主义者,所以不管对架构还是UI,我都是比较抠细节的,在状态栏和导航栏沉浸式这一块,我还是踩了挺多坑,费了挺多精力的.这次我将我踩坑,适配各机 ...
- android 虚拟导航监听,Android另类判断NavigationBar虚拟导航栏状态
好久没码字了,所以出来冒个泡 一直用着华为的手机,从一开始就觉得华为的虚拟导航栏用着还是挺顺手的,后来发现越来越多的机子都开始使用起来,查看源码发现,虚拟导航栏是属于SystemUI的一部分. 再一看 ...
- Android 8.0 学习(26)---Android 8.0 SystemUI(一)
Android 8.0 SystemUI(一):图文并茂的介绍 : 文章已同步更新至微信公众号:猿湿Xoong 我擅长什么? 当我想到这个这个问题的时候,脑子里是一片空白的:哎呀,我什么都知道点,可是 ...
- [高通SDM450][Android9.0]动态控制虚拟导航栏显示与隐藏
文章目录 开发平台基本信息 问题描述 解决方法 开发平台基本信息 芯片: SDM450 版本: Android 9.0 kernel: msm-4.9 问题描述 虚拟导航栏原生默认是显示的,但是,作为 ...
- (2019年10月更新) Android 最全的底部导航栏实现方法
本文(争取做到)Android 最全的底部导航栏实现方法. 现在写了4个主要方法. 官方方法. 官方的 BottomNavigationActivity 使用Android studio 新建一个工程 ...
- [九鼎RK3399Pro] Android 8.1定制系统导航栏和状态栏显示和隐藏可控制
我们的app跑在RK3399Pro上面,是放在一个公共场合使用,所以把底部的 返回,HOME,MENU键都隐藏掉,并且上部导航栏下拉功能也要取消. 代码我是参考Firefly的代码写的. 实现了一下功 ...
最新文章
- 修复Long类型太长转为JSON格式的时候出错的问题
- redis的五种存储类型的具体用法
- 恢复linux里被误删除的文件
- 一位大牛的JAVA学习资料
- IMYAOPTableView 源码学习笔记
- 【WC2014】紫荆花之恋【替罪羊思想】【动态点分树】【替罪羊树】
- BilibilivideoDownload下载器
- ES6/04/严格模式,开启严格模式,严格模式与普通模式对比发生了那些变化,高阶函数,闭包函数,递归函数,递归实例(1,阶乘,2,斐波那契数列,3,根据id返回对应数据对象),浅拷贝和深拷贝
- 大学计算机张青答案,《大学计算机Ⅰ》实验报告实验一1
- 想创业?从学会需求谈判开始
- strike F1 to retry boot,F2 for setup utility
- 米家扫地机器人按键没反应_小米扫地机系统重置键在哪?
- 推荐个不错的 Word 全文翻译和压缩工具!
- 18. --plic--=--ply--=--pli--=--ple--=--plex--=--plo-- to fold 倍,重,折叠 (词19、20)
- 一些事,只配当回忆.一些人,只能做过客。既不回头 何必不忘 既然无缘 何必誓言 。这个世界.那么脏.谁有资格.说悲伤。...
- DONT_TOUCH约束
- CSS3 媒体查询(media)与 Viewport
- 【高级篇 / System】(7.0) ❀ 07. HA 下配置核心交换机 (下) ❀ FortiGate 防火墙
- html游戏让目标人物移动,如何用html5编写鼠标事件与游戏人物移动
- Reso | Noise 网易云音乐插件