summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yunfan Chen <yunfanc@google.com> 2025-02-09 22:38:36 -0800
committer Yunfan Chen <yunfanc@google.com> 2025-02-13 15:01:46 +0900
commitbf8b16bc6cf96fe58049a3b525c773d97d9b7ace (patch)
tree5c2793d93357d12fa19824c1ad68f9c43e075a6e
parent7d2ddd33d9715f791ec4fa930a2c2aa3a46120bf (diff)
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
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java54
2 files changed, 64 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 05dcbb7f9af4..aaa18ad6acc9 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -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) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 1dfb20a41816..d228970e0371 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -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();
}