diff options
7 files changed, 161 insertions, 75 deletions
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java index c906705ae5a9..cf88bd5364a7 100644 --- a/services/core/java/com/android/server/policy/BarController.java +++ b/services/core/java/com/android/server/policy/BarController.java @@ -20,6 +20,7 @@ import static com.android.server.wm.proto.BarControllerProto.STATE; import static com.android.server.wm.proto.BarControllerProto.TRANSIENT_STATE; import android.app.StatusBarManager; +import android.graphics.Rect; import android.os.Handler; import android.os.Message; import android.os.SystemClock; @@ -68,6 +69,7 @@ public class BarController { private boolean mShowTransparent; private boolean mSetUnHideFlagWhenNextTransparent; private boolean mNoAnimationOnNextShow; + private final Rect mContentFrame = new Rect(); private OnBarVisibilityChangedListener mVisibilityChangeListener; @@ -87,6 +89,15 @@ public class BarController { mWin = win; } + /** + * Sets the frame within which the bar will display its content. + * + * This is used to determine if letterboxes interfere with the display of such content. + */ + public void setContentFrame(Rect frame) { + mContentFrame.set(frame); + } + public void setShowTransparent(boolean transparent) { if (transparent != mShowTransparent) { mShowTransparent = transparent; @@ -135,7 +146,8 @@ public class BarController { } else { vis &= ~mTranslucentFlag; } - if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) { + if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 + && isTransparentAllowed(win)) { vis |= mTransparentFlag; } else { vis &= ~mTransparentFlag; @@ -148,6 +160,10 @@ public class BarController { return vis; } + boolean isTransparentAllowed(WindowState win) { + return win == null || !win.isLetterboxedOverlappingWith(mContentFrame); + } + public boolean setBarShowingLw(final boolean show) { if (mWin == null) return false; if (show && mTransientBarState == TRANSIENT_BAR_HIDING) { @@ -328,6 +344,7 @@ public class BarController { pw.println(StatusBarManager.windowStateToString(mState)); pw.print(prefix); pw.print(" "); pw.print("mTransientBar"); pw.print('='); pw.println(transientBarStateToString(mTransientBarState)); + pw.print(prefix); pw.print(" mContentFrame="); pw.println(mContentFrame); } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 3cd79e1642dc..3cdb130d5efe 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4705,6 +4705,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeightForRotation[displayFrames.mRotation]; + // Tell the bar controller where the collapsed status bar content is + mTmpRect.set(mStatusBar.getContentFrameLw()); + mTmpRect.intersect(displayFrames.mDisplayCutoutSafe); + mTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset + mTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size + mStatusBarController.setContentFrame(mTmpRect); + boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0; boolean statusBarTranslucent = (sysui & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0; @@ -4838,6 +4845,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, mTmpNavigationFrame, dcf, mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, displayFrames.mDisplayCutout); + mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw()); + if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); return mNavigationBarController.checkHiddenLw(); } @@ -8025,11 +8034,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the top fullscreen-or-dimming window is also the top fullscreen, respect // its light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - if (!statusColorWin.isLetterboxedForDisplayCutoutLw()) { - // Only allow white status bar if the window was not letterboxed. - vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null) - & 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; @@ -8097,15 +8103,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } - private boolean drawsSystemBarBackground(WindowState win) { - return win == null || (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; - } - - private boolean forcesDrawStatusBarBackground(WindowState win) { - return win == null || (win.getAttrs().privateFlags - & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0; - } - private int updateSystemBarsLw(WindowState win, int oldVis, int vis) { final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); @@ -8129,13 +8126,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTopDockedOpaqueWindowState, 0, 0); final boolean fullscreenDrawsStatusBarBackground = - (drawsSystemBarBackground(mTopFullscreenOpaqueWindowState) - && (vis & View.STATUS_BAR_TRANSLUCENT) == 0) - || forcesDrawStatusBarBackground(mTopFullscreenOpaqueWindowState); + drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState); final boolean dockedDrawsStatusBarBackground = - (drawsSystemBarBackground(mTopDockedOpaqueWindowState) - && (dockedVis & View.STATUS_BAR_TRANSLUCENT) == 0) - || forcesDrawStatusBarBackground(mTopDockedOpaqueWindowState); + drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState); // prevent status bar interaction from clearing certain flags int type = win.getAttrs().type; @@ -8238,6 +8231,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } + private boolean drawsStatusBarBackground(int vis, WindowState win) { + if (!mStatusBarController.isTransparentAllowed(win)) { + return false; + } + if (win == null) { + return true; + } + + final boolean drawsSystemBars = + (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; + final boolean forceDrawsSystemBars = + (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0; + + return forceDrawsSystemBars || drawsSystemBars && (vis & View.STATUS_BAR_TRANSLUCENT) == 0; + } + /** * @return the current visibility flags with the nav-bar opacity related flags toggled based * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}. diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index b0d5e1a8c62a..990421653c1d 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -447,6 +447,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { return false; } + /** + * Returns true if the window has a letterbox and any part of that letterbox overlaps with + * the given {@code rect}. + */ + default boolean isLetterboxedOverlappingWith(Rect rect) { + return false; + } + /** @return the current windowing mode of this window. */ int getWindowingMode(); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 88cb54d126c1..d2ddf551fc8d 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -24,7 +24,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.SurfaceControl.HIDDEN; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; @@ -712,7 +711,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (destroyedSomething) { final DisplayContent dc = getDisplayContent(); dc.assignWindowLayers(true /*setLayoutNeeded*/); - updateLetterbox(null); + updateLetterboxSurface(null); } } @@ -979,7 +978,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree void removeChild(WindowState child) { super.removeChild(child); checkKeyguardFlagsChanged(); - updateLetterbox(child); + updateLetterboxSurface(child); } private boolean waitingForReplacement() { @@ -1470,7 +1469,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return isInterestingAndDrawn; } - void updateLetterbox(WindowState winHint) { + void layoutLetterbox(WindowState winHint) { final WindowState w = findMainWindow(); if (w != winHint && winHint != null && w != null) { return; @@ -1481,19 +1480,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null)); } - mLetterbox.setDimensions(mPendingTransaction, getParent().getBounds(), w.mFrame); + mLetterbox.layout(getParent().getBounds(), w.mFrame); } else if (mLetterbox != null) { - final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - // Make sure we have a transaction here, in case we're called outside of a transaction. - // This does not use mPendingTransaction, because SurfaceAnimator uses a - // global transaction in onAnimationEnd. - SurfaceControl.openTransaction(); - try { - mLetterbox.hide(t); - } finally { - SurfaceControl.mergeToGlobalTransaction(t); - SurfaceControl.closeTransaction(); - } + mLetterbox.hide(); + } + } + + void updateLetterboxSurface(WindowState winHint) { + final WindowState w = findMainWindow(); + if (w != winHint && winHint != null && w != null) { + return; + } + layoutLetterbox(winHint); + if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) { + mLetterbox.applySurfaceChanges(mPendingTransaction); } } @@ -2163,4 +2163,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return new Rect(); } } + + /** + * @eturn true if there is a letterbox and any part of that letterbox overlaps with + * the given {@code rect}. + */ + boolean isLetterboxOverlappingWith(Rect rect) { + return mLetterbox != null && mLetterbox.isOverlappingWith(rect); + } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 59babcfe0371..c35c05dc7212 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -80,7 +80,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -558,6 +557,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo w.updateLastInsetValues(); } + if (w.mAppToken != null) { + w.mAppToken.layoutLetterbox(w); + } + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame + " mContainingFrame=" + w.mContainingFrame + " mDisplayFrame=" + w.mDisplayFrame); @@ -697,7 +700,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final AppWindowToken atoken = w.mAppToken; if (atoken != null) { - atoken.updateLetterbox(w); + atoken.updateLetterboxSurface(w); final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w); if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) { mTmpUpdateAllDrawn.add(atoken); diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 0f9735dc23d4..4eb021cd55dc 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -49,24 +49,26 @@ public class Letterbox { } /** - * Sets the dimensions of the the letterbox, such that the area between the outer and inner + * Lays out the letterbox, such that the area between the outer and inner * frames will be covered by black color surfaces. * - * @param t a transaction in which to set the dimensions + * The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface. + * * @param outer the outer frame of the letterbox (this frame will be black, except the area * that intersects with the {code inner} frame). * @param inner the inner frame of the letterbox (this frame will be clear) */ - public void setDimensions(SurfaceControl.Transaction t, Rect outer, Rect inner) { + public void layout(Rect outer, Rect inner) { mOuter.set(outer); mInner.set(inner); - mTop.setRect(t, outer.left, outer.top, inner.right, inner.top); - mLeft.setRect(t, outer.left, inner.top, inner.left, outer.bottom); - mBottom.setRect(t, inner.left, inner.bottom, outer.right, outer.bottom); - mRight.setRect(t, inner.right, outer.top, outer.right, inner.bottom); + mTop.layout(outer.left, outer.top, inner.right, inner.top); + mLeft.layout(outer.left, inner.top, inner.left, outer.bottom); + mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom); + mRight.layout(inner.right, outer.top, outer.right, inner.bottom); } + /** * Gets the insets between the outer and inner rects. */ @@ -79,12 +81,20 @@ public class Letterbox { } /** + * Returns true if any part of the letterbox overlaps with the given {@code rect}. + */ + public boolean isOverlappingWith(Rect rect) { + return mTop.isOverlappingWith(rect) || mLeft.isOverlappingWith(rect) + || mBottom.isOverlappingWith(rect) || mRight.isOverlappingWith(rect); + } + + /** * Hides the letterbox. * - * @param t a transaction in which to hide the letterbox + * The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface. */ - public void hide(SurfaceControl.Transaction t) { - setDimensions(t, EMPTY_RECT, EMPTY_RECT); + public void hide() { + layout(EMPTY_RECT, EMPTY_RECT); } /** @@ -100,43 +110,40 @@ public class Letterbox { mRight.destroy(); } + /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ + public boolean needsApplySurfaceChanges() { + return mTop.needsApplySurfaceChanges() + || mLeft.needsApplySurfaceChanges() + || mBottom.needsApplySurfaceChanges() + || mRight.needsApplySurfaceChanges(); + } + + public void applySurfaceChanges(SurfaceControl.Transaction t) { + mTop.applySurfaceChanges(t); + mLeft.applySurfaceChanges(t); + mBottom.applySurfaceChanges(t); + mRight.applySurfaceChanges(t); + } + private class LetterboxSurface { private final String mType; private SurfaceControl mSurface; - private int mLastLeft = 0; - private int mLastTop = 0; - private int mLastRight = 0; - private int mLastBottom = 0; + private final Rect mSurfaceFrame = new Rect(); + private final Rect mLayoutFrame = new Rect(); public LetterboxSurface(String type) { mType = type; } - public void setRect(SurfaceControl.Transaction t, - int left, int top, int right, int bottom) { - if (mLastLeft == left && mLastTop == top - && mLastRight == right && mLastBottom == bottom) { + public void layout(int left, int top, int right, int bottom) { + if (mLayoutFrame.left == left && mLayoutFrame.top == top + && mLayoutFrame.right == right && mLayoutFrame.bottom == bottom) { // Nothing changed. return; } - - if (left < right && top < bottom) { - if (mSurface == null) { - createSurface(); - } - t.setPosition(mSurface, left, top); - t.setSize(mSurface, right - left, bottom - top); - t.show(mSurface); - } else if (mSurface != null) { - t.hide(mSurface); - } - - mLastLeft = left; - mLastTop = top; - mLastRight = right; - mLastBottom = bottom; + mLayoutFrame.set(left, top, right, bottom); } private void createSurface() { @@ -154,11 +161,40 @@ public class Letterbox { } public int getWidth() { - return Math.max(0, mLastRight - mLastLeft); + return Math.max(0, mLayoutFrame.width()); } public int getHeight() { - return Math.max(0, mLastBottom - mLastTop); + return Math.max(0, mLayoutFrame.height()); + } + + public boolean isOverlappingWith(Rect rect) { + if (getWidth() <= 0 || getHeight() <= 0) { + return false; + } + return Rect.intersects(rect, mLayoutFrame); + } + + public void applySurfaceChanges(SurfaceControl.Transaction t) { + if (mSurfaceFrame.equals(mLayoutFrame)) { + // Nothing changed. + return; + } + mSurfaceFrame.set(mLayoutFrame); + if (!mSurfaceFrame.isEmpty()) { + if (mSurface == null) { + createSurface(); + } + t.setPosition(mSurface, mSurfaceFrame.left, mSurfaceFrame.top); + t.setSize(mSurface, mSurfaceFrame.width(), mSurfaceFrame.height()); + t.show(mSurface); + } else if (mSurface != null) { + t.hide(mSurface); + } + } + + public boolean needsApplySurfaceChanges() { + return !mSurfaceFrame.equals(mLayoutFrame); } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 91cd4bb545a1..591289723a00 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3074,6 +3074,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return (fl & FLAG_FULLSCREEN) != 0 || (sysui & (SYSTEM_UI_FLAG_FULLSCREEN)) != 0; } + @Override + public boolean isLetterboxedOverlappingWith(Rect rect) { + return mAppToken != null && mAppToken.isLetterboxOverlappingWith(rect); + } + boolean isDragResizeChanged() { return mDragResizing != computeDragResizing(); } |