平台
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进制字符串.
如:
| 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=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);
}
本文详细解析了Android7.1+RK3288系统中实现沉浸式全屏体验的过程,重点介绍了状态栏和导航栏的隐藏与显示机制。内容涉及PhoneWindowManager、PhoneStatusBar、WindowManagerService等核心组件的交互,以及相关FLAG的管理和动画处理。此外,还探讨了如何通过调整系统UI变量状态来定制状态栏的显示行为。

1048

被折叠的 条评论
为什么被折叠?



