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

Commit 5aa29ae5 authored by Mariia Sandrikova's avatar Mariia Sandrikova
Browse files

Adjust smallestScreenWidthDp for letterbox

By definition, smallestScreenWidthDp is the smallest value of both screenWidthDp and screenHeightDp in both portrait and landscape orientations. When a different value is reported in smallestScreenWidthDp, the app can load incorrect layout.

Also, move updateCompatDisplayInsets to ensureActivityConfiguration to guarantee that it is called after the full config is updated in ConfigurationContainer#onConfigurationChanged

Revert "Revert "Adjust smallestScreenWidthDp for letterbox""
This reverts commit f20212ad.

Reason for revert: Fixing the problem that led to the original revert: in the original CL, smallestScreenWidthDp for activities eligible for size-compat mode wasn't guaranteed to be constant and equal to a minimum between screenWidthDp and screenHeightDp because computeConfigResourceOverrides wasn't triggered from ActivityRecord with mCompatDisplayInsets passed as a parameter when activity was cold started in a configuration that didn't require letterboxing.

Test: atest WmTests:SizeCompatTests
Fix: 232406936

Change-Id: Ib4b88360312795097e33d422c444c0e855a06a7b
parent fa71876c
Loading
Loading
Loading
Loading
+33 −9
Original line number Diff line number Diff line
@@ -7934,6 +7934,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // The smallest screen width is the short side of screen bounds. Because the bounds
        // and density won't be changed, smallestScreenWidthDp is also fixed.
        overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
        // TODO(b/264276741): Check whether the runtime orietnation request is fixed rather than
        // the manifest orientation which may be obsolete.
        if (info.isFixedOrientation()) {
            // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
            // apply runtime rotation changes.
@@ -8047,8 +8049,24 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            updateResolvedBoundsPosition(newParentConfiguration);
        }

        if (mVisibleRequested) {
            updateCompatDisplayInsets();
        boolean isIgnoreOrientationRequest = mDisplayContent != null
                && mDisplayContent.getIgnoreOrientationRequest();
        if (mCompatDisplayInsets == null // for size compat mode set in updateCompatDisplayInsets
                // Fixed orientation letterboxing is possible on both large screen devices
                // with ignoreOrientationRequest enabled and on phones in split screen even with
                // ignoreOrientationRequest disabled.
                && (mLetterboxBoundsForFixedOrientationAndAspectRatio != null
                        // Limiting check for aspect ratio letterboxing to devices with enabled
                        // ignoreOrientationRequest. This avoids affecting phones where apps may
                        // not expect the change of smallestScreenWidthDp after rotation which is
                        // possible with this logic. Not having smallestScreenWidthDp completely
                        // accurate on phones shouldn't make the big difference and is expected
                        // to be already well-tested by apps.
                        || (isIgnoreOrientationRequest && mIsAspectRatioApplied))) {
            // TODO(b/264034555): Use mDisplayContent to calculate smallestScreenWidthDp from all
            // rotations and only re-calculate if parent bounds have non-orientation size change.
            resolvedConfig.smallestScreenWidthDp =
                    Math.min(resolvedConfig.screenWidthDp, resolvedConfig.screenHeightDp);
        }

        // Assign configuration sequence number into hierarchy because there is a different way than
@@ -8436,7 +8454,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Calculate app bounds using fixed orientation bounds because they will be needed later
        // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
        getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
                newParentConfig);
                newParentConfig, mCompatDisplayInsets);
        mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
    }

@@ -9107,6 +9125,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            mLastReportedDisplayId = newDisplayId;
        }

        // Calling from here rather than from onConfigurationChanged because it's possible that
        // onConfigurationChanged was called before mVisibleRequested became true and
        // mCompatDisplayInsets may not be called again when mVisibleRequested changes. And we
        // don't want to save mCompatDisplayInsets in onConfigurationChanged without visibility
        // check to avoid remembering obsolete configuration which can lead to unnecessary
        // size-compat mode.
        if (mVisibleRequested) {
            // Calling from here rather than resolveOverrideConfiguration to ensure that this is
            // called after full config is updated in ConfigurationContainer#onConfigurationChanged.
            updateCompatDisplayInsets();
        }

        // Short circuit: if the two full configurations are equal (the common case), then there is
        // nothing to do.  We test the full configuration instead of the global and merged override
        // configurations because there are cases (like moving a task to the root pinned task) where
@@ -9115,12 +9145,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
                    + "unchanged in %s", this);
            // It's possible that resolveOverrideConfiguration was called before mVisibleRequested
            // became true and mCompatDisplayInsets may not have been created so ensure
            // that mCompatDisplayInsets is created here.
            if (mVisibleRequested) {
                updateCompatDisplayInsets();
            }
            return true;
        }

+2 −1
Original line number Diff line number Diff line
@@ -2124,7 +2124,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {

        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
        final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
        if (resolvedBounds == null || resolvedBounds.isEmpty()) {
        if (resolvedBounds.isEmpty()) {
            mTmpFullBounds.set(parentBounds);
            insideParentBounds = true;
        } else {
@@ -2213,6 +2213,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
                        : overrideScreenHeightDp;
            }

            // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
            if (inOutConfig.smallestScreenWidthDp
                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
                // When entering to or exiting from Pip, the PipTaskOrganizer will set the
+73 −0
Original line number Diff line number Diff line
@@ -1616,6 +1616,79 @@ public class SizeCompatTests extends WindowTestsBase {
        assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5);
    }

    @Test
    public void testComputeConfigResourceOverrides_unresizableApp() {
        // Set up a display in landscape and ignoring orientation request.
        setUpDisplaySizeWithApp(2800, 1400);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);

        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);

        final Rect activityBounds = new Rect(mActivity.getBounds());

        int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
        int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;

        // App should launch in fixed orientation letterbox.
        // Activity bounds should be 700x1400 with the ratio as the display.
        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
        assertFitted();
        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
        assertTrue(originalScreenWidthDp < originalScreenHeighthDp);

        // Rotate display to portrait.
        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);

        // After we rotate, the activity should go in the size-compat mode and report the same
        // configuration values.
        assertScaled();
        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
        assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);

        // Restart activity
        mActivity.restartProcessIfVisible();

        // Now configuration should be updated
        assertFitted();
        assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
        assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
        assertEquals(mActivity.getConfiguration().screenWidthDp,
                mActivity.getConfiguration().smallestScreenWidthDp);
    }

    @Test
    public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() {
        // Set up a display in landscape and ignoring orientation request.
        setUpDisplaySizeWithApp(2800, 1400);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);

        // Portrait fixed app without max aspect.
        prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */);

        final Rect activityBounds = new Rect(mActivity.getBounds());

        int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
        int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;

        // App should launch in fixed orientation letterbox.
        // Activity bounds should be 700x1400 with the ratio as the display.
        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
        assertFitted();
        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
        assertTrue(originalScreenWidthDp < originalScreenHeighthDp);

        // Rotate display to portrait.
        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);

        // Now configuration should be updated
        assertFitted();
        assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
        assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
        assertEquals(mActivity.getConfiguration().screenWidthDp,
                mActivity.getConfiguration().smallestScreenWidthDp);
    }

    @Test
    public void testSplitAspectRatioForUnresizablePortraitApps() {
        // Set up a display in landscape and ignoring orientation request.