Loading core/res/res/values/config.xml +12 −0 Original line number Diff line number Diff line Loading @@ -6063,6 +6063,18 @@ <!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. --> <bool name="config_letterboxIsEducationEnabled">false</bool> <!-- The width in dp to use to detect vertical thin letterboxing. If W is the available width and w is the letterbox width, an app is thin letterboxed if the value here is < (W - w) / 2 If the value is < 0 the thin letterboxing policy is disabled --> <dimen name="config_letterboxThinLetterboxWidthDp">-1dp</dimen> <!-- The height in dp to use to detect horizontal thin letterboxing If H is the available height and h is the letterbox height, an app is thin letterboxed if the value here is < (H - h) / 2 If the value is < 0 the thin letterboxing policy is disabled --> <dimen name="config_letterboxThinLetterboxHeightDp">-1dp</dimen> <!-- Default min aspect ratio for unresizable apps which are eligible for size compat mode. Values <= 1.0 will be ignored. Activity min/max aspect ratio restrictions will still be espected so this override can control the maximum screen area that can be occupied by Loading core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -4695,6 +4695,8 @@ <java-symbol type="integer" name="config_letterboxDefaultPositionForTabletopModeReachability" /> <java-symbol type="bool" name="config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled" /> <java-symbol type="bool" name="config_letterboxIsEducationEnabled" /> <java-symbol type="dimen" name="config_letterboxThinLetterboxWidthDp" /> <java-symbol type="dimen" name="config_letterboxThinLetterboxHeightDp" /> <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" /> <java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" /> <java-symbol type="bool" name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled" /> Loading services/core/java/com/android/server/wm/LetterboxConfiguration.java +29 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.Color; import android.provider.DeviceConfig; import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; Loading @@ -33,6 +32,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.function.Function; import java.util.function.IntSupplier; /** Reads letterbox configs from resources and controls their overrides at runtime. */ final class LetterboxConfiguration { Loading Loading @@ -265,6 +265,12 @@ final class LetterboxConfiguration { // unresizable apps private boolean mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; // Supplier for the value in pixel to consider when detecting vertical thin letterboxing private final IntSupplier mThinLetterboxWidthFn; // Supplier for the value in pixel to consider when detecting horizontal thin letterboxing private final IntSupplier mThinLetterboxHeightFn; // Allows to enable letterboxing strategy for translucent activities ignoring flags. private boolean mTranslucentLetterboxingOverrideEnabled; Loading Loading @@ -358,6 +364,10 @@ final class LetterboxConfiguration { R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled); mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean( R.bool.config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled); mThinLetterboxWidthFn = () -> mContext.getResources().getDimensionPixelSize( R.dimen.config_letterboxThinLetterboxWidthDp); mThinLetterboxHeightFn = () -> mContext.getResources().getDimensionPixelSize( R.dimen.config_letterboxThinLetterboxHeightDp); mLetterboxConfigurationPersister = letterboxConfigurationPersister; mLetterboxConfigurationPersister.start(); Loading Loading @@ -1128,6 +1138,24 @@ final class LetterboxConfiguration { return mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; } /** * @return Width in pixel about the padding to use to understand if the letterbox for an * activity is thin. If the available space has width W and the app has width w, this * is the maximum value for (W - w) / 2 to be considered for a thin letterboxed app. */ int getThinLetterboxWidthPx() { return mThinLetterboxWidthFn.getAsInt(); } /** * @return Height in pixel about the padding to use to understand if a letterbox is thin. * If the available space has height H and the app has height h, this is the maximum * value for (H - h) / 2 to be considered for a thin letterboxed app. */ int getThinLetterboxHeightPx() { return mThinLetterboxHeightFn.getAsInt(); } /** * Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable * apps. Loading services/core/java/com/android/server/wm/LetterboxUiController.java +70 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.internal.statusbar.LetterboxDetails; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; import com.android.server.wm.utils.OptPropFactory; import com.android.server.wm.utils.OptPropFactory.OptProp; import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.ArrayList; Loading Loading @@ -1004,6 +1005,67 @@ final class LetterboxUiController { return getSplitScreenAspectRatio(); } /** * @return {@value true} if the resulting app is letterboxed in a way defined as thin. */ boolean isVerticalThinLetterboxed() { final int thinHeight = mLetterboxConfiguration.getThinLetterboxHeightPx(); if (thinHeight < 0) { return false; } final Task task = mActivityRecord.getTask(); if (task == null) { return false; } final int padding = Math.abs( task.getBounds().height() - mActivityRecord.getBounds().height()) / 2; return padding <= thinHeight; } /** * @return {@value true} if the resulting app is pillarboxed in a way defined as thin. */ boolean isHorizontalThinLetterboxed() { final int thinWidth = mLetterboxConfiguration.getThinLetterboxWidthPx(); if (thinWidth < 0) { return false; } final Task task = mActivityRecord.getTask(); if (task == null) { return false; } final int padding = Math.abs( task.getBounds().width() - mActivityRecord.getBounds().width()) / 2; return padding <= thinWidth; } /** * @return {@value true} if the vertical reachability should be allowed in case of * thin letteboxing */ boolean allowVerticalReachabilityForThinLetterbox() { if (!Flags.disableThinLetterboxingReachability()) { return true; } // When the flag is enabled we allow vertical reachability only if the // app is not thin letterboxed vertically. return !isVerticalThinLetterboxed(); } /** * @return {@value true} if the vertical reachability should be enabled in case of * thin letteboxing */ boolean allowHorizontalReachabilityForThinLetterbox() { if (!Flags.disableThinLetterboxingReachability()) { return true; } // When the flag is enabled we allow horizontal reachability only if the // app is not thin pillarboxed. return !isHorizontalThinLetterboxed(); } float getSplitScreenAspectRatio() { // Getting the same aspect ratio that apps get in split screen. final DisplayArea displayArea = mActivityRecord.getDisplayArea(); Loading Loading @@ -1243,6 +1305,9 @@ final class LetterboxUiController { * </ul> */ private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) { if (!allowHorizontalReachabilityForThinLetterbox()) { return false; } // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() Loading Loading @@ -1278,6 +1343,9 @@ final class LetterboxUiController { * </ul> */ private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) { if (!allowVerticalReachabilityForThinLetterbox()) { return false; } // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() Loading Loading @@ -1551,6 +1619,8 @@ final class LetterboxUiController { if (!shouldShowLetterboxUi) { return; } pw.println(prefix + " isVerticalThinLetterboxed=" + isVerticalThinLetterboxed()); pw.println(prefix + " isHorizontalThinLetterboxed=" + isHorizontalThinLetterboxed()); pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString( getLetterboxBackgroundColor().toArgb())); pw.println(prefix + " letterboxBackgroundType=" Loading services/core/java/com/android/server/wm/Task.java +20 −8 Original line number Diff line number Diff line Loading @@ -3546,8 +3546,6 @@ class Task extends TaskFragment { info.isVisibleRequested = isVisibleRequested(); info.isSleeping = shouldSleepActivities(); info.isTopActivityTransparent = top != null && !top.fillsParent(); appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled(); appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET; Loading @@ -3562,15 +3560,29 @@ class Task extends TaskFragment { appCompatTaskInfo.topActivityLetterboxWidth = top.getBounds().width(); appCompatTaskInfo.topActivityLetterboxHeight = top.getBounds().height(); } // We need to consider if letterboxed or pillarboxed // TODO(b/336807329) Encapsulate reachability logic appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled(); if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) { if (appCompatTaskInfo.isTopActivityPillarboxed()) { if (top.mLetterboxUiController.allowHorizontalReachabilityForThinLetterbox()) { // Pillarboxed appCompatTaskInfo.topActivityLetterboxHorizontalPosition = top.mLetterboxUiController.getLetterboxPositionForHorizontalReachability(); top.mLetterboxUiController .getLetterboxPositionForHorizontalReachability(); } else { appCompatTaskInfo.isLetterboxDoubleTapEnabled = false; } } else { if (top.mLetterboxUiController.allowVerticalReachabilityForThinLetterbox()) { // Letterboxed appCompatTaskInfo.topActivityLetterboxVerticalPosition = top.mLetterboxUiController.getLetterboxPositionForVerticalReachability(); top.mLetterboxUiController .getLetterboxPositionForVerticalReachability(); } else { appCompatTaskInfo.isLetterboxDoubleTapEnabled = false; } } } appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton = top != null Loading Loading
core/res/res/values/config.xml +12 −0 Original line number Diff line number Diff line Loading @@ -6063,6 +6063,18 @@ <!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. --> <bool name="config_letterboxIsEducationEnabled">false</bool> <!-- The width in dp to use to detect vertical thin letterboxing. If W is the available width and w is the letterbox width, an app is thin letterboxed if the value here is < (W - w) / 2 If the value is < 0 the thin letterboxing policy is disabled --> <dimen name="config_letterboxThinLetterboxWidthDp">-1dp</dimen> <!-- The height in dp to use to detect horizontal thin letterboxing If H is the available height and h is the letterbox height, an app is thin letterboxed if the value here is < (H - h) / 2 If the value is < 0 the thin letterboxing policy is disabled --> <dimen name="config_letterboxThinLetterboxHeightDp">-1dp</dimen> <!-- Default min aspect ratio for unresizable apps which are eligible for size compat mode. Values <= 1.0 will be ignored. Activity min/max aspect ratio restrictions will still be espected so this override can control the maximum screen area that can be occupied by Loading
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -4695,6 +4695,8 @@ <java-symbol type="integer" name="config_letterboxDefaultPositionForTabletopModeReachability" /> <java-symbol type="bool" name="config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled" /> <java-symbol type="bool" name="config_letterboxIsEducationEnabled" /> <java-symbol type="dimen" name="config_letterboxThinLetterboxWidthDp" /> <java-symbol type="dimen" name="config_letterboxThinLetterboxHeightDp" /> <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" /> <java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" /> <java-symbol type="bool" name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled" /> Loading
services/core/java/com/android/server/wm/LetterboxConfiguration.java +29 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.Color; import android.provider.DeviceConfig; import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; Loading @@ -33,6 +32,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.function.Function; import java.util.function.IntSupplier; /** Reads letterbox configs from resources and controls their overrides at runtime. */ final class LetterboxConfiguration { Loading Loading @@ -265,6 +265,12 @@ final class LetterboxConfiguration { // unresizable apps private boolean mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; // Supplier for the value in pixel to consider when detecting vertical thin letterboxing private final IntSupplier mThinLetterboxWidthFn; // Supplier for the value in pixel to consider when detecting horizontal thin letterboxing private final IntSupplier mThinLetterboxHeightFn; // Allows to enable letterboxing strategy for translucent activities ignoring flags. private boolean mTranslucentLetterboxingOverrideEnabled; Loading Loading @@ -358,6 +364,10 @@ final class LetterboxConfiguration { R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled); mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean( R.bool.config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled); mThinLetterboxWidthFn = () -> mContext.getResources().getDimensionPixelSize( R.dimen.config_letterboxThinLetterboxWidthDp); mThinLetterboxHeightFn = () -> mContext.getResources().getDimensionPixelSize( R.dimen.config_letterboxThinLetterboxHeightDp); mLetterboxConfigurationPersister = letterboxConfigurationPersister; mLetterboxConfigurationPersister.start(); Loading Loading @@ -1128,6 +1138,24 @@ final class LetterboxConfiguration { return mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; } /** * @return Width in pixel about the padding to use to understand if the letterbox for an * activity is thin. If the available space has width W and the app has width w, this * is the maximum value for (W - w) / 2 to be considered for a thin letterboxed app. */ int getThinLetterboxWidthPx() { return mThinLetterboxWidthFn.getAsInt(); } /** * @return Height in pixel about the padding to use to understand if a letterbox is thin. * If the available space has height H and the app has height h, this is the maximum * value for (H - h) / 2 to be considered for a thin letterboxed app. */ int getThinLetterboxHeightPx() { return mThinLetterboxHeightFn.getAsInt(); } /** * Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable * apps. Loading
services/core/java/com/android/server/wm/LetterboxUiController.java +70 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.internal.statusbar.LetterboxDetails; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; import com.android.server.wm.utils.OptPropFactory; import com.android.server.wm.utils.OptPropFactory.OptProp; import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.ArrayList; Loading Loading @@ -1004,6 +1005,67 @@ final class LetterboxUiController { return getSplitScreenAspectRatio(); } /** * @return {@value true} if the resulting app is letterboxed in a way defined as thin. */ boolean isVerticalThinLetterboxed() { final int thinHeight = mLetterboxConfiguration.getThinLetterboxHeightPx(); if (thinHeight < 0) { return false; } final Task task = mActivityRecord.getTask(); if (task == null) { return false; } final int padding = Math.abs( task.getBounds().height() - mActivityRecord.getBounds().height()) / 2; return padding <= thinHeight; } /** * @return {@value true} if the resulting app is pillarboxed in a way defined as thin. */ boolean isHorizontalThinLetterboxed() { final int thinWidth = mLetterboxConfiguration.getThinLetterboxWidthPx(); if (thinWidth < 0) { return false; } final Task task = mActivityRecord.getTask(); if (task == null) { return false; } final int padding = Math.abs( task.getBounds().width() - mActivityRecord.getBounds().width()) / 2; return padding <= thinWidth; } /** * @return {@value true} if the vertical reachability should be allowed in case of * thin letteboxing */ boolean allowVerticalReachabilityForThinLetterbox() { if (!Flags.disableThinLetterboxingReachability()) { return true; } // When the flag is enabled we allow vertical reachability only if the // app is not thin letterboxed vertically. return !isVerticalThinLetterboxed(); } /** * @return {@value true} if the vertical reachability should be enabled in case of * thin letteboxing */ boolean allowHorizontalReachabilityForThinLetterbox() { if (!Flags.disableThinLetterboxingReachability()) { return true; } // When the flag is enabled we allow horizontal reachability only if the // app is not thin pillarboxed. return !isHorizontalThinLetterboxed(); } float getSplitScreenAspectRatio() { // Getting the same aspect ratio that apps get in split screen. final DisplayArea displayArea = mActivityRecord.getDisplayArea(); Loading Loading @@ -1243,6 +1305,9 @@ final class LetterboxUiController { * </ul> */ private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) { if (!allowHorizontalReachabilityForThinLetterbox()) { return false; } // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() Loading Loading @@ -1278,6 +1343,9 @@ final class LetterboxUiController { * </ul> */ private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) { if (!allowVerticalReachabilityForThinLetterbox()) { return false; } // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() Loading Loading @@ -1551,6 +1619,8 @@ final class LetterboxUiController { if (!shouldShowLetterboxUi) { return; } pw.println(prefix + " isVerticalThinLetterboxed=" + isVerticalThinLetterboxed()); pw.println(prefix + " isHorizontalThinLetterboxed=" + isHorizontalThinLetterboxed()); pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString( getLetterboxBackgroundColor().toArgb())); pw.println(prefix + " letterboxBackgroundType=" Loading
services/core/java/com/android/server/wm/Task.java +20 −8 Original line number Diff line number Diff line Loading @@ -3546,8 +3546,6 @@ class Task extends TaskFragment { info.isVisibleRequested = isVisibleRequested(); info.isSleeping = shouldSleepActivities(); info.isTopActivityTransparent = top != null && !top.fillsParent(); appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled(); appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET; Loading @@ -3562,15 +3560,29 @@ class Task extends TaskFragment { appCompatTaskInfo.topActivityLetterboxWidth = top.getBounds().width(); appCompatTaskInfo.topActivityLetterboxHeight = top.getBounds().height(); } // We need to consider if letterboxed or pillarboxed // TODO(b/336807329) Encapsulate reachability logic appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled(); if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) { if (appCompatTaskInfo.isTopActivityPillarboxed()) { if (top.mLetterboxUiController.allowHorizontalReachabilityForThinLetterbox()) { // Pillarboxed appCompatTaskInfo.topActivityLetterboxHorizontalPosition = top.mLetterboxUiController.getLetterboxPositionForHorizontalReachability(); top.mLetterboxUiController .getLetterboxPositionForHorizontalReachability(); } else { appCompatTaskInfo.isLetterboxDoubleTapEnabled = false; } } else { if (top.mLetterboxUiController.allowVerticalReachabilityForThinLetterbox()) { // Letterboxed appCompatTaskInfo.topActivityLetterboxVerticalPosition = top.mLetterboxUiController.getLetterboxPositionForVerticalReachability(); top.mLetterboxUiController .getLetterboxPositionForVerticalReachability(); } else { appCompatTaskInfo.isLetterboxDoubleTapEnabled = false; } } } appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton = top != null Loading