diff options
7 files changed, 176 insertions, 30 deletions
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 8868a6c2e6d8..b3e162d473db 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -396,14 +396,6 @@ 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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 40e558c09965..3e9377ed0664 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1395,6 +1395,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** + * @see Letterbox#notIntersectsOrFullyContains(Rect) + */ + boolean letterboxNotIntersectsOrFullyContains(Rect rect) { + return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect); + } + + /** * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with * the given {@code rect}. */ diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java index 123fb6c9d8e3..c1447553ba31 100644 --- a/services/core/java/com/android/server/wm/BarController.java +++ b/services/core/java/com/android/server/wm/BarController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static com.android.server.wm.BarControllerProto.STATE; import static com.android.server.wm.BarControllerProto.TRANSIENT_STATE; +import android.annotation.NonNull; import android.app.StatusBarManager; import android.graphics.Rect; import android.os.Handler; @@ -169,13 +170,23 @@ public class BarController { return vis; } + private Rect getContentFrame(@NonNull WindowState win) { + final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType); + return rotatedContentFrame != null ? rotatedContentFrame : mContentFrame; + } + + boolean isLightAppearanceAllowed(WindowState win) { + if (win == null) { + return true; + } + return !win.isLetterboxedOverlappingWith(getContentFrame(win)); + } + boolean isTransparentAllowed(WindowState win) { if (win == null) { return true; } - final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType); - final Rect contentFrame = rotatedContentFrame != null ? rotatedContentFrame : mContentFrame; - return !win.isLetterboxedOverlappingWith(contentFrame); + return win.letterboxNotIntersectsOrFullyContains(getContentFrame(win)); } boolean setBarShowingLw(final boolean show) { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 68051ab59599..605d0b2cc127 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -3437,17 +3437,22 @@ public class DisplayPolicy { WindowState opaqueOrDimming) { final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded(); final WindowState statusColorWin = onKeyguard ? mNotificationShade : opaqueOrDimming; - if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) { - // If the top fullscreen-or-dimming window is also the top fullscreen, respect - // its light flag. - appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; - final int legacyAppearance = InsetsFlags.getAppearance( - PolicyControl.getSystemUiVisibility(statusColorWin, null)); - appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance) - & APPEARANCE_LIGHT_STATUS_BARS; - } else if (statusColorWin != null && statusColorWin.isDimming()) { - // Otherwise if it's dimming, clear the light flag. - appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; + if (statusColorWin != null) { + if (statusColorWin == opaque || onKeyguard) { + // If the top fullscreen-or-dimming window is also the top fullscreen, respect + // its light flag. + appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; + final int legacyAppearance = InsetsFlags.getAppearance( + PolicyControl.getSystemUiVisibility(statusColorWin, null)); + appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance) + & APPEARANCE_LIGHT_STATUS_BARS; + } else if (statusColorWin.isDimming()) { + // Otherwise if it's dimming, clear the light flag. + appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; + } + if (!mStatusBarController.isLightAppearanceAllowed(statusColorWin)) { + appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; + } } return appearance; } @@ -3512,8 +3517,7 @@ public class DisplayPolicy { return vis; } - @VisibleForTesting - static int updateLightNavigationBarAppearanceLw(int appearance, WindowState opaque, + private int updateLightNavigationBarAppearanceLw(int appearance, WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) { if (navColorWin != null) { @@ -3526,6 +3530,9 @@ public class DisplayPolicy { // Clear the light flag for dimming window. appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; } + if (!mNavigationBarController.isLightAppearanceAllowed(navColorWin)) { + appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; + } } return appearance; } diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index a685886da032..28dcbcdf3cc7 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -77,10 +77,10 @@ public class Letterbox { mOuter.set(outer); mInner.set(inner); - mTop.layout(outer.left, outer.top, inner.right, inner.top, surfaceOrigin); - mLeft.layout(outer.left, inner.top, inner.left, outer.bottom, surfaceOrigin); - mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin); - mRight.layout(inner.right, outer.top, outer.right, inner.bottom, surfaceOrigin); + mTop.layout(outer.left, outer.top, outer.right, inner.top, surfaceOrigin); + mLeft.layout(outer.left, outer.top, inner.left, outer.bottom, surfaceOrigin); + mBottom.layout(outer.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin); + mRight.layout(inner.right, outer.top, outer.right, outer.bottom, surfaceOrigin); } @@ -101,6 +101,31 @@ public class Letterbox { } /** + * Returns {@code true} if the letterbox does not overlap with the bar, or the letterbox can + * fully cover the window frame. + * + * @param rect The area of the window frame. + */ + boolean notIntersectsOrFullyContains(Rect rect) { + int emptyCount = 0; + int noOverlappingCount = 0; + for (LetterboxSurface surface : mSurfaces) { + final Rect surfaceRect = surface.mLayoutFrameGlobal; + if (surfaceRect.isEmpty()) { + // empty letterbox + emptyCount++; + } else if (!Rect.intersects(surfaceRect, rect)) { + // no overlapping + noOverlappingCount++; + } else if (surfaceRect.contains(rect)) { + // overlapping and covered + return true; + } + } + return (emptyCount + noOverlappingCount) == mSurfaces.length; + } + + /** * Returns true if any part of the letterbox overlaps with the given {@code rect}. */ public boolean isOverlappingWith(Rect rect) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 26bcf3b285ec..1f2a8f052a3e 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3797,7 +3797,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mActivityRecord.getBounds().equals(mTmpRect); } - @Override + /** + * @see Letterbox#notIntersectsOrFullyContains(Rect) + */ + boolean letterboxNotIntersectsOrFullyContains(Rect rect) { + return mActivityRecord == null + || mActivityRecord.letterboxNotIntersectsOrFullyContains(rect); + } + public boolean isLetterboxedOverlappingWith(Rect rect) { return mActivityRecord != null && mActivityRecord.isLetterboxOverlappingWith(rect); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index bf84aecdb6a0..2f3004bf6832 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -16,8 +16,8 @@ package com.android.server.wm; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; @@ -60,6 +60,103 @@ public class LetterboxTest { assertTrue(mLetterbox.isOverlappingWith(new Rect(0, 0, 1, 1))); } + private static final int TOP_BAR = 0x1; + private static final int BOTTOM_BAR = 0x2; + private static final int LEFT_BAR = 0x4; + private static final int RIGHT_BAR = 0x8; + @Test + public void testNotIntersectsOrFullyContains_usesGlobalCoordinates() { + final Rect outer = new Rect(0, 0, 10, 50); + final Point surfaceOrig = new Point(1000, 2000); + + final Rect topBar = new Rect(0, 0, 10, 2); + final Rect bottomBar = new Rect(0, 45, 10, 50); + final Rect leftBar = new Rect(0, 0, 2, 50); + final Rect rightBar = new Rect(8, 0, 10, 50); + + final LetterboxLayoutVerifier verifier = + new LetterboxLayoutVerifier(outer, surfaceOrig, mLetterbox); + verifier.setBarRect(topBar, bottomBar, leftBar, rightBar); + + // top + verifier.setInner(0, 2, 10, 50).verifyPositions(TOP_BAR | BOTTOM_BAR, BOTTOM_BAR); + // bottom + verifier.setInner(0, 0, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, TOP_BAR); + // left + verifier.setInner(2, 0, 10, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, RIGHT_BAR); + // right + verifier.setInner(0, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, LEFT_BAR); + // top + bottom + verifier.setInner(0, 2, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, 0); + // left + right + verifier.setInner(2, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, 0); + // top + left + verifier.setInner(2, 2, 10, 50).verifyPositions(TOP_BAR | LEFT_BAR, 0); + // top + left + right + verifier.setInner(2, 2, 8, 50).verifyPositions(TOP_BAR | LEFT_BAR | RIGHT_BAR, 0); + // left + right + bottom + verifier.setInner(2, 0, 8, 45).verifyPositions(LEFT_BAR | RIGHT_BAR | BOTTOM_BAR, 0); + // all + verifier.setInner(2, 2, 8, 45) + .verifyPositions(TOP_BAR | BOTTOM_BAR | LEFT_BAR | RIGHT_BAR, 0); + } + + private static class LetterboxLayoutVerifier { + final Rect mOuter; + final Rect mInner = new Rect(); + final Point mSurfaceOrig; + final Letterbox mLetterbox; + final Rect mTempRect = new Rect(); + + final Rect mTop = new Rect(); + final Rect mBottom = new Rect(); + final Rect mLeft = new Rect(); + final Rect mRight = new Rect(); + + LetterboxLayoutVerifier(Rect outer, Point surfaceOrig, Letterbox letterbox) { + mOuter = new Rect(outer); + mSurfaceOrig = new Point(surfaceOrig); + mLetterbox = letterbox; + } + + LetterboxLayoutVerifier setInner(int left, int top, int right, int bottom) { + mInner.set(left, top, right, bottom); + mLetterbox.layout(mOuter, mInner, mSurfaceOrig); + return this; + } + + void setBarRect(Rect top, Rect bottom, Rect left, Rect right) { + mTop.set(top); + mBottom.set(bottom); + mLeft.set(left); + mRight.set(right); + } + + void verifyPositions(int allowedPos, int noOverlapPos) { + assertEquals(mLetterbox.notIntersectsOrFullyContains(mTop), + (allowedPos & TOP_BAR) != 0); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mBottom), + (allowedPos & BOTTOM_BAR) != 0); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mLeft), + (allowedPos & LEFT_BAR) != 0); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mRight), + (allowedPos & RIGHT_BAR) != 0); + + mTempRect.set(mTop.left, mTop.top, mTop.right, mTop.bottom + 1); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), + (noOverlapPos & TOP_BAR) != 0); + mTempRect.set(mLeft.left, mLeft.top, mLeft.right + 1, mLeft.bottom); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), + (noOverlapPos & LEFT_BAR) != 0); + mTempRect.set(mRight.left - 1, mRight.top, mRight.right, mRight.bottom); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), + (noOverlapPos & RIGHT_BAR) != 0); + mTempRect.set(mBottom.left, mBottom.top - 1, mBottom.right, mBottom.bottom); + assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), + (noOverlapPos & BOTTOM_BAR) != 0); + } + } + @Test public void testSurfaceOrigin_applied() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); |