summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tiger <tigerhuang@google.com> 2024-07-03 21:10:14 +0800
committer Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2024-07-15 23:15:13 +0000
commit9b84dabc96d2414986439a0d2f55f5150098d0ca (patch)
treeb7bcc45e874a68a3602ff2aaef782538b9c563a7
parent1f7fc92a2acba0c6bdf5d698c72316f0772be769 (diff)
Re-land: Let WindowProcessController apply app specific config
Since the feature of insetsDecoupledConfiguration, targetSdk can affect the app sizes of the configuration. An app might get the configuration from WindowProcessController before the size is overridden by the ActivityRecord. This CL applies the size override to WindowProcessController as well so that apps won't get the unexpected apps size from the configuration. This CL also fixes a bug that the appBounds would still be affected by insets even when the bounds is not overlapped with the insets area. Fix: 347136833 Bug: 151861875 Flag: com.android.window.flags.insets_decoupled_configuration Test: atest WindowPolicyTests QSMediaPlayerContent WindowProcessControllerTests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:11374298355d57672609acbbea041e6621b95d88) Merged-In: I3b373607ffc0a6c1b4e6ecffb4a2857fc0d18d9d Change-Id: I3b373607ffc0a6c1b4e6ecffb4a2857fc0d18d9d
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java105
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java117
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java2
4 files changed, 143 insertions, 97 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8f0517435aed..de16683f2d77 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -53,7 +53,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.isFloating;
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
@@ -342,7 +341,6 @@ import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
@@ -8667,7 +8665,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
- applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+ applySizeOverrideIfNeeded(
+ mDisplayContent,
+ info.applicationInfo,
+ newParentConfiguration,
+ resolvedConfig,
+ mOptOutEdgeToEdge,
+ hasFixedRotationTransform(),
+ getCompatDisplayInsets() != null);
mResolveConfigHint.resetTmpOverrides();
logAppCompatState();
@@ -8677,100 +8682,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return Rect.copyOrNull(mResolveConfigHint.mParentAppBoundsOverride);
}
- /**
- * If necessary, override configuration fields related to app bounds.
- * This will happen when the app is targeting SDK earlier than 35.
- * The insets and configuration has decoupled since SDK level 35, to make the system
- * compatible to existing apps, override the configuration with legacy metrics. In legacy
- * metrics, fields such as appBounds will exclude some of the system bar areas.
- * The override contains all potentially affected fields in Configuration, including
- * screenWidthDp, screenHeightDp, smallestScreenWidthDp, and orientation.
- * All overrides to those fields should be in this method.
- *
- * TODO: Consider integrate this with computeConfigByResolveHint()
- */
- private void applySizeOverrideIfNeeded(Configuration newParentConfiguration,
- int parentWindowingMode, Configuration inOutConfig) {
- if (mDisplayContent == null) {
- return;
- }
- final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
- int rotation = newParentConfiguration.windowConfiguration.getRotation();
- if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
- rotation = mDisplayContent.getRotation();
- }
- if (!mOptOutEdgeToEdge && (!mResolveConfigHint.mUseOverrideInsetsForConfig
- || getCompatDisplayInsets() != null
- || (isFloating(parentWindowingMode)
- // Check the requested windowing mode of activity as well in case it is
- // switching between PiP and fullscreen.
- && (inOutConfig.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_UNDEFINED
- || isFloating(inOutConfig.windowConfiguration.getWindowingMode())))
- || rotation == ROTATION_UNDEFINED)) {
- // If the insets configuration decoupled logic is not enabled for the app, or the app
- // already has a compat override, or the context doesn't contain enough info to
- // calculate the override, skip the override.
- return;
- }
- // Make sure the orientation related fields will be updated by the override insets, because
- // fixed rotation has assigned the fields from display's configuration.
- if (hasFixedRotationTransform()) {
- inOutConfig.windowConfiguration.setAppBounds(null);
- inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
- inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
- inOutConfig.smallestScreenWidthDp = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
- inOutConfig.orientation = ORIENTATION_UNDEFINED;
- }
-
- // Override starts here.
- final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
- : mDisplayContent.mBaseDisplayWidth;
- final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
- : mDisplayContent.mBaseDisplayHeight;
- final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
- .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
- // This should be the only place override the configuration for ActivityRecord. Override
- // the value if not calculated yet.
- Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- if (outAppBounds == null || outAppBounds.isEmpty()) {
- inOutConfig.windowConfiguration.setAppBounds(parentBounds);
- outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- outAppBounds.inset(nonDecorInsets);
- }
- float density = inOutConfig.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = newParentConfiguration.densityDpi;
- }
- density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
- }
- if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
- }
- if (inOutConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
- && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
- // For the case of PIP transition and multi-window environment, the
- // smallestScreenWidthDp is handled already. Override only if the app is in
- // fullscreen.
- final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
- mDisplayContent.computeSizeRanges(info, rotated, dw, dh,
- mDisplayContent.getDisplayMetrics().density,
- inOutConfig, true /* overrideConfig */);
- }
-
- // It's possible that screen size will be considered in different orientation with or
- // without considering the system bar insets. Override orientation as well.
- if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
- inOutConfig.orientation =
- (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- }
- }
-
private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
@NonNull Configuration parentConfig) {
task.computeConfigResourceOverrides(resolvedConfig, parentConfig, mResolveConfigHint);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index efd52026cfec..a38ac9ba4b75 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -22,14 +22,23 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.isFloating;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.app.WindowConfigurationProto.WINDOWING_MODE;
import static android.content.ConfigurationProto.WINDOW_CONFIGURATION;
+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.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
@@ -38,11 +47,14 @@ import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGU
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.WindowConfiguration;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.LocaleList;
+import android.util.DisplayMetrics;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -173,6 +185,111 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
}
+ /**
+ * If necessary, override configuration fields related to app bounds.
+ * This will happen when the app is targeting SDK earlier than 35.
+ * The insets and configuration has decoupled since SDK level 35, to make the system
+ * compatible to existing apps, override the configuration with legacy metrics. In legacy
+ * metrics, fields such as appBounds will exclude some of the system bar areas.
+ * The override contains all potentially affected fields in Configuration, including
+ * screenWidthDp, screenHeightDp, smallestScreenWidthDp, and orientation.
+ * All overrides to those fields should be in this method.
+ *
+ * TODO: Consider integrate this with computeConfigByResolveHint()
+ */
+ static void applySizeOverrideIfNeeded(DisplayContent displayContent, ApplicationInfo appInfo,
+ Configuration newParentConfiguration, Configuration inOutConfig,
+ boolean optOutEdgeToEdge, boolean hasFixedRotationTransform,
+ boolean hasCompatDisplayInsets) {
+ if (displayContent == null) {
+ return;
+ }
+ final boolean useOverrideInsetsForConfig =
+ displayContent.mWmService.mFlags.mInsetsDecoupledConfiguration
+ ? !appInfo.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
+ && !appInfo.isChangeEnabled(
+ OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION)
+ : appInfo.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
+ final int parentWindowingMode =
+ newParentConfiguration.windowConfiguration.getWindowingMode();
+ final boolean isFloating = isFloating(parentWindowingMode)
+ // Check the requested windowing mode of activity as well in case it is
+ // switching between PiP and fullscreen.
+ && (inOutConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_UNDEFINED
+ || isFloating(inOutConfig.windowConfiguration.getWindowingMode()));
+ final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
+ int rotation = newParentConfiguration.windowConfiguration.getRotation();
+ if (rotation == ROTATION_UNDEFINED && !hasFixedRotationTransform) {
+ rotation = displayContent.getRotation();
+ }
+ if (!optOutEdgeToEdge && (!useOverrideInsetsForConfig
+ || hasCompatDisplayInsets
+ || isFloating
+ || rotation == ROTATION_UNDEFINED)) {
+ // If the insets configuration decoupled logic is not enabled for the app, or the app
+ // already has a compat override, or the context doesn't contain enough info to
+ // calculate the override, skip the override.
+ return;
+ }
+ // Make sure the orientation related fields will be updated by the override insets, because
+ // fixed rotation has assigned the fields from display's configuration.
+ if (hasFixedRotationTransform) {
+ inOutConfig.windowConfiguration.setAppBounds(null);
+ inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+ inOutConfig.smallestScreenWidthDp = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.orientation = ORIENTATION_UNDEFINED;
+ }
+
+ // Override starts here.
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated
+ ? displayContent.mBaseDisplayHeight
+ : displayContent.mBaseDisplayWidth;
+ final int dh = rotated
+ ? displayContent.mBaseDisplayWidth
+ : displayContent.mBaseDisplayHeight;
+ final Rect nonDecorFrame = displayContent.getDisplayPolicy()
+ .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorFrame;
+ // This should be the only place override the configuration for ActivityRecord. Override
+ // the value if not calculated yet.
+ Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds == null || outAppBounds.isEmpty()) {
+ inOutConfig.windowConfiguration.setAppBounds(parentBounds);
+ outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ outAppBounds.intersect(nonDecorFrame);
+ }
+ float density = inOutConfig.densityDpi;
+ if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+ density = newParentConfiguration.densityDpi;
+ }
+ density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
+ }
+ if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
+ }
+ if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
+ && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // For the case of PIP transition and multi-window environment, the
+ // smallestScreenWidthDp is handled already. Override only if the app is in
+ // fullscreen.
+ final DisplayInfo info = new DisplayInfo(displayContent.getDisplayInfo());
+ displayContent.computeSizeRanges(info, rotated, dw, dh,
+ displayContent.getDisplayMetrics().density,
+ inOutConfig, true /* overrideConfig */);
+ }
+
+ // It's possible that screen size will be considered in different orientation with or
+ // without considering the system bar insets. Override orientation as well.
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+ inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT
+ : ORIENTATION_LANDSCAPE;
+ }
+ }
+
/** Returns {@code true} if requested override override configuration is not empty. */
boolean hasRequestedOverrideConfiguration() {
return mHasOverrideConfiguration;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 1c00fbbf5c92..607347e46702 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1660,6 +1660,22 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// Otherwise if other places send wpc.getConfiguration() to client, the configuration may
// be ignored due to the seq is older.
resolvedConfig.seq = newParentConfig.seq;
+
+ if (mConfigActivityRecord != null) {
+ // Let the activity decide whether to apply the size override.
+ return;
+ }
+ final DisplayContent displayContent = mAtm.mWindowManager != null
+ ? mAtm.mWindowManager.getDefaultDisplayContentLocked()
+ : null;
+ applySizeOverrideIfNeeded(
+ displayContent,
+ mInfo,
+ newParentConfig,
+ resolvedConfig,
+ false /* optOutEdgeToEdge */,
+ false /* hasFixedRotationTransform */,
+ false /* hasCompatDisplayInsets */);
}
void dispatchConfiguration(@NonNull Configuration config) {
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 059fed20c38d..b11eca9963a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -18,6 +18,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.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -86,6 +87,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
ApplicationInfo info = mock(ApplicationInfo.class);
info.packageName = "test.package.name";
+ doReturn(true).when(info).isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED);
mWpc = new WindowProcessController(
mAtm, info, null, 0, -1, null, mMockListener);
mWpc.setThread(mock(IApplicationThread.class));