From d4fa6371286ebebd5e4a0fe3c51aa9c8c13e292d Mon Sep 17 00:00:00 2001 From: Kazuki Takise Date: Mon, 11 Apr 2022 18:01:54 +0900 Subject: [PATCH] Shrink default launch bounds on small display The current implementation doesn't allow changing the default launch size when it doesn't fit the display. However, lots of apps have important UI pieces on top or bottom, so having a window height larger than the display height can degrade the usability of such app a lot. More and more laptops have horizentally longer displays these days, so this problem is getting more common. I think any adjustment will be small enough not to affect apps' layouts much. Also, this logic cannot make the app smaller than the min sizes defined by the system or apps. Bug: 185427982 Test: atest WmTests:TaskLaunchParamsModifierTests Change-Id: I53171bba183e5f00be3118d41c57731b5e3d5e19 --- .../android/server/wm/LaunchParamsUtil.java | 42 ++++++++++++---- .../server/wm/TaskLaunchParamsModifier.java | 6 +-- .../wm/TaskLaunchParamsModifierTests.java | 48 ++++++++++++++----- 3 files changed, 73 insertions(+), 23 deletions(-) diff --git a/services/core/java/com/android/server/wm/LaunchParamsUtil.java b/services/core/java/com/android/server/wm/LaunchParamsUtil.java index 91469a065eeca..09a17e166f46e 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsUtil.java +++ b/services/core/java/com/android/server/wm/LaunchParamsUtil.java @@ -46,6 +46,8 @@ class LaunchParamsUtil { private static final int DISPLAY_EDGE_OFFSET_DP = 27; + private static final Rect TMP_STABLE_BOUNDS = new Rect(); + private LaunchParamsUtil() {} /** @@ -130,18 +132,42 @@ class LaunchParamsUtil { return new Size(adjWidth, adjHeight); } - static void adjustBoundsToFitInDisplayArea(@NonNull Rect stableBounds, int layoutDirection, + static void adjustBoundsToFitInDisplayArea(@NonNull TaskDisplayArea displayArea, + int layoutDirection, @NonNull ActivityInfo.WindowLayout layout, @NonNull Rect inOutBounds) { + // Give a small margin between the window bounds and the display bounds. + final Rect stableBounds = TMP_STABLE_BOUNDS; + displayArea.getStableRect(stableBounds); + final float density = (float) displayArea.getConfiguration().densityDpi / DENSITY_DEFAULT; + final int displayEdgeOffset = (int) (DISPLAY_EDGE_OFFSET_DP * density + 0.5f); + stableBounds.inset(displayEdgeOffset, displayEdgeOffset); + if (stableBounds.width() < inOutBounds.width() || stableBounds.height() < inOutBounds.height()) { - // There is no way for us to fit the bounds in the displayArea without changing width - // or height. Just move the start to align with the displayArea. - final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL - ? stableBounds.right - inOutBounds.right + inOutBounds.left - : stableBounds.left; - inOutBounds.offsetTo(left, stableBounds.top); - return; + final float heightShrinkRatio = stableBounds.width() / (float) inOutBounds.width(); + final float widthShrinkRatio = + stableBounds.height() / (float) inOutBounds.height(); + final float shrinkRatio = Math.min(heightShrinkRatio, widthShrinkRatio); + // Minimum layout requirements. + final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth; + final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight; + int adjustedWidth = Math.max(layoutMinWidth, (int) (inOutBounds.width() * shrinkRatio)); + int adjustedHeight = Math.max(layoutMinHeight, + (int) (inOutBounds.height() * shrinkRatio)); + if (stableBounds.width() < adjustedWidth + || stableBounds.height() < adjustedHeight) { + // There is no way for us to fit the bounds in the displayArea without breaking min + // size constraints. Set the min size to make visible as much content as possible. + final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL + ? stableBounds.right - adjustedWidth + : stableBounds.left; + inOutBounds.set(left, stableBounds.top, left + adjustedWidth, + stableBounds.top + adjustedHeight); + return; + } + inOutBounds.set(inOutBounds.left, inOutBounds.top, + inOutBounds.left + adjustedWidth, inOutBounds.top + adjustedHeight); } final int dx; diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index f51a173924cb6..14a2d0383019e 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -768,9 +768,10 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // to the center of suggested bounds (or the displayArea if no suggested bounds). The // default size might be too big to center to source activity bounds in displayArea, so // we may need to move it back to the displayArea. + adjustBoundsToFitInDisplayArea(displayArea, layout, mTmpBounds); + inOutBounds.setEmpty(); LaunchParamsUtil.centerBounds(displayArea, mTmpBounds.width(), mTmpBounds.height(), inOutBounds); - adjustBoundsToFitInDisplayArea(displayArea, layout, inOutBounds); if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds); } @@ -821,8 +822,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { @NonNull Rect inOutBounds) { final int layoutDirection = mSupervisor.mRootWindowContainer.getConfiguration() .getLayoutDirection(); - displayArea.getStableRect(mTmpStableBounds); - LaunchParamsUtil.adjustBoundsToFitInDisplayArea(mTmpStableBounds, layoutDirection, layout, + LaunchParamsUtil.adjustBoundsToFitInDisplayArea(displayArea, layoutDirection, layout, inOutBounds); } 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 dce9f66356535..1188f49ae60e9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -85,6 +85,11 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { private static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100, /* top */ 200, /* right */ 1620, /* bottom */ 680); + private static final Rect SMALL_DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0, + /* right */ 1000, /* bottom */ 500); + private static final Rect SMALL_DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100, + /* top */ 50, /* right */ 900, /* bottom */ 450); + private ActivityRecord mActivity; private TaskLaunchParamsModifier mTarget; @@ -1345,6 +1350,20 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { DISPLAY_STABLE_BOUNDS.bottom - mResult.mBounds.bottom, /* delta */ 1); } + @Test + public void testDefaultFreeformSizeShrinksOnSmallDisplay() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM, SMALL_DISPLAY_BOUNDS, SMALL_DISPLAY_STABLE_BOUNDS); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setOptions(options) + .calculate()); + + assertEquals(new Rect(414, 77, 587, 423), mResult.mBounds); + } + @Test public void testDefaultFreeformSizeRespectsMinAspectRatio() { final TestDisplayContent freeformDisplay = createNewDisplayContent( @@ -1535,16 +1554,15 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { options.setLaunchDisplayId(freeformDisplay.mDisplayId); mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM; - mCurrent.mBounds.set(100, 300, 1820, 1380); + mCurrent.mBounds.set(0, 0, 3000, 2000); mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setOptions(options).calculate()); - assertTrue("Result bounds should start from app bounds's origin, but it's " - + mResult.mBounds, - mResult.mBounds.left == 100 && mResult.mBounds.top == 200); + // Must shrink to fit the display while reserving aspect ratio. + assertEquals(new Rect(127, 227, 766, 653), mResult.mBounds); } @Test @@ -1560,18 +1578,19 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchDisplayId(freeformDisplay.mDisplayId); + final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder() + .setMinWidth(500).setMinHeight(500).build(); mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM; - mCurrent.mBounds.set(100, 300, 1820, 1380); + mCurrent.mBounds.set(0, 0, 2000, 3000); mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; assertEquals(RESULT_CONTINUE, - new CalculateRequestBuilder().setOptions(options).calculate()); + new CalculateRequestBuilder().setOptions(options).setLayout(layout).calculate()); - assertTrue("Result bounds should start from top-right corner of app bounds, but " - + "it's " + mResult.mBounds, - mResult.mBounds.left == -100 && mResult.mBounds.top == 200); + // Must shrink to fit the display while reserving aspect ratio. + assertEquals(new Rect(1093, 227, 1593, 727), mResult.mBounds); } @Test @@ -1746,7 +1765,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setOptions(options).calculate()); - assertEquals(new Rect(100, 200, 400, 500), mResult.mBounds); + assertEquals(new Rect(127, 227, 427, 527), mResult.mBounds); } @Test @@ -1799,13 +1818,18 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { } private TestDisplayContent createNewDisplayContent(int windowingMode) { + return createNewDisplayContent(windowingMode, DISPLAY_BOUNDS, DISPLAY_STABLE_BOUNDS); + } + + private TestDisplayContent createNewDisplayContent(int windowingMode, Rect displayBounds, + Rect displayStableBounds) { final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); display.getDefaultTaskDisplayArea().setWindowingMode(windowingMode); - display.setBounds(DISPLAY_BOUNDS); + display.setBounds(displayBounds); display.getConfiguration().densityDpi = DENSITY_DEFAULT; display.getConfiguration().orientation = ORIENTATION_LANDSCAPE; configInsetsState(display.getInsetsStateController().getRawInsetsState(), display, - DISPLAY_STABLE_BOUNDS); + displayStableBounds); return display; }