diff options
6 files changed, 184 insertions, 18 deletions
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index a64ee5b38cc1..88527059b3f9 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1519,6 +1519,16 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { private static final long CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW = 197654537L; /** + * The activity is targeting a SDK version that should receive the changed behavior of + * configuration insets decouple. + * + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + public static final long INSETS_DECOUPLED_CONFIGURATION_ENFORCED = 151861875L; + + /** * Optional set of a certificates identifying apps that are allowed to embed this activity. From * the "knownActivityEmbeddingCerts" attribute. */ diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 7d5aa96db0b8..149f55f9ae93 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -50,6 +50,7 @@ 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; @@ -75,6 +76,7 @@ import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON; +import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; @@ -332,6 +334,7 @@ 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; @@ -8483,6 +8486,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // and back which can cause visible issues (see b/184078928). final int parentWindowingMode = newParentConfiguration.windowConfiguration.getWindowingMode(); + + applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig); + final boolean isFixedOrientationLetterboxAllowed = parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW || parentWindowingMode == WINDOWING_MODE_FULLSCREEN @@ -8582,6 +8588,87 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** + * 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. + */ + private void applySizeOverrideIfNeeded(Configuration newParentConfiguration, + int parentWindowingMode, Configuration inOutConfig) { + if (mDisplayContent == null) { + return; + } + final Rect fullBounds = newParentConfiguration.windowConfiguration.getAppBounds(); + int rotation = newParentConfiguration.windowConfiguration.getRotation(); + if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) { + rotation = mDisplayContent.getRotation(); + } + if (!mWmService.mFlags.mInsetsDecoupledConfiguration + || info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED) + || getCompatDisplayInsets() != null + || isFloating(parentWindowingMode) || fullBounds == null + || fullBounds.isEmpty() || 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; + } + + // Override starts here. + final Rect stableInsets = mDisplayContent.getDisplayPolicy().getDecorInsetsInfo( + rotation, fullBounds.width(), fullBounds.height()).mLegacyConfigInsets; + // 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(fullBounds); + outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); + outAppBounds.inset(stableInsets); + } + 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) { + final int overrideScreenWidthDp = (int) (outAppBounds.width() / density + 0.5f); + inOutConfig.screenWidthDp = + Math.min(overrideScreenWidthDp, newParentConfiguration.screenWidthDp); + } + if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { + final int overrideScreenHeightDp = + (int) (outAppBounds.height() / density + 0.5f); + inOutConfig.screenHeightDp = + Math.min(overrideScreenHeightDp, newParentConfiguration.screenHeightDp); + } + 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 boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); + DisplayInfo info = new DisplayInfo(); + mDisplayContent.getDisplay().getDisplayInfo(info); + mDisplayContent.computeSizeRanges(info, rotated, info.logicalWidth, + info.logicalHeight, mDisplayContent.getDisplayMetrics().density, + inOutConfig, true /* legacyConfig */); + } + + // 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; + } + } + + /** * @return The orientation to use to understand if reachability is enabled. */ @Configuration.Orientation @@ -8834,6 +8921,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mDisplayContent == null) { return true; } + if (mWmService.mFlags.mInsetsDecoupledConfiguration + && info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)) { + // No insets should be considered any more. + return true; + } // Only need to make changes if activity sets an orientation final int requestedOrientation = getRequestedConfigurationOrientation(); if (requestedOrientation == ORIENTATION_UNDEFINED) { @@ -8848,7 +8940,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A : mDisplayContent.getDisplayInfo(); final Task task = getTask(); task.calculateInsetFrames(mTmpBounds /* outNonDecorBounds */, - outStableBounds /* outStableBounds */, parentBounds /* bounds */, di); + outStableBounds /* outStableBounds */, parentBounds /* bounds */, di, + true /* useLegacyInsetsForStableBounds */); final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width() ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; // If orientation does not match the orientation with insets applied, then a diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f25780c9469c..877f97450fb2 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2301,7 +2301,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED; } - computeSizeRanges(mDisplayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig); + computeSizeRanges(mDisplayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig, + false /* legacyConfig */); setDisplayInfoOverride(); @@ -2437,7 +2438,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp displayInfo.appHeight = appBounds.height(); final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation); displayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout; - computeSizeRanges(displayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig); + computeSizeRanges(displayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig, + false /* legacyConfig */); return displayInfo; } @@ -2601,8 +2603,21 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return curSize; } - private void computeSizeRanges(DisplayInfo displayInfo, boolean rotated, - int dw, int dh, float density, Configuration outConfig) { + /** + * Compute size range related fields of DisplayInfo and Configuration based on provided info. + * The fields usually contain word such as smallest or largest. + * + * @param displayInfo In-out display info to compute the result. + * @param rotated Whether the display is rotated. + * @param dw Display Width in current rotation. + * @param dh Display Height in current rotation. + * @param density Display density. + * @param outConfig The output configuration to + * @param legacyConfig Whether we need to report the legacy result, which is excluding system + * decorations. + */ + void computeSizeRanges(DisplayInfo displayInfo, boolean rotated, + int dw, int dh, float density, Configuration outConfig, boolean legacyConfig) { // We need to determine the smallest width that will occur under normal // operation. To this, start with the base screen size and compute the @@ -2620,10 +2635,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp displayInfo.smallestNominalAppHeight = 1<<30; displayInfo.largestNominalAppWidth = 0; displayInfo.largestNominalAppHeight = 0; - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh, legacyConfig); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw, legacyConfig); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh, legacyConfig); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw, legacyConfig); if (outConfig == null) { return; @@ -2632,11 +2647,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp (int) (displayInfo.smallestNominalAppWidth / density + 0.5f); } - private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) { + private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh, + boolean legacyConfig) { final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo( rotation, dw, dh); - final int w = info.mConfigFrame.width(); - final int h = info.mConfigFrame.height(); + final int w; + final int h; + if (!legacyConfig) { + w = info.mConfigFrame.width(); + h = info.mConfigFrame.height(); + } else { + w = info.mLegacyConfigFrame.width(); + h = info.mLegacyConfigFrame.height(); + } if (w < displayInfo.smallestNominalAppWidth) { displayInfo.smallestNominalAppWidth = w; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 7f3df958664c..cc00280b55d7 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1913,6 +1913,11 @@ public class DisplayPolicy { */ final Rect mConfigInsets = new Rect(); + /** + * Legacy value of mConfigInsets for app compatibility purpose. + */ + final Rect mLegacyConfigInsets = new Rect(); + /** The display frame available after excluding {@link #mNonDecorInsets}. */ final Rect mNonDecorFrame = new Rect(); @@ -1923,6 +1928,11 @@ public class DisplayPolicy { */ final Rect mConfigFrame = new Rect(); + /** + * Legacy value of mConfigFrame for app compatibility purpose. + */ + final Rect mLegacyConfigFrame = new Rect(); + private boolean mNeedUpdate = true; InsetsState update(DisplayContent dc, int rotation, int w, int h) { @@ -1933,15 +1943,26 @@ public class DisplayPolicy { final Rect displayFrame = insetsState.getDisplayFrame(); final Insets decor = insetsState.calculateInsets(displayFrame, dc.mWmService.mDecorTypes, true /* ignoreVisibility */); - final Insets configInsets = insetsState.calculateInsets(displayFrame, - dc.mWmService.mConfigTypes, true /* ignoreVisibility */); + final Insets configInsets = dc.mWmService.mConfigTypes == dc.mWmService.mDecorTypes + ? decor + : insetsState.calculateInsets(displayFrame, dc.mWmService.mConfigTypes, + true /* ignoreVisibility */); + final Insets legacyConfigInsets = dc.mWmService.mConfigTypes + == dc.mWmService.mLegacyConfigTypes + ? configInsets + : insetsState.calculateInsets(displayFrame, + dc.mWmService.mLegacyConfigTypes, true /* ignoreVisibility */); mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom); mConfigInsets.set(configInsets.left, configInsets.top, configInsets.right, configInsets.bottom); + mLegacyConfigInsets.set(legacyConfigInsets.left, legacyConfigInsets.top, + legacyConfigInsets.right, legacyConfigInsets.bottom); mNonDecorFrame.set(displayFrame); mNonDecorFrame.inset(mNonDecorInsets); mConfigFrame.set(displayFrame); mConfigFrame.inset(mConfigInsets); + mLegacyConfigFrame.set(displayFrame); + mLegacyConfigFrame.inset(mLegacyConfigInsets); mNeedUpdate = false; return insetsState; } @@ -1949,8 +1970,10 @@ public class DisplayPolicy { void set(Info other) { mNonDecorInsets.set(other.mNonDecorInsets); mConfigInsets.set(other.mConfigInsets); + mLegacyConfigInsets.set(other.mLegacyConfigInsets); mNonDecorFrame.set(other.mNonDecorFrame); mConfigFrame.set(other.mConfigFrame); + mLegacyConfigFrame.set(other.mLegacyConfigFrame); mNeedUpdate = false; } @@ -2062,7 +2085,8 @@ public class DisplayPolicy { final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo; final InsetsState newInsetsState = newInfo.update(mDisplayContent, rotation, dw, dh); final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh); - if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) { + if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame) + && newInfo.mLegacyConfigFrame.equals(currentInfo.mLegacyConfigFrame)) { // Even if the config frame is not changed in current rotation, it may change the // insets in other rotations if the frame of insets source is changed. final InsetsState currentInsetsState = mDisplayContent.mDisplayFrames.mInsetsState; diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 85d81c4db2ca..e716c38ebb48 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2331,7 +2331,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { // area, i.e. the screen area without the system bars. // The non decor inset are areas that could never be removed in Honeycomb. See // {@link WindowManagerPolicy#getNonDecorInsetsLw}. - calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di); + calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di, + false /* useLegacyInsetsForStableBounds */); } else { // Apply the given non-decor and stable insets to calculate the corresponding bounds // for screen size of configuration. @@ -2429,9 +2430,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { * @param outNonDecorBounds where to place bounds with non-decor insets applied. * @param outStableBounds where to place bounds with stable insets applied. * @param bounds the bounds to inset. + * @param useLegacyInsetsForStableBounds {@code true} if we need to use the legacy insets frame + * for apps targeting U or before when calculating stable bounds. */ void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, - DisplayInfo displayInfo) { + DisplayInfo displayInfo, boolean useLegacyInsetsForStableBounds) { outNonDecorBounds.set(bounds); outStableBounds.set(bounds); if (mDisplayContent == null) { @@ -2443,7 +2446,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { final DisplayPolicy.DecorInsets.Info info = policy.getDecorInsetsInfo( displayInfo.rotation, displayInfo.logicalWidth, displayInfo.logicalHeight); intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mNonDecorInsets); - intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets); + if (!useLegacyInsetsForStableBounds) { + intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets); + } else { + intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mLegacyConfigInsets); + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ae5a5cb7316c..da3f59625456 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -561,6 +561,8 @@ public class WindowManagerService extends IWindowManager.Stub /** Device default insets types shall be excluded from config app sizes. */ final int mConfigTypes; + final int mLegacyConfigTypes; + final boolean mLimitedAlphaCompositing; final int mMaxUiWidth; @@ -1198,6 +1200,13 @@ public class WindowManagerService extends IWindowManager.Stub mDecorTypes = WindowInsets.Type.navigationBars(); mConfigTypes = WindowInsets.Type.navigationBars(); } + if (isScreenSizeDecoupledFromStatusBarAndCutout) { + // Do not fallback to legacy value for enabled devices. + mLegacyConfigTypes = WindowInsets.Type.navigationBars(); + } else { + mLegacyConfigTypes = WindowInsets.Type.displayCutout() | WindowInsets.Type.statusBars() + | WindowInsets.Type.navigationBars(); + } mLetterboxConfiguration = new LetterboxConfiguration( // Using SysUI context to have access to Material colors extracted from Wallpaper. |