Loading services/core/java/com/android/server/wm/ActivityRecord.java +8 −97 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -336,7 +335,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; Loading Loading @@ -8648,7 +8646,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(); Loading @@ -8658,100 +8663,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); Loading services/core/java/com/android/server/wm/ConfigurationContainer.java +116 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -173,6 +185,110 @@ 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 optsOutEdgeToEdge, 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())); int rotation = newParentConfiguration.windowConfiguration.getRotation(); if (rotation == ROTATION_UNDEFINED && !hasFixedRotationTransform) { rotation = displayContent.getRotation(); } if (!optsOutEdgeToEdge && (!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; // 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( newParentConfiguration.windowConfiguration.getBounds()); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); outAppBounds.inset(displayContent.getDisplayPolicy() .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets); } 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; Loading services/core/java/com/android/server/wm/WindowProcessController.java +16 −0 Original line number Diff line number Diff line Loading @@ -1674,6 +1674,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 /* optsOutEdgeToEdge */, false /* hasFixedRotationTransform */, false /* hasCompatDisplayInsets */); } void dispatchConfiguration(@NonNull Configuration config) { Loading services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +8 −97 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -336,7 +335,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; Loading Loading @@ -8648,7 +8646,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(); Loading @@ -8658,100 +8663,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); Loading
services/core/java/com/android/server/wm/ConfigurationContainer.java +116 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -173,6 +185,110 @@ 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 optsOutEdgeToEdge, 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())); int rotation = newParentConfiguration.windowConfiguration.getRotation(); if (rotation == ROTATION_UNDEFINED && !hasFixedRotationTransform) { rotation = displayContent.getRotation(); } if (!optsOutEdgeToEdge && (!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; // 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( newParentConfiguration.windowConfiguration.getBounds()); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); outAppBounds.inset(displayContent.getDisplayPolicy() .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets); } 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; Loading
services/core/java/com/android/server/wm/WindowProcessController.java +16 −0 Original line number Diff line number Diff line Loading @@ -1674,6 +1674,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 /* optsOutEdgeToEdge */, false /* hasFixedRotationTransform */, false /* hasCompatDisplayInsets */); } void dispatchConfiguration(@NonNull Configuration config) { Loading
services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); Loading