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

Commit bf8b16bc authored by Yunfan Chen's avatar Yunfan Chen
Browse files

Fix wrong compat override screen sizes

Override is applied when the insets decouple is enabled and the app is a
legacy app. When calculating the screenWidthDp and screenHeightDp, the
display size excluding status bars, navigation bars, and display cutouts
should be used.

The current implementation is calculating the screenWidthDp and
screenHeightDp by excluding the navigation bars and display cutouts from
the display size. This is not consistent with the legacy behavior of the
system.

When the device has a status bar larger than a display cutout, or the
device doesn't have a display cutout, some app may experience layout
issue because of the inconsistency.

Bug: 391063639
Test: WindowProcessControllerTests
Flag: EXEMPT bugfix
Change-Id: I2e3ac42ac341e8eff7a01dd4985451b7e37a4842
parent 7d2ddd33
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -257,10 +257,12 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
        // This should be the only place override the configuration for ActivityRecord. Override
        // the value if not calculated yet.
        Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
        Rect outConfigBounds = new Rect(outAppBounds);
        if (outAppBounds == null || outAppBounds.isEmpty()) {
            inOutConfig.windowConfiguration.setAppBounds(
                    newParentConfiguration.windowConfiguration.getBounds());
            outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
            outConfigBounds.set(outAppBounds);
            if (task != null) {
                task = task.getCreatedByOrganizerTask();
                if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) {
@@ -279,6 +281,12 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
                    outAppBounds.inset(decor.mOverrideNonDecorInsets);
                }
            }
            if (!outConfigBounds.intersect(decor.mOverrideConfigFrame)) {
                if (inOutConfig.windowConfiguration.getWindowingMode()
                        == WINDOWING_MODE_MULTI_WINDOW) {
                    outAppBounds.inset(decor.mOverrideConfigInsets);
                }
            }
            if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) {
                outAppBounds.offset(-task.mOffsetXForInsets, -task.mOffsetYForInsets);
            }
@@ -289,10 +297,10 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
        }
        density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
        if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
            inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
            inOutConfig.screenWidthDp = (int) (outConfigBounds.width() / density + 0.5f);
        }
        if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
            inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
            inOutConfig.screenHeightDp = (int) (outConfigBounds.height() / density + 0.5f);
        }
        if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
                && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+54 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -33,9 +34,11 @@ import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityRecord.State.STARTED;
import static com.android.server.wm.ActivityRecord.State.STOPPED;
import static com.android.server.wm.ActivityRecord.State.STOPPING;
import static com.android.server.wm.ConfigurationContainer.applySizeOverrideIfNeeded;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -58,6 +61,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.LocaleList;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;

import org.junit.Before;
@@ -453,6 +457,56 @@ public class WindowProcessControllerTests extends WindowTestsBase {
        assertEquals(topDisplayArea, mWpc.getTopActivityDisplayArea());
    }

    @Test
    @EnableFlags(com.android.window.flags.Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION)
    public void testOverrideConfigurationApplied() {
        final DisplayContent displayContent = new TestDisplayContent.Builder(mAtm, 1000, 1500)
                .setSystemDecorations(true).setDensityDpi(160).build();
        final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
        // Setup the decor insets info.
        final DisplayPolicy.DecorInsets.Info decorInsetsInfo = new DisplayPolicy.DecorInsets.Info();
        final Rect emptyRect = new Rect();
        decorInsetsInfo.mNonDecorInsets.set(emptyRect);
        decorInsetsInfo.mConfigInsets.set(emptyRect);
        decorInsetsInfo.mOverrideConfigInsets.set(new Rect(0, 100, 0, 200));
        decorInsetsInfo.mOverrideNonDecorInsets.set(new Rect(0, 0, 0, 200));
        decorInsetsInfo.mNonDecorFrame.set(new Rect(0, 0, 1000, 1500));
        decorInsetsInfo.mConfigFrame.set(new Rect(0, 0, 1000, 1500));
        decorInsetsInfo.mOverrideConfigFrame.set(new Rect(0, 100, 1000, 1300));
        decorInsetsInfo.mOverrideNonDecorFrame.set(new Rect(0, 0, 1000, 1300));
        doReturn(decorInsetsInfo).when(displayPolicy)
                .getDecorInsetsInfo(anyInt(), anyInt(), anyInt());

        final Configuration newParentConfig = displayContent.getConfiguration();
        final Configuration resolvedConfig = new Configuration();

        // Mock the app info to not enforce the decoupled configuration to apply the override.
        final ApplicationInfo appInfo = mock(ApplicationInfo.class);
        doReturn(false).when(appInfo)
                .isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED);
        doReturn(false).when(appInfo)
                .isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);

        // No value should be set before override.
        assertNull(resolvedConfig.windowConfiguration.getAppBounds());
        applySizeOverrideIfNeeded(
                displayContent,
                appInfo,
                newParentConfig,
                resolvedConfig,
                false /* optsOutEdgeToEdge */,
                false /* hasFixedRotationTransform */,
                false /* hasCompatDisplayInsets */,
                null /* task */);

        // Assert the override config insets are applied.
        // Status bars, and all non-decor insets should be deducted for the config screen size.
        assertEquals(1200, resolvedConfig.screenHeightDp);
        // Only the non-decor insets should be deducted for the app bounds.
        assertNotNull(resolvedConfig.windowConfiguration.getAppBounds());
        assertEquals(1300, resolvedConfig.windowConfiguration.getAppBounds().height());
    }

    private TestDisplayContent createTestDisplayContentInContainer() {
        return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
    }