Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4fa6371 authored by Kazuki Takise's avatar Kazuki Takise
Browse files

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
parent 03529c60
Loading
Loading
Loading
Loading
+34 −8
Original line number Diff line number Diff line
@@ -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,19 +132,43 @@ 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 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 - inOutBounds.right + inOutBounds.left
                        ? stableBounds.right - adjustedWidth
                        : stableBounds.left;
            inOutBounds.offsetTo(left, stableBounds.top);
                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;
        if (inOutBounds.right > stableBounds.right) {
+3 −3
Original line number Diff line number Diff line
@@ -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);
    }

+36 −12
Original line number Diff line number Diff line
@@ -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;
    }