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
diff --git a/services/core/java/com/android/server/wm/LaunchParamsUtil.java b/services/core/java/com/android/server/wm/LaunchParamsUtil.java
index 91469a0..09a17e1 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 @@
private static final int DISPLAY_EDGE_OFFSET_DP = 27;
+ private static final Rect TMP_STABLE_BOUNDS = new Rect();
+
private LaunchParamsUtil() {}
/**
@@ -130,18 +132,42 @@
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 f51a173..14a2d03 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 @@
// 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 @@
@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 dce9f66..1188f49 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 @@
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;
@@ -1346,6 +1351,20 @@
}
@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(
WINDOWING_MODE_FREEFORM);
@@ -1535,16 +1554,15 @@
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 @@
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 @@
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 @@
}
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;
}