From c99afb71e2bd044672cc11fd2b201aaa626bfad5 Mon Sep 17 00:00:00 2001 From: "jorgegil@google.com" Date: Tue, 10 Aug 2021 08:49:59 -0700 Subject: [PATCH] Respect min/max aspect ratio in freeform launch bounds Bug: 194520339 Test: atest WmTests:TaskLaunchParamsModifierTests Change-Id: I99f86ea49bc62df3fe3861fd25992c3f4e8d1136 --- .../server/wm/TaskLaunchParamsModifier.java | 36 +++++- .../wm/TaskLaunchParamsModifierTests.java | 110 ++++++++++++++++++ 2 files changed, 142 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index f43cd7a80ede6..a77ce7b8cf969 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -713,7 +713,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } // First we get the default size we want. - getDefaultFreeformSize(displayArea, layout, orientation, mTmpBounds); + getDefaultFreeformSize(root.info, displayArea, layout, orientation, mTmpBounds); if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) { // We're here because either input parameters specified initial bounds, or the suggested // bounds have the same size of the default freeform size. We should use the suggested @@ -781,7 +781,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { return orientation; } - private void getDefaultFreeformSize(@NonNull TaskDisplayArea displayArea, + private void getDefaultFreeformSize(@NonNull ActivityInfo info, + @NonNull TaskDisplayArea displayArea, @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) { // Default size, which is letterboxing/pillarboxing in displayArea. That's to say the large // dimension of default size is the small dimension of displayArea size, and the small @@ -812,11 +813,38 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth; final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight; - // Final result. + // Aspect ratio requirements. + final float minAspectRatio = info.getMinAspectRatio(); + final float maxAspectRatio = info.getMaxAspectRatio(); + final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth)); final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight)); + final float aspectRatio = (float) Math.max(width, height) / (float) Math.min(width, height); - bounds.set(0, 0, width, height); + // Adjust the width and height to the aspect ratio requirements. + int adjWidth = width; + int adjHeight = height; + if (minAspectRatio >= 1 && aspectRatio < minAspectRatio) { + // The aspect ratio is below the minimum, adjust it to the minimum. + if (orientation == SCREEN_ORIENTATION_LANDSCAPE) { + // Fix the width, scale the height. + adjHeight = (int) (adjWidth / minAspectRatio + 0.5f); + } else { + // Fix the height, scale the width. + adjWidth = (int) (adjHeight / minAspectRatio + 0.5f); + } + } else if (maxAspectRatio >= 1 && aspectRatio > maxAspectRatio) { + // The aspect ratio exceeds the maximum, adjust it to the maximum. + if (orientation == SCREEN_ORIENTATION_LANDSCAPE) { + // Fix the width, scale the height. + adjHeight = (int) (adjWidth / maxAspectRatio + 0.5f); + } else { + // Fix the height, scale the width. + adjWidth = (int) (adjHeight / maxAspectRatio + 0.5f); + } + } + + bounds.set(0, 0, adjWidth, adjHeight); bounds.offset(stableBounds.left, stableBounds.top); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index e528a4a23e459..168c250a8c930 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1320,6 +1320,50 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { DISPLAY_STABLE_BOUNDS.bottom - mResult.mBounds.bottom, /* delta */ 1); } + @Test + public void testDefaultFreeformSizeRespectsMinAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMinAspectRatio(5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder() + .setOptions(options).calculate()); + + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at least 5.0, but was " + aspectRatio, + aspectRatio >= 5f); + } + + @Test + public void testDefaultFreeformSizeRespectsMaxAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMaxAspectRatio(1.5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder() + .setOptions(options).calculate()); + + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at most 1.5, but was " + aspectRatio, + aspectRatio <= 1.5f); + } + @Test public void testCascadesToSourceSizeForFreeform() { final TestDisplayContent freeformDisplay = createNewDisplayContent( @@ -1347,6 +1391,72 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { mResult.mBounds.centerY() < displayBounds.centerY()); } + @Test + public void testCascadesToSourceSizeForFreeformRespectingMinAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + final ActivityRecord source = createSourceActivity(freeformDisplay); + source.setBounds(0, 0, 412, 732); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMinAspectRatio(5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder().setSource(source).setOptions(options).calculate()); + + final Rect displayBounds = freeformDisplay.getBounds(); + assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0); + assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0); + assertTrue("Bounds should be centered at somewhere in the left half, but it's " + + "centerX is " + mResult.mBounds.centerX(), + mResult.mBounds.centerX() < displayBounds.centerX()); + assertTrue("Bounds should be centered at somewhere in the top half, but it's " + + "centerY is " + mResult.mBounds.centerY(), + mResult.mBounds.centerY() < displayBounds.centerY()); + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at least 5.0, but was " + aspectRatio, + aspectRatio >= 5f); + } + + @Test + public void testCascadesToSourceSizeForFreeformRespectingMaxAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + final ActivityRecord source = createSourceActivity(freeformDisplay); + source.setBounds(0, 0, 412, 732); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMaxAspectRatio(1.5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder().setSource(source).setOptions(options).calculate()); + + final Rect displayBounds = freeformDisplay.getBounds(); + assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0); + assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0); + assertTrue("Bounds should be centered at somewhere in the left half, but it's " + + "centerX is " + mResult.mBounds.centerX(), + mResult.mBounds.centerX() < displayBounds.centerX()); + assertTrue("Bounds should be centered at somewhere in the top half, but it's " + + "centerY is " + mResult.mBounds.centerY(), + mResult.mBounds.centerY() < displayBounds.centerY()); + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at most 1.5, but was " + aspectRatio, + aspectRatio <= 1.5f); + } + @Test public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() { final TestDisplayContent freeformDisplay = createNewDisplayContent(