Loading services/core/java/com/android/server/wm/ActivityRecord.java +4 −0 Original line number Diff line number Diff line Loading @@ -8051,6 +8051,7 @@ final class ActivityRecord extends WindowToken { mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; // TODO(b/392069771): Move to AppCompatSandboxingPolicy. // Sandbox max bounds by setting it to the activity bounds, if activity is letterboxed, or // has or will have mAppCompatDisplayInsets for size compat. Also forces an activity to be // sandboxed or not depending upon the configuration settings. Loading Loading @@ -8079,6 +8080,9 @@ final class ActivityRecord extends WindowToken { resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds); } mAppCompatController.getSandboxingPolicy().sandboxBoundsIfNeeded(resolvedConfig, parentWindowingMode); applySizeOverrideIfNeeded( mDisplayContent, info.applicationInfo, Loading services/core/java/com/android/server/wm/AppCompatController.java +8 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ class AppCompatController { private final AppCompatLetterboxPolicy mLetterboxPolicy; @NonNull private final AppCompatSizeCompatModePolicy mSizeCompatModePolicy; @NonNull private final AppCompatSandboxingPolicy mSandboxingPolicy; AppCompatController(@NonNull WindowManagerService wmService, @NonNull ActivityRecord activityRecord) { Loading @@ -66,6 +68,7 @@ class AppCompatController { mAppCompatOverrides, mTransparentPolicy, wmService.mAppCompatConfiguration); mSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord, mAppCompatOverrides); mSandboxingPolicy = new AppCompatSandboxingPolicy(activityRecord); } @NonNull Loading Loading @@ -143,6 +146,11 @@ class AppCompatController { return mSizeCompatModePolicy; } @NonNull AppCompatSandboxingPolicy getSandboxingPolicy() { return mSandboxingPolicy; } void dump(@NonNull PrintWriter pw, @NonNull String prefix) { getTransparentPolicy().dump(pw, prefix); getLetterboxPolicy().dump(pw, prefix); Loading services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static com.android.server.wm.AppCompatUtils.isInDesktopMode; import android.annotation.NonNull; import android.app.WindowConfiguration.WindowingMode; import android.content.res.Configuration; import android.graphics.Rect; import com.android.window.flags.Flags; /** * Encapsulate logic related to sandboxing for app compatibility. */ class AppCompatSandboxingPolicy { @NonNull private final ActivityRecord mActivityRecord; AppCompatSandboxingPolicy(@NonNull ActivityRecord activityRecord) { mActivityRecord = activityRecord; } /** * In freeform, the container bounds are scaled with app bounds. Activity bounds can be * outside of its container bounds if insets are coupled with configuration outside of * freeform and maintained in freeform for size compat mode. * * <p>Sandbox activity bounds in freeform to app bounds to force app to display within the * container. This prevents UI cropping when activities can draw below insets which are * normally excluded from appBounds before targetSDK < 35 * (see ConfigurationContainer#applySizeOverrideIfNeeded). */ void sandboxBoundsIfNeeded(@NonNull Configuration resolvedConfig, @WindowingMode int windowingMode) { if (!Flags.excludeCaptionFromAppBounds()) { return; } if (isInDesktopMode(mActivityRecord.mAtmService.mContext, windowingMode)) { Rect appBounds = resolvedConfig.windowConfiguration.getAppBounds(); if (appBounds == null || appBounds.isEmpty()) { // When there is no override bounds, the activity will inherit the bounds from // parent. appBounds = mActivityRecord.mResolveConfigHint.mParentAppBoundsOverride; } resolvedConfig.windowConfiguration.setBounds(appBounds); } } } services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java +3 −5 Original line number Diff line number Diff line Loading @@ -17,14 +17,13 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA; import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE; import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA; import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode; import static com.android.server.wm.AppCompatUtils.isInDesktopMode; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -545,9 +544,8 @@ class AppCompatSizeCompatModePolicy { // Allow an application to be up-scaled if its window is smaller than its // original container or if it's a freeform window in desktop mode. boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH) || (canEnterDesktopMode(mActivityRecord.mAtmService.mContext) && newParentConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM); || isInDesktopMode(mActivityRecord.mAtmService.mContext, newParentConfig.windowConfiguration.getWindowingMode()); return shouldAllowUpscaling ? Math.min( (float) viewportW / contentW, (float) viewportH / contentH) : 1f; } Loading services/core/java/com/android/server/wm/AppCompatUtils.java +12 −0 Original line number Diff line number Diff line Loading @@ -16,16 +16,20 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppCompatTaskInfo; import android.app.CameraCompatTaskInfo; import android.app.TaskInfo; import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.view.InsetsSource; Loading Loading @@ -276,6 +280,14 @@ final class AppCompatUtils { inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY); } /** * Return {@code true} if window is currently in desktop mode. */ static boolean isInDesktopMode(@NonNull Context context, @WindowingMode int parentWindowingMode) { return parentWindowingMode == WINDOWING_MODE_FREEFORM && canEnterDesktopMode(context); } private static void clearAppCompatTaskInfo(@NonNull AppCompatTaskInfo info) { info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +4 −0 Original line number Diff line number Diff line Loading @@ -8051,6 +8051,7 @@ final class ActivityRecord extends WindowToken { mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; // TODO(b/392069771): Move to AppCompatSandboxingPolicy. // Sandbox max bounds by setting it to the activity bounds, if activity is letterboxed, or // has or will have mAppCompatDisplayInsets for size compat. Also forces an activity to be // sandboxed or not depending upon the configuration settings. Loading Loading @@ -8079,6 +8080,9 @@ final class ActivityRecord extends WindowToken { resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds); } mAppCompatController.getSandboxingPolicy().sandboxBoundsIfNeeded(resolvedConfig, parentWindowingMode); applySizeOverrideIfNeeded( mDisplayContent, info.applicationInfo, Loading
services/core/java/com/android/server/wm/AppCompatController.java +8 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ class AppCompatController { private final AppCompatLetterboxPolicy mLetterboxPolicy; @NonNull private final AppCompatSizeCompatModePolicy mSizeCompatModePolicy; @NonNull private final AppCompatSandboxingPolicy mSandboxingPolicy; AppCompatController(@NonNull WindowManagerService wmService, @NonNull ActivityRecord activityRecord) { Loading @@ -66,6 +68,7 @@ class AppCompatController { mAppCompatOverrides, mTransparentPolicy, wmService.mAppCompatConfiguration); mSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord, mAppCompatOverrides); mSandboxingPolicy = new AppCompatSandboxingPolicy(activityRecord); } @NonNull Loading Loading @@ -143,6 +146,11 @@ class AppCompatController { return mSizeCompatModePolicy; } @NonNull AppCompatSandboxingPolicy getSandboxingPolicy() { return mSandboxingPolicy; } void dump(@NonNull PrintWriter pw, @NonNull String prefix) { getTransparentPolicy().dump(pw, prefix); getLetterboxPolicy().dump(pw, prefix); Loading
services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static com.android.server.wm.AppCompatUtils.isInDesktopMode; import android.annotation.NonNull; import android.app.WindowConfiguration.WindowingMode; import android.content.res.Configuration; import android.graphics.Rect; import com.android.window.flags.Flags; /** * Encapsulate logic related to sandboxing for app compatibility. */ class AppCompatSandboxingPolicy { @NonNull private final ActivityRecord mActivityRecord; AppCompatSandboxingPolicy(@NonNull ActivityRecord activityRecord) { mActivityRecord = activityRecord; } /** * In freeform, the container bounds are scaled with app bounds. Activity bounds can be * outside of its container bounds if insets are coupled with configuration outside of * freeform and maintained in freeform for size compat mode. * * <p>Sandbox activity bounds in freeform to app bounds to force app to display within the * container. This prevents UI cropping when activities can draw below insets which are * normally excluded from appBounds before targetSDK < 35 * (see ConfigurationContainer#applySizeOverrideIfNeeded). */ void sandboxBoundsIfNeeded(@NonNull Configuration resolvedConfig, @WindowingMode int windowingMode) { if (!Flags.excludeCaptionFromAppBounds()) { return; } if (isInDesktopMode(mActivityRecord.mAtmService.mContext, windowingMode)) { Rect appBounds = resolvedConfig.windowConfiguration.getAppBounds(); if (appBounds == null || appBounds.isEmpty()) { // When there is no override bounds, the activity will inherit the bounds from // parent. appBounds = mActivityRecord.mResolveConfigHint.mParentAppBoundsOverride; } resolvedConfig.windowConfiguration.setBounds(appBounds); } } }
services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java +3 −5 Original line number Diff line number Diff line Loading @@ -17,14 +17,13 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA; import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE; import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA; import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode; import static com.android.server.wm.AppCompatUtils.isInDesktopMode; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -545,9 +544,8 @@ class AppCompatSizeCompatModePolicy { // Allow an application to be up-scaled if its window is smaller than its // original container or if it's a freeform window in desktop mode. boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH) || (canEnterDesktopMode(mActivityRecord.mAtmService.mContext) && newParentConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM); || isInDesktopMode(mActivityRecord.mAtmService.mContext, newParentConfig.windowConfiguration.getWindowingMode()); return shouldAllowUpscaling ? Math.min( (float) viewportW / contentW, (float) viewportH / contentH) : 1f; } Loading
services/core/java/com/android/server/wm/AppCompatUtils.java +12 −0 Original line number Diff line number Diff line Loading @@ -16,16 +16,20 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppCompatTaskInfo; import android.app.CameraCompatTaskInfo; import android.app.TaskInfo; import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.view.InsetsSource; Loading Loading @@ -276,6 +280,14 @@ final class AppCompatUtils { inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY); } /** * Return {@code true} if window is currently in desktop mode. */ static boolean isInDesktopMode(@NonNull Context context, @WindowingMode int parentWindowingMode) { return parentWindowingMode == WINDOWING_MODE_FREEFORM && canEnterDesktopMode(context); } private static void clearAppCompatTaskInfo(@NonNull AppCompatTaskInfo info) { info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; Loading