Loading core/res/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -4632,6 +4632,10 @@ maximum screen area that can be occupied by the app in the letterbox mode. --> <item name="config_taskLetterboxAspectRatio" format="float" type="dimen">0.0</item> <!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and corners of the activity won't be rounded. --> <integer name="config_letterboxActivityCornersRadius">0</integer> <!-- If true, hide the display cutout with display area --> <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool> Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4132,6 +4132,7 @@ <java-symbol type="dimen" name="controls_thumbnail_image_max_width" /> <java-symbol type="dimen" name="config_taskLetterboxAspectRatio" /> <java-symbol type="integer" name="config_letterboxActivityCornersRadius" /> <java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" /> Loading services/core/java/com/android/server/wm/ActivityRecord.java +32 −5 Original line number Diff line number Diff line Loading @@ -1355,11 +1355,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean surfaceReady = w.isDrawn() // Regular case || w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready. || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface. final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent(); final boolean needsLetterbox = surfaceReady && isLetterboxed(w); updateRoundedCorners(w); if (needsLetterbox) { if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null), mWmService.mTransactionFactory); mWmService.mTransactionFactory, mWmService::isLetterboxActivityCornersRounded); mLetterbox.attachInput(w); } getPosition(mTmpPoint); Loading @@ -1379,6 +1381,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } /** @return {@code true} when main window is letterboxed and activity isn't transparent. */ private boolean isLetterboxed(WindowState mainWindow) { return mainWindow.isLetterboxedAppWindow() && fillsParent(); } private void updateRoundedCorners(WindowState mainWindow) { int cornersRadius = // Don't round corners if letterboxed only for display cutout. isLetterboxed(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout() ? Math.max(0, mWmService.getLetterboxActivityCornersRadius()) : 0; setCornersRadius(mainWindow, cornersRadius); } private void setCornersRadius(WindowState mainWindow, int cornersRadius) { final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface(); if (windowSurface != null && windowSurface.isValid()) { Transaction transaction = getPendingTransaction(); transaction.setCornerRadius(windowSurface, cornersRadius); } } void updateLetterboxSurface(WindowState winHint) { final WindowState w = findMainWindow(); if (w != winHint && winHint != null && w != null) { Loading Loading @@ -1408,10 +1431,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** * @see Letterbox#notIntersectsOrFullyContains(Rect) * @return {@code true} if bar shown within a given rectangle is allowed to be transparent * when the current activity is displayed. */ boolean letterboxNotIntersectsOrFullyContains(Rect rect) { return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect); boolean isTransparentBarAllowed(Rect rect) { // TODO(b/175482966): Allow status and navigation bars to be semi-transparent black // in letterbox mode. return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect) || mWmService.isLetterboxActivityCornersRounded(); } /** Loading services/core/java/com/android/server/wm/BarController.java +1 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,6 @@ public class BarController { if (win == null) { return true; } return win.letterboxNotIntersectsOrFullyContains(getContentFrame(win)); return win.isTransparentBarAllowed(getContentFrame(win)); } } services/core/java/com/android/server/wm/Letterbox.java +18 −1 Original line number Diff line number Diff line Loading @@ -44,12 +44,17 @@ public class Letterbox { private final Supplier<SurfaceControl.Builder> mSurfaceControlFactory; private final Supplier<SurfaceControl.Transaction> mTransactionFactory; private final Supplier<Boolean> mAreCornersRounded; private final Rect mOuter = new Rect(); private final Rect mInner = new Rect(); private final LetterboxSurface mTop = new LetterboxSurface("top"); private final LetterboxSurface mLeft = new LetterboxSurface("left"); private final LetterboxSurface mBottom = new LetterboxSurface("bottom"); private final LetterboxSurface mRight = new LetterboxSurface("right"); // Prevents wallpaper from peeking through near rounded corners. It's not included in // mSurfaces array since it isn't needed in methods like notIntersectsOrFullyContains // or attachInput. private final LetterboxSurface mBehind = new LetterboxSurface("behind"); private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; /** Loading @@ -58,9 +63,11 @@ public class Letterbox { * @param surfaceControlFactory a factory for creating the managed {@link SurfaceControl}s */ public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory, Supplier<SurfaceControl.Transaction> transactionFactory) { Supplier<SurfaceControl.Transaction> transactionFactory, Supplier<Boolean> areCornersRounded) { mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mAreCornersRounded = areCornersRounded; } /** Loading @@ -82,6 +89,7 @@ public class Letterbox { 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); mBehind.layout(inner.left, inner.top, inner.right, inner.bottom, surfaceOrigin); } Loading Loading @@ -157,6 +165,7 @@ public class Letterbox { for (LetterboxSurface surface : mSurfaces) { surface.remove(); } mBehind.remove(); } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ Loading @@ -166,6 +175,9 @@ public class Letterbox { return true; } } if (mBehind.needsApplySurfaceChanges()) { return true; } return false; } Loading @@ -173,6 +185,11 @@ public class Letterbox { for (LetterboxSurface surface : mSurfaces) { surface.applySurfaceChanges(t); } if (mAreCornersRounded.get()) { mBehind.applySurfaceChanges(t); } else { mBehind.remove(); } } /** Enables touches to slide into other neighboring surfaces. */ Loading Loading
core/res/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -4632,6 +4632,10 @@ maximum screen area that can be occupied by the app in the letterbox mode. --> <item name="config_taskLetterboxAspectRatio" format="float" type="dimen">0.0</item> <!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and corners of the activity won't be rounded. --> <integer name="config_letterboxActivityCornersRadius">0</integer> <!-- If true, hide the display cutout with display area --> <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool> Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4132,6 +4132,7 @@ <java-symbol type="dimen" name="controls_thumbnail_image_max_width" /> <java-symbol type="dimen" name="config_taskLetterboxAspectRatio" /> <java-symbol type="integer" name="config_letterboxActivityCornersRadius" /> <java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" /> Loading
services/core/java/com/android/server/wm/ActivityRecord.java +32 −5 Original line number Diff line number Diff line Loading @@ -1355,11 +1355,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean surfaceReady = w.isDrawn() // Regular case || w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready. || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface. final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent(); final boolean needsLetterbox = surfaceReady && isLetterboxed(w); updateRoundedCorners(w); if (needsLetterbox) { if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null), mWmService.mTransactionFactory); mWmService.mTransactionFactory, mWmService::isLetterboxActivityCornersRounded); mLetterbox.attachInput(w); } getPosition(mTmpPoint); Loading @@ -1379,6 +1381,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } /** @return {@code true} when main window is letterboxed and activity isn't transparent. */ private boolean isLetterboxed(WindowState mainWindow) { return mainWindow.isLetterboxedAppWindow() && fillsParent(); } private void updateRoundedCorners(WindowState mainWindow) { int cornersRadius = // Don't round corners if letterboxed only for display cutout. isLetterboxed(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout() ? Math.max(0, mWmService.getLetterboxActivityCornersRadius()) : 0; setCornersRadius(mainWindow, cornersRadius); } private void setCornersRadius(WindowState mainWindow, int cornersRadius) { final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface(); if (windowSurface != null && windowSurface.isValid()) { Transaction transaction = getPendingTransaction(); transaction.setCornerRadius(windowSurface, cornersRadius); } } void updateLetterboxSurface(WindowState winHint) { final WindowState w = findMainWindow(); if (w != winHint && winHint != null && w != null) { Loading Loading @@ -1408,10 +1431,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** * @see Letterbox#notIntersectsOrFullyContains(Rect) * @return {@code true} if bar shown within a given rectangle is allowed to be transparent * when the current activity is displayed. */ boolean letterboxNotIntersectsOrFullyContains(Rect rect) { return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect); boolean isTransparentBarAllowed(Rect rect) { // TODO(b/175482966): Allow status and navigation bars to be semi-transparent black // in letterbox mode. return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect) || mWmService.isLetterboxActivityCornersRounded(); } /** Loading
services/core/java/com/android/server/wm/BarController.java +1 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,6 @@ public class BarController { if (win == null) { return true; } return win.letterboxNotIntersectsOrFullyContains(getContentFrame(win)); return win.isTransparentBarAllowed(getContentFrame(win)); } }
services/core/java/com/android/server/wm/Letterbox.java +18 −1 Original line number Diff line number Diff line Loading @@ -44,12 +44,17 @@ public class Letterbox { private final Supplier<SurfaceControl.Builder> mSurfaceControlFactory; private final Supplier<SurfaceControl.Transaction> mTransactionFactory; private final Supplier<Boolean> mAreCornersRounded; private final Rect mOuter = new Rect(); private final Rect mInner = new Rect(); private final LetterboxSurface mTop = new LetterboxSurface("top"); private final LetterboxSurface mLeft = new LetterboxSurface("left"); private final LetterboxSurface mBottom = new LetterboxSurface("bottom"); private final LetterboxSurface mRight = new LetterboxSurface("right"); // Prevents wallpaper from peeking through near rounded corners. It's not included in // mSurfaces array since it isn't needed in methods like notIntersectsOrFullyContains // or attachInput. private final LetterboxSurface mBehind = new LetterboxSurface("behind"); private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; /** Loading @@ -58,9 +63,11 @@ public class Letterbox { * @param surfaceControlFactory a factory for creating the managed {@link SurfaceControl}s */ public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory, Supplier<SurfaceControl.Transaction> transactionFactory) { Supplier<SurfaceControl.Transaction> transactionFactory, Supplier<Boolean> areCornersRounded) { mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mAreCornersRounded = areCornersRounded; } /** Loading @@ -82,6 +89,7 @@ public class Letterbox { 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); mBehind.layout(inner.left, inner.top, inner.right, inner.bottom, surfaceOrigin); } Loading Loading @@ -157,6 +165,7 @@ public class Letterbox { for (LetterboxSurface surface : mSurfaces) { surface.remove(); } mBehind.remove(); } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ Loading @@ -166,6 +175,9 @@ public class Letterbox { return true; } } if (mBehind.needsApplySurfaceChanges()) { return true; } return false; } Loading @@ -173,6 +185,11 @@ public class Letterbox { for (LetterboxSurface surface : mSurfaces) { surface.applySurfaceChanges(t); } if (mAreCornersRounded.get()) { mBehind.applySurfaceChanges(t); } else { mBehind.remove(); } } /** Enables touches to slide into other neighboring surfaces. */ Loading