summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/AppCompatTaskInfo.java22
-rw-r--r--core/java/com/android/internal/policy/DesktopModeCompatUtils.java60
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt32
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/AppCompatUtils.java1
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java50
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java2
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsController.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java36
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java35
10 files changed, 192 insertions, 62 deletions
diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java
index ea4646aa9eb9..3fd9d8b26611 100644
--- a/core/java/android/app/AppCompatTaskInfo.java
+++ b/core/java/android/app/AppCompatTaskInfo.java
@@ -104,6 +104,8 @@ public class AppCompatTaskInfo implements Parcelable {
public static final int FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE = FLAG_BASE << 9;
/** Top activity flag for whether restart menu is shown due to display move. */
private static final int FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE = FLAG_BASE << 10;
+ /** Top activity flag for whether activity opted out of edge to edge. */
+ public static final int FLAG_OPT_OUT_EDGE_TO_EDGE = FLAG_BASE << 11;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {
@@ -118,7 +120,8 @@ public class AppCompatTaskInfo implements Parcelable {
FLAG_FULLSCREEN_OVERRIDE_SYSTEM,
FLAG_FULLSCREEN_OVERRIDE_USER,
FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE,
- FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE
+ FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE,
+ FLAG_OPT_OUT_EDGE_TO_EDGE
})
public @interface TopActivityFlag {}
@@ -132,7 +135,8 @@ public class AppCompatTaskInfo implements Parcelable {
@TopActivityFlag
private static final int FLAGS_ORGANIZER_INTERESTED = FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP
| FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON | FLAG_FULLSCREEN_OVERRIDE_SYSTEM
- | FLAG_FULLSCREEN_OVERRIDE_USER | FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE;
+ | FLAG_FULLSCREEN_OVERRIDE_USER | FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE
+ | FLAG_OPT_OUT_EDGE_TO_EDGE;
@TopActivityFlag
private static final int FLAGS_COMPAT_UI_INTERESTED = FLAGS_ORGANIZER_INTERESTED
@@ -347,6 +351,20 @@ public class AppCompatTaskInfo implements Parcelable {
setTopActivityFlag(FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE, enable);
}
+ /**
+ * Sets the top activity flag for whether the activity has opted out of edge to edge.
+ */
+ public void setOptOutEdgeToEdge(boolean enable) {
+ setTopActivityFlag(FLAG_OPT_OUT_EDGE_TO_EDGE, enable);
+ }
+
+ /**
+ * @return {@code true} if the top activity has opted out of edge to edge.
+ */
+ public boolean hasOptOutEdgeToEdge() {
+ return isTopActivityFlagEnabled(FLAG_OPT_OUT_EDGE_TO_EDGE);
+ }
+
/** Clear all top activity flags and set to false. */
public void clearTopActivityFlags() {
mTopActivityFlags = FLAG_UNDEFINED;
diff --git a/core/java/com/android/internal/policy/DesktopModeCompatUtils.java b/core/java/com/android/internal/policy/DesktopModeCompatUtils.java
new file mode 100644
index 000000000000..d7cfbdfed99c
--- /dev/null
+++ b/core/java/com/android/internal/policy/DesktopModeCompatUtils.java
@@ -0,0 +1,60 @@
+/*
+ * 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.internal.policy;
+
+import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
+import static android.content.pm.ActivityInfo.OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS;
+
+import android.annotation.NonNull;
+import android.content.pm.ActivityInfo;
+import android.window.DesktopModeFlags;
+
+/**
+ * Utility functions for app compat in desktop windowing used by both window manager and System UI.
+ * @hide
+ */
+public final class DesktopModeCompatUtils {
+
+ /**
+ * Whether the caption insets should be excluded from configuration for system to handle.
+ * The caller should ensure the activity is in or entering desktop view.
+ *
+ * <p> The treatment is enabled when all the of the following is true:
+ * <li> Any flags to forcibly consume caption insets are enabled.
+ * <li> Top activity have configuration coupled with insets.
+ * <li> Task is not resizeable or per-app override
+ * {@link ActivityInfo#OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS} is enabled.
+ */
+ public static boolean shouldExcludeCaptionFromAppBounds(@NonNull ActivityInfo info,
+ boolean isResizeable, boolean optOutEdgeToEdge) {
+ return DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue()
+ && isAnyForceConsumptionFlagsEnabled()
+ && !isConfigurationDecoupled(info, optOutEdgeToEdge)
+ && (!isResizeable
+ || info.isChangeEnabled(OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS));
+ }
+
+ private static boolean isConfigurationDecoupled(@NonNull ActivityInfo info,
+ boolean optOutEdgeToEdge) {
+ return info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED) && !optOutEdgeToEdge;
+ }
+
+ private static boolean isAnyForceConsumptionFlagsEnabled() {
+ return DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue()
+ || DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue();
+ }
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt
index 9ea0532f9450..b87c2054bea6 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt
@@ -19,13 +19,10 @@ package com.android.wm.shell.shared.desktopmode
import android.Manifest.permission.SYSTEM_ALERT_WINDOW
import android.app.TaskInfo
import android.content.Context
-import android.content.pm.ActivityInfo
-import android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED
-import android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION
-import android.content.pm.ActivityInfo.OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS
import android.content.pm.PackageManager
import android.window.DesktopModeFlags
import com.android.internal.R
+import com.android.internal.policy.DesktopModeCompatUtils
/**
* Class to decide whether to apply app compat policies in desktop mode.
@@ -60,22 +57,11 @@ class DesktopModeCompatPolicy(private val context: Context) {
hasFullscreenTransparentPermission(packageName))) &&
!isTopActivityNoDisplay)
- /**
- * Whether the caption insets should be excluded from configuration for system to handle.
- *
- * The treatment is enabled when all the of the following is true:
- * * Any flags to forcibly consume caption insets are enabled.
- * * Top activity have configuration coupled with insets.
- * * Task is not resizeable or [ActivityInfo.OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS]
- * is enabled.
- */
+ /** @see DesktopModeCompatUtils.shouldExcludeCaptionFromAppBounds */
fun shouldExcludeCaptionFromAppBounds(taskInfo: TaskInfo): Boolean =
- DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue
- && isAnyForceConsumptionFlagsEnabled()
- && taskInfo.topActivityInfo?.let {
- isInsetsCoupledWithConfiguration(it) && (!taskInfo.isResizeable || it.isChangeEnabled(
- OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS
- ))
+ taskInfo.topActivityInfo?.let {
+ DesktopModeCompatUtils.shouldExcludeCaptionFromAppBounds(it, taskInfo.isResizeable,
+ taskInfo.appCompatTaskInfo.hasOptOutEdgeToEdge())
} ?: false
/**
@@ -118,12 +104,4 @@ class DesktopModeCompatPolicy(private val context: Context) {
*/
private fun isPartOfDefaultHomePackageOrNoHomeAvailable(packageName: String?) =
defaultHomePackage == null || (packageName != null && packageName == defaultHomePackage)
-
- private fun isAnyForceConsumptionFlagsEnabled(): Boolean =
- DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue
- || DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue
-
- private fun isInsetsCoupledWithConfiguration(info: ActivityInfo): Boolean =
- !(info.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION)
- || info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED))
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e91d88901751..919b14b6db62 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -625,7 +625,7 @@ final class ActivityRecord extends WindowToken {
@VisibleForTesting
final TaskFragment.ConfigOverrideHint mResolveConfigHint;
- private final boolean mOptOutEdgeToEdge;
+ final boolean mOptOutEdgeToEdge;
private static ConstrainDisplayApisConfig sConstrainDisplayApisConfig;
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index b91a12598e01..80df081a6271 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -216,6 +216,7 @@ final class AppCompatUtils {
AppCompatCameraPolicy.getCameraCompatFreeformMode(top);
appCompatTaskInfo.setHasMinAspectRatioOverride(top.mAppCompatController
.getDesktopAspectRatioPolicy().hasMinAspectRatioOverride(task));
+ appCompatTaskInfo.setOptOutEdgeToEdge(top.mOptOutEdgeToEdge);
}
/**
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index 7a959c14fbd2..ce3ad889a308 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -24,6 +24,8 @@ import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static com.android.internal.policy.SystemBarUtils.getDesktopViewAppHeaderHeightPx;
+import static com.android.internal.policy.DesktopModeCompatUtils.shouldExcludeCaptionFromAppBounds;
import static com.android.server.wm.LaunchParamsUtil.applyLayoutGravity;
import static com.android.server.wm.LaunchParamsUtil.calculateLayoutBounds;
@@ -64,7 +66,8 @@ public final class DesktopModeBoundsCalculator {
*/
static void updateInitialBounds(@NonNull Task task, @Nullable WindowLayout layout,
@Nullable ActivityRecord activity, @Nullable ActivityOptions options,
- @NonNull Rect outBounds, @NonNull Consumer<String> logger) {
+ @NonNull LaunchParamsController.LaunchParams outParams,
+ @NonNull Consumer<String> logger) {
// Use stable frame instead of raw frame to avoid launching freeform windows on top of
// stable insets, which usually are system widgets such as sysbar & navbar.
final Rect stableBounds = new Rect();
@@ -77,36 +80,44 @@ public final class DesktopModeBoundsCalculator {
// during the size update.
final boolean shouldRespectOptionPosition =
updateOptionBoundsSize && DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue();
+ final int captionHeight = activity != null && shouldExcludeCaptionFromAppBounds(
+ activity.info, task.isResizeable(), activity.mOptOutEdgeToEdge)
+ ? getDesktopViewAppHeaderHeightPx(activity.mWmService.mContext) : 0;
if (options != null && options.getLaunchBounds() != null
&& !updateOptionBoundsSize) {
- outBounds.set(options.getLaunchBounds());
- logger.accept("inherit-from-options=" + outBounds);
+ outParams.mBounds.set(options.getLaunchBounds());
+ logger.accept("inherit-from-options=" + outParams.mBounds);
} else if (layout != null) {
final int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
final int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if (layout.hasSpecifiedSize()) {
- calculateLayoutBounds(stableBounds, layout, outBounds,
+ calculateLayoutBounds(stableBounds, layout, outParams.mBounds,
calculateIdealSize(stableBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE));
- applyLayoutGravity(verticalGravity, horizontalGravity, outBounds,
+ applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds,
stableBounds);
logger.accept("layout specifies sizes, inheriting size and applying gravity");
} else if (verticalGravity > 0 || horizontalGravity > 0) {
- outBounds.set(calculateInitialBounds(task, activity, stableBounds, options,
- shouldRespectOptionPosition));
- applyLayoutGravity(verticalGravity, horizontalGravity, outBounds,
+ outParams.mBounds.set(calculateInitialBounds(task, activity, stableBounds, options,
+ shouldRespectOptionPosition, captionHeight));
+ applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds,
stableBounds);
logger.accept("layout specifies gravity, applying desired bounds and gravity");
logger.accept("respecting option bounds cascaded position="
+ shouldRespectOptionPosition);
}
} else {
- outBounds.set(calculateInitialBounds(task, activity, stableBounds, options,
- shouldRespectOptionPosition));
+ outParams.mBounds.set(calculateInitialBounds(task, activity, stableBounds, options,
+ shouldRespectOptionPosition, captionHeight));
logger.accept("layout not specified, applying desired bounds");
logger.accept("respecting option bounds cascaded position="
+ shouldRespectOptionPosition);
}
+ if (updateOptionBoundsSize && captionHeight != 0) {
+ outParams.mAppBounds.set(outParams.mBounds);
+ outParams.mAppBounds.top += captionHeight;
+ logger.accept("excluding caption height from app bounds");
+ }
}
/**
@@ -119,7 +130,8 @@ public final class DesktopModeBoundsCalculator {
@NonNull
private static Rect calculateInitialBounds(@NonNull Task task,
@NonNull ActivityRecord activity, @NonNull Rect stableBounds,
- @Nullable ActivityOptions options, boolean shouldRespectOptionPosition
+ @Nullable ActivityOptions options, boolean shouldRespectOptionPosition,
+ int captionHeight
) {
// Display bounds not taking into account insets.
final TaskDisplayArea displayArea = task.getDisplayArea();
@@ -160,7 +172,8 @@ public final class DesktopModeBoundsCalculator {
}
// If activity is unresizeable, regardless of orientation, calculate maximum size
// (within the ideal size) maintaining original aspect ratio.
- yield maximizeSizeGivenAspectRatio(activityOrientation, idealSize, appAspectRatio);
+ yield maximizeSizeGivenAspectRatio(activityOrientation, idealSize, appAspectRatio,
+ captionHeight);
}
case ORIENTATION_PORTRAIT -> {
// Device in portrait orientation.
@@ -188,11 +201,12 @@ public final class DesktopModeBoundsCalculator {
// ratio.
yield maximizeSizeGivenAspectRatio(activityOrientation,
new Size(customPortraitWidthForLandscapeApp, idealSize.getHeight()),
- appAspectRatio);
+ appAspectRatio, captionHeight);
}
// For portrait unresizeable activities, calculate maximum size (within the ideal
// size) maintaining original aspect ratio.
- yield maximizeSizeGivenAspectRatio(activityOrientation, idealSize, appAspectRatio);
+ yield maximizeSizeGivenAspectRatio(activityOrientation, idealSize, appAspectRatio,
+ captionHeight);
}
default -> idealSize;
};
@@ -232,13 +246,15 @@ public final class DesktopModeBoundsCalculator {
* Calculates the largest size that can fit in a given area while maintaining a specific aspect
* ratio.
*/
+ // TODO(b/400617906): Merge duplicate initial bounds calculations to shared class.
@NonNull
private static Size maximizeSizeGivenAspectRatio(
@ScreenOrientation int orientation,
@NonNull Size targetArea,
- float aspectRatio
+ float aspectRatio,
+ int captionHeight
) {
- final int targetHeight = targetArea.getHeight();
+ final int targetHeight = targetArea.getHeight() - captionHeight;
final int targetWidth = targetArea.getWidth();
final int finalHeight;
final int finalWidth;
@@ -275,7 +291,7 @@ public final class DesktopModeBoundsCalculator {
finalHeight = (int) (finalWidth / aspectRatio);
}
}
- return new Size(finalWidth, finalHeight);
+ return new Size(finalWidth, finalHeight + captionHeight);
}
/**
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index ddcb5eccb1d8..6698d2ec7cc4 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -150,7 +150,7 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
}
DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options,
- outParams.mBounds, this::appendLog);
+ outParams, this::appendLog);
appendLog("final desktop mode task bounds set to %s", outParams.mBounds);
if (options != null && options.getFlexibleLaunchSize()) {
// Return result done to prevent other modifiers from respecting option bounds and
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index fa65bda7104d..8eec98cb5fcc 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -26,6 +26,7 @@ import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration.WindowingMode;
@@ -138,6 +139,10 @@ class LaunchParamsController {
mService.deferWindowLayout();
try {
if (task.getRootTask().inMultiWindowMode()) {
+ if (!mTmpParams.mAppBounds.isEmpty()) {
+ task.getRequestedOverrideConfiguration().windowConfiguration.setAppBounds(
+ mTmpParams.mAppBounds);
+ }
task.setBounds(mTmpParams.mBounds);
return true;
}
@@ -169,6 +174,9 @@ class LaunchParamsController {
static class LaunchParams {
/** The bounds within the parent container. */
final Rect mBounds = new Rect();
+ /** The bounds within the parent container respecting insets. Usually empty. */
+ @NonNull
+ final Rect mAppBounds = new Rect();
/** The display area the {@link Task} would prefer to be on. */
@Nullable
@@ -181,6 +189,7 @@ class LaunchParamsController {
/** Sets values back to default. {@link #isEmpty} will return {@code true} once called. */
void reset() {
mBounds.setEmpty();
+ mAppBounds.setEmpty();
mPreferredTaskDisplayArea = null;
mWindowingMode = WINDOWING_MODE_UNDEFINED;
}
@@ -188,13 +197,14 @@ class LaunchParamsController {
/** Copies the values set on the passed in {@link LaunchParams}. */
void set(LaunchParams params) {
mBounds.set(params.mBounds);
+ mAppBounds.set(params.mAppBounds);
mPreferredTaskDisplayArea = params.mPreferredTaskDisplayArea;
mWindowingMode = params.mWindowingMode;
}
/** Returns {@code true} if no values have been explicitly set. */
boolean isEmpty() {
- return mBounds.isEmpty() && mPreferredTaskDisplayArea == null
+ return mBounds.isEmpty() && mAppBounds.isEmpty() && mPreferredTaskDisplayArea == null
&& mWindowingMode == WINDOWING_MODE_UNDEFINED;
}
@@ -215,12 +225,14 @@ class LaunchParamsController {
if (mPreferredTaskDisplayArea != that.mPreferredTaskDisplayArea) return false;
if (mWindowingMode != that.mWindowingMode) return false;
+ if (!mAppBounds.equals(that.mAppBounds)) return false;
return mBounds != null ? mBounds.equals(that.mBounds) : that.mBounds == null;
}
@Override
public int hashCode() {
int result = mBounds != null ? mBounds.hashCode() : 0;
+ result = 31 * result + mAppBounds.hashCode();
result = 31 * result + (mPreferredTaskDisplayArea != null
? mPreferredTaskDisplayArea.hashCode() : 0);
result = 31 * result + mWindowingMode;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index e87e107cd793..3e86f7b57294 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -41,6 +41,7 @@ import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.internal.policy.SystemBarUtils.getDesktopViewAppHeaderHeightPx;
import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_LANDSCAPE_APP_PADDING;
import static com.android.server.wm.DesktopModeBoundsCalculator.centerInScreen;
@@ -893,9 +894,11 @@ public class DesktopModeLaunchParamsModifierTests extends
@Test
@EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS})
+ Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS,
+ Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS})
public void testDefaultLandscapeBounds_landscapeDevice_unResizable_landscapeOrientation() {
setupDesktopModeLaunchParamsModifier();
+ final int captionHeight = getDesktopViewAppHeaderHeightPx(mContext);
final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE,
LANDSCAPE_DISPLAY_BOUNDS);
@@ -903,11 +906,11 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
task, /* ignoreOrientationRequest */ true);
-
- final int desiredWidth =
- (int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final float displayAspectRatio = (float) LANDSCAPE_DISPLAY_BOUNDS.width()
+ / LANDSCAPE_DISPLAY_BOUNDS.height();
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth = (int) ((desiredHeight - captionHeight) * displayAspectRatio);
assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
.setActivity(activity).calculate());
@@ -916,7 +919,8 @@ public class DesktopModeLaunchParamsModifierTests extends
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableFlags({Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS,
+ Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS})
public void testUnResizablePortraitBounds_landscapeDevice_unResizable_portraitOrientation() {
setupDesktopModeLaunchParamsModifier();
@@ -925,6 +929,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final Task task = createTask(display, /* isResizeable */ false);
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
task, /* ignoreOrientationRequest */ true);
+ final int captionHeight = getDesktopViewAppHeaderHeightPx(mContext);
spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
@@ -932,7 +937,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- final int desiredWidth = (int) (desiredHeight / LETTERBOX_ASPECT_RATIO);
+ final int desiredWidth = (int) ((desiredHeight - captionHeight) / LETTERBOX_ASPECT_RATIO);
assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
.setActivity(activity).calculate());
@@ -1070,7 +1075,8 @@ public class DesktopModeLaunchParamsModifierTests extends
@Test
@EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS})
+ Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS,
+ Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS})
public void testDefaultPortraitBounds_portraitDevice_unResizable_portraitOrientation() {
setupDesktopModeLaunchParamsModifier();
@@ -1079,12 +1085,14 @@ public class DesktopModeLaunchParamsModifierTests extends
final Task task = createTask(display, /* isResizeable */ false);
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
task, /* ignoreOrientationRequest */ true);
+ final int captionHeight = getDesktopViewAppHeaderHeightPx(mContext);
-
- final int desiredWidth =
- (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final float displayAspectRatio = (float) PORTRAIT_DISPLAY_BOUNDS.height()
+ / PORTRAIT_DISPLAY_BOUNDS.width();
final int desiredHeight =
- (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+ final int desiredWidth =
+ (int) ((desiredHeight - captionHeight) / displayAspectRatio);
assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
.setActivity(activity).calculate());
@@ -1093,7 +1101,8 @@ public class DesktopModeLaunchParamsModifierTests extends
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
+ @EnableFlags({Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS,
+ Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS})
public void testUnResizableLandscapeBounds_portraitDevice_unResizable_landscapeOrientation() {
setupDesktopModeLaunchParamsModifier();
@@ -1102,6 +1111,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final Task task = createTask(display, /* isResizeable */ false);
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
task, /* ignoreOrientationRequest */ true);
+ final int captionHeight = getDesktopViewAppHeaderHeightPx(mContext);
spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
@@ -1109,7 +1119,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
- final int desiredHeight = (int) (desiredWidth / LETTERBOX_ASPECT_RATIO);
+ final int desiredHeight = (int) (desiredWidth / LETTERBOX_ASPECT_RATIO) + captionHeight;
assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
.setActivity(activity).calculate());
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 67a95de8a5c1..0d5828a3c4e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -44,6 +44,7 @@ import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.pm.ActivityInfo.WindowLayout;
import android.graphics.Rect;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -52,6 +53,7 @@ import androidx.test.filters.MediumTest;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
+import com.android.window.flags.Flags;
import org.junit.Before;
import org.junit.Test;
@@ -372,6 +374,34 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
assertEquals(expected, task.mLastNonFullscreenBounds);
}
+ /**
+ * Ensures that app bounds are set to exclude freeform caption if window is in freeform.
+ */
+ @Test
+ @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS)
+ public void testLayoutTaskBoundsFreeformAppBounds() {
+ final Rect expected = new Rect(10, 20, 30, 40);
+
+ final LaunchParams params = new LaunchParams();
+ params.mBounds.set(expected);
+ params.mAppBounds.set(expected);
+ final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+ final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final ActivityOptions options = ActivityOptions.makeBasic().setFlexibleLaunchSize(true);
+
+ mController.registerModifier(positioner);
+
+ assertNotEquals(expected, task.getBounds());
+
+ layoutTask(task, options);
+
+ // Task will make adjustments to requested bounds. We only need to guarantee that the
+ // requested bounds are expected.
+ assertEquals(expected,
+ task.getRequestedOverrideConfiguration().windowConfiguration.getAppBounds());
+ }
+
public static class InstrumentedPositioner implements LaunchParamsModifier {
private final int mReturnVal;
@@ -473,4 +503,9 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
mController.layoutTask(task, null /* layout */, null /* activity */, null /* source */,
null /* options */);
}
+
+ private void layoutTask(@NonNull Task task, ActivityOptions options) {
+ mController.layoutTask(task, null /* layout */, null /* activity */, null /* source */,
+ options /* options */);
+ }
}