diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 419f142d0795a..f24d663ced16b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4700,6 +4700,11 @@
-->
This value can be outside of [0, 1] range so clients need to check and default to the + * central position (0.5). + */ + float getLetterboxHorizontalPositionMultiplier() { + return mLetterboxHorizontalPositionMultiplier; + } + + /** + * Overrides horizontal position of a center of the letterboxed app window. If given value < 0 + * or > 1, then it and a value of {@link + * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and + * central position (0.5) is used. + */ + void setLetterboxHorizontalPositionMultiplier(float multiplier) { + mLetterboxHorizontalPositionMultiplier = multiplier; + } + + /** + * Resets horizontal position of a center of the letterboxed app window to {@link + * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}. + */ + void resetLetterboxHorizontalPositionMultiplier() { + mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat( + com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier); + } + @Override public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) { if (!checkCallingPermission( diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 5942f34048e7e..68257d4adb7f4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -143,6 +143,10 @@ public class WindowManagerShellCommand extends ShellCommand { return runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw); case "get-letterbox-background-wallpaper-dark-scrim-alpha": return runGetLetterboxBackgroundWallpaperDarkScrimAlpha(pw); + case "set-letterbox-horizontal-position-multiplier": + return runSeLetterboxHorizontalPositionMultiplier(pw); + case "get-letterbox-horizontal-position-multiplier": + return runGetLetterboxHorizontalPositionMultiplier(pw); case "set-sandbox-display-apis": return runSandboxDisplayApis(pw); case "reset": @@ -846,6 +850,43 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private int runSeLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException { + final float multiplier; + try { + String arg = getNextArgRequired(); + if ("reset".equals(arg)) { + synchronized (mInternal.mGlobalLock) { + mInternal.resetLetterboxHorizontalPositionMultiplier(); + } + return 0; + } + multiplier = Float.parseFloat(arg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: bad multiplier format " + e); + return -1; + } catch (IllegalArgumentException e) { + getErrPrintWriter().println( + "Error: 'reset' or multiplier should be provided as an argument " + e); + return -1; + } + synchronized (mInternal.mGlobalLock) { + mInternal.setLetterboxHorizontalPositionMultiplier(multiplier); + } + return 0; + } + + private int runGetLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException { + synchronized (mInternal.mGlobalLock) { + final float multiplier = mInternal.getLetterboxHorizontalPositionMultiplier(); + if (multiplier < 0) { + pw.println("Letterbox horizontal position multiplier is not set"); + } else { + pw.println("Letterbox horizontal position multiplier is " + multiplier); + } + } + return 0; + } + private int runReset(PrintWriter pw) throws RemoteException { int displayId = getDisplayId(getNextArg()); @@ -888,6 +929,9 @@ public class WindowManagerShellCommand extends ShellCommand { // set-letterbox-background-wallpaper-dark-scrim-alpha mInternal.resetLetterboxBackgroundWallpaperDarkScrimAlpha(); + // set-letterbox-horizontal-position-multiplier + mInternal.resetLetterboxHorizontalPositionMultiplier(); + // set-sandbox-display-apis mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true); @@ -954,6 +998,11 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" letterbox background. If alpha < 0 or >= 1 both it and"); pw.println(" R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored and "); pw.println(" 0.0 (transparent) is used instead."); + pw.println(" set-letterbox-horizontal-position-multiplier [reset|multiplier]"); + pw.println(" get-letterbox-horizontal-position-multiplier"); + pw.println(" horizontal position of a center of a letterboxed app. If it < 0 or > 1"); + pw.println(" then both it and R.dimen.config_letterboxHorizontalPositionMultiplier"); + pw.println(" are ignored and central position (0.5) is used."); pw.println(" set-sandbox-display-apis [true|1|false|0]"); pw.println(" Sets override of Display APIs getRealSize / getRealMetrics to reflect "); pw.println(" DisplayArea of the activity, or the window bounds if in letterbox or"); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 7c2cfab50821e..ee1d393285557 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -1515,6 +1515,129 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(primarySplitBounds, letterboxedBounds); } + @Test + public void testUpdateResolvedBoundsHorizontalPosition_left() { + // Display configured as (2800, 1400). + assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( + /* letterboxHorizontalPositionMultiplier */ 0.0f, + // At launch. + /* fixedOrientationLetterbox */ new Rect(0, 0, 700, 1400), + // After 90 degree rotation. + /* sizeCompatUnscaled */ new Rect(0, 0, 700, 1400), + // After the display is resized to (700, 1400). + /* sizeCompatScaled */ new Rect(0, 0, 350, 700)); + } + + @Test + public void testUpdateResolvedBoundsHorizontalPosition_center() { + // Display configured as (2800, 1400). + assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( + /* letterboxHorizontalPositionMultiplier */ 0.5f, + // At launch. + /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), + // After 90 degree rotation. + /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), + // After the display is resized to (700, 1400). + /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); + } + + @Test + public void testUpdateResolvedBoundsHorizontalPosition_invalidMultiplier_defaultToCenter() { + // Display configured as (2800, 1400). + + // Below 0.0. + assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( + /* letterboxHorizontalPositionMultiplier */ -1.0f, + // At launch. + /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), + // After 90 degree rotation. + /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), + // After the display is resized to (700, 1400). + /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); + + // Above 1.0 + assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( + /* letterboxHorizontalPositionMultiplier */ 2.0f, + // At launch. + /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), + // After 90 degree rotation. + /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), + // After the display is resized to (700, 1400). + /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); + } + + @Test + public void testUpdateResolvedBoundsHorizontalPosition_right() { + // Display configured as (2800, 1400). + assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( + /* letterboxHorizontalPositionMultiplier */ 1.0f, + // At launch. + /* fixedOrientationLetterbox */ new Rect(2100, 0, 2800, 1400), + // After 90 degree rotation. + /* sizeCompatUnscaled */ new Rect(700, 0, 1400, 1400), + // After the display is resized to (700, 1400). + /* sizeCompatScaled */ new Rect(1050, 0, 1400, 700)); + } + + private void assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( + float letterboxHorizontalPositionMultiplier, Rect fixedOrientationLetterbox, + Rect sizeCompatUnscaled, Rect sizeCompatScaled) { + // Set up a display in landscape and ignoring orientation request. + setUpDisplaySizeWithApp(2800, 1400); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + mActivity.mWmService.setLetterboxHorizontalPositionMultiplier( + letterboxHorizontalPositionMultiplier); + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + + assertEquals(fixedOrientationLetterbox, mActivity.getBounds()); + + // Rotate to put activity in size compat mode. + rotateDisplay(mActivity.mDisplayContent, ROTATION_90); + + assertTrue(mActivity.inSizeCompatMode()); + // Activity is in size compat mode but not scaled. + assertEquals(sizeCompatUnscaled, mActivity.getBounds()); + + // Force activity to scaled down for size compat mode. + resizeDisplay(mTask.mDisplayContent, 700, 1400); + + assertTrue(mActivity.inSizeCompatMode()); + assertScaled(); + assertEquals(sizeCompatScaled, mActivity.getBounds()); + } + + @Test + public void testUpdateResolvedBoundsHorizontalPosition_activityFillParentWidth() { + // When activity width equals parent width, multiplier shouldn't have any effect. + assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( + /* letterboxHorizontalPositionMultiplier */ 0.0f); + assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( + /* letterboxHorizontalPositionMultiplier */ 0.5f); + assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( + /* letterboxHorizontalPositionMultiplier */ 1.0f); + } + + private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( + float letterboxHorizontalPositionMultiplier) { + // Set up a display in landscape and ignoring orientation request. + setUpDisplaySizeWithApp(2800, 1400); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + mActivity.mWmService.setLetterboxHorizontalPositionMultiplier( + letterboxHorizontalPositionMultiplier); + prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); + + assertFitted(); + + // Rotate to put activity in size compat mode. + rotateDisplay(mActivity.mDisplayContent, ROTATION_90); + + assertTrue(mActivity.inSizeCompatMode()); + // Activity is in size compat mode but not scaled. + assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds()); + } + private static WindowState addWindowToActivity(ActivityRecord activity) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 5bafbbd2bdf79..ae12062987cdb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -101,6 +101,7 @@ import android.window.TransitionRequestInfo; import com.android.internal.policy.AttributeCache; import com.android.internal.util.ArrayUtils; +import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.runner.Description; @@ -208,10 +209,25 @@ class WindowTestsBase extends SystemServiceTestsBase { // {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set // on some device form factors. mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(0); + // Ensure letterbox position multiplier is not overridden on any device target. + // {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}, + // may be set on some device form factors. + mAtm.mWindowManager.setLetterboxHorizontalPositionMultiplier(0.5f); checkDeviceSpecificOverridesNotApplied(); } + @After + public void tearDown() throws Exception { + // Revert back to device overrides. + mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio( + mContext.getResources().getFloat( + com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio)); + mAtm.mWindowManager.setLetterboxHorizontalPositionMultiplier( + mContext.getResources().getFloat( + com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier)); + } + /** * Check that device-specific overrides are not applied. Only need to check once during entire * test run for each case: global overrides, default display, and test display.