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

Commit ea12f9a7 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. When a different value is reported in smallestScreenWidthDp, the app can load incorrect layout.

Test: atest WmTests:SizeCompatTests
Fix: 232406936
Change-Id: Ie0d7767fba03cc07e21e3624d9d8c5b0ea13dff1
parent 91079f44
Loading
Loading
Loading
Loading
+6 −8
Original line number Original line Diff line number Diff line
@@ -7737,9 +7737,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // relatively fixed.
        // relatively fixed.
        overrideConfig.colorMode = fullConfig.colorMode;
        overrideConfig.colorMode = fullConfig.colorMode;
        overrideConfig.densityDpi = fullConfig.densityDpi;
        overrideConfig.densityDpi = fullConfig.densityDpi;
        // 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;
        if (info.isFixedOrientation()) {
        if (info.isFixedOrientation()) {
            // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
            // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
            // apply runtime rotation changes.
            // apply runtime rotation changes.
@@ -7836,7 +7833,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            // computed accordingly.
            // computed accordingly.
            if (!matchParentBounds()) {
            if (!matchParentBounds()) {
                getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
                getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
                        newParentConfiguration);
                        newParentConfiguration, areBoundsLetterboxed());
            }
            }
        // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
        // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
        // are already calculated in resolveFixedOrientationConfiguration.
        // are already calculated in resolveFixedOrientationConfiguration.
@@ -8007,7 +8004,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
        }


        // Since bounds has changed, the configuration needs to be computed accordingly.
        // Since bounds has changed, the configuration needs to be computed accordingly.
        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                areBoundsLetterboxed());
    }
    }


    void recomputeConfiguration() {
    void recomputeConfiguration() {
@@ -8223,7 +8221,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Calculate app bounds using fixed orientation bounds because they will be needed later
        // Calculate app bounds using fixed orientation bounds because they will be needed later
        // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
        // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
        getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
        getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
                newParentConfig);
                newParentConfig, mCompatDisplayInsets, areBoundsLetterboxed());
        mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
        mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
    }
    }


@@ -8251,7 +8249,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
            // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
            // restrict, the bounds should be the requested override bounds.
            // restrict, the bounds should be the requested override bounds.
            getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
            getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                    getFixedRotationTransformDisplayInfo());
                    getFixedRotationTransformDisplayInfo(), areBoundsLetterboxed());
        }
        }
    }
    }


@@ -8315,7 +8313,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // are calculated in compat container space. The actual position on screen will be applied
        // are calculated in compat container space. The actual position on screen will be applied
        // later, so the calculation is simpler that doesn't need to involve offset from parent.
        // later, so the calculation is simpler that doesn't need to involve offset from parent.
        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                mCompatDisplayInsets);
                mCompatDisplayInsets,  areBoundsLetterboxed());
        // Use current screen layout as source because the size of app is independent to parent.
        // Use current screen layout as source because the size of app is independent to parent.
        resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
        resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
                getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
                getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
+20 −9
Original line number Original line Diff line number Diff line
@@ -1957,29 +1957,37 @@ class TaskFragment extends WindowContainer<WindowContainer> {
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig) {
            @NonNull Configuration parentConfig) {
        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
                null /* compatInsets */);
                null /* compatInsets */, false /* areBoundsLetterboxed */);
    }
    }


    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
            @NonNull Configuration parentConfig, boolean areBoundsLetterboxed) {
        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
                null /* compatInsets */, areBoundsLetterboxed);
    }

    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
            boolean areBoundsLetterboxed) {
        if (overrideDisplayInfo != null) {
        if (overrideDisplayInfo != null) {
            // Make sure the screen related configs can be computed by the provided display info.
            // Make sure the screen related configs can be computed by the provided display info.
            inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
            inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
            invalidateAppBoundsConfig(inOutConfig);
            invalidateAppBoundsConfig(inOutConfig);
        }
        }
        computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
        computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
                null /* compatInsets */);
                null /* compatInsets */, areBoundsLetterboxed);
    }
    }


    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig,
            @NonNull Configuration parentConfig,
            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
            @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
            boolean areBoundsLetterboxed) {
        if (compatInsets != null) {
        if (compatInsets != null) {
            // Make sure the app bounds can be computed by the compat insets.
            // Make sure the app bounds can be computed by the compat insets.
            invalidateAppBoundsConfig(inOutConfig);
            invalidateAppBoundsConfig(inOutConfig);
        }
        }
        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
                compatInsets);
                compatInsets, areBoundsLetterboxed);
    }
    }


    /**
    /**
@@ -2006,7 +2014,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
     **/
     **/
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
            @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
            boolean areBoundsLetterboxed) {
        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2113,6 +2122,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
                        : overrideScreenHeightDp;
                        : overrideScreenHeightDp;
            }
            }


            // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
            if (inOutConfig.smallestScreenWidthDp
            if (inOutConfig.smallestScreenWidthDp
                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
                // When entering to or exiting from Pip, the PipTaskOrganizer will set the
                // When entering to or exiting from Pip, the PipTaskOrganizer will set the
@@ -2128,9 +2138,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
                    // task, because they should not be affected by insets.
                    // task, because they should not be affected by insets.
                    inOutConfig.smallestScreenWidthDp = (int) (0.5f
                    inOutConfig.smallestScreenWidthDp = (int) (0.5f
                            + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
                            + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
                } else if (isEmbedded()) {
                } else if (isEmbedded() || areBoundsLetterboxed || customContainerPolicy) {
                    // For embedded TFs, the smallest width should be updated. Otherwise, inherit
                    // For embedded TFs and activities that are letteboxed or eligible for size
                    // from the parent task would result in applications loaded wrong resource.
                    // compat mode, the smallest width should be updated. Otherwise, inherit from
                    // the parent task would result in applications loaded wrong resource.
                    inOutConfig.smallestScreenWidthDp =
                    inOutConfig.smallestScreenWidthDp =
                            Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
                            Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
                }
                }
+73 −0
Original line number Original line Diff line number Diff line
@@ -1495,6 +1495,79 @@ public class SizeCompatTests extends WindowTestsBase {
        assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5);
        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
    @Test
    public void testSplitAspectRatioForUnresizablePortraitApps() {
    public void testSplitAspectRatioForUnresizablePortraitApps() {
        // Set up a display in landscape and ignoring orientation request.
        // Set up a display in landscape and ignoring orientation request.
+2 −1
Original line number Original line Diff line number Diff line
@@ -691,7 +691,8 @@ public class TaskTests extends WindowTestsBase {
        final ActivityRecord.CompatDisplayInsets compatInsets =
        final ActivityRecord.CompatDisplayInsets compatInsets =
                new ActivityRecord.CompatDisplayInsets(
                new ActivityRecord.CompatDisplayInsets(
                        display, activity, /* fixedOrientationBounds= */ null);
                        display, activity, /* fixedOrientationBounds= */ null);
        task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
        task.computeConfigResourceOverrides(
                inOutConfig, parentConfig, compatInsets, /* areBoundsLetterboxed */ true);


        assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
        assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
        final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
        final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;