From cd47f74012664c16bcb525c1a4d1291a30644956 Mon Sep 17 00:00:00 2001 From: Eghosa Ewansiha-Vlachavas Date: Mon, 10 Jun 2024 14:40:06 +0000 Subject: [2/n] Introduce dynamic bounds calculation to prevent letterboxing When entering desktop windowing, applications should no longer be letterboxed. This means scaling down apps in SCM for all unresizable apps so intial bounds match scale of the fullscreen bounds. This removes letterboxing while ensuring the apps layout is not disrupted. For portrait resizable apps when the device is in landscape, the height of the initial bounds will match the desired app height for desktopmode while the width will remain from the apps fullscreen width. For landscape resizable apps when the device is portrait, the fullscreen height of the app will be preserved while the width will be set to a custom value. Flag: com.android.window.flags.enable_windowing_dynamic_initial_bounds Bug: 319820230 Bug: 324378380 Fixes: 335401172 Fixes: 346821376 Test: atest WmTests:DesktopModeLaunchParamsModifierTests Test: atest WmTests:DesktopModeUtilsTests Test: atest WmTests:DisplayContentTests Test: atest WMShellUnitTests:DesktopTasksControllerTest Change-Id: Ie111c025256de9afdd9d2568a28a5078413fcbfe --- .../wm/shell/desktopmode/DesktopModeUtils.kt | 8 +- .../wm/shell/desktopmode/DesktopTasksController.kt | 6 +- .../desktopmode/DesktopTasksControllerTest.kt | 132 --------- .../server/wm/AppCompatAspectRatioOverrides.java | 10 +- .../server/wm/DesktopModeBoundsCalculator.java | 300 +++++++++++++++++++-- .../server/wm/DesktopModeLaunchParamsModifier.java | 13 +- .../wm/DesktopModeLaunchParamsModifierTests.java | 266 +++++++++++++++++- .../android/server/wm/SystemServicesTestRule.java | 1 + 8 files changed, 560 insertions(+), 176 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index 1bf125938e6f..da212e704b24 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -66,7 +66,7 @@ fun calculateInitialBounds( idealSize } } else { - maximumSizeMaintainingAspectRatio(taskInfo, idealSize, appAspectRatio) + maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio) } } ORIENTATION_PORTRAIT -> { @@ -85,13 +85,13 @@ fun calculateInitialBounds( } else { if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) { // Apply custom app width and calculate maximum size - maximumSizeMaintainingAspectRatio( + maximizeSizeGivenAspectRatio( taskInfo, Size(customPortraitWidthForLandscapeApp, idealSize.height), appAspectRatio ) } else { - maximumSizeMaintainingAspectRatio(taskInfo, idealSize, appAspectRatio) + maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio) } } } @@ -107,7 +107,7 @@ fun calculateInitialBounds( * Calculates the largest size that can fit in a given area while maintaining a specific aspect * ratio. */ -fun maximumSizeMaintainingAspectRatio( +fun maximizeSizeGivenAspectRatio( taskInfo: RunningTaskInfo, targetArea: Size, aspectRatio: Float diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 9a1a8a20ae0e..43fa3df07741 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -671,7 +671,7 @@ class DesktopTasksController( } else { // if non-resizable then calculate max bounds according to aspect ratio val activityAspectRatio = calculateAspectRatio(taskInfo) - val newSize = maximumSizeMaintainingAspectRatio(taskInfo, + val newSize = maximizeSizeGivenAspectRatio(taskInfo, Size(stableBounds.width(), stableBounds.height()), activityAspectRatio) val newBounds = centerInArea( newSize, stableBounds, stableBounds.left, stableBounds.top) @@ -1074,7 +1074,6 @@ class DesktopTasksController( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo ) { - val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(taskInfo.displayId)!! val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode val targetWindowingMode = @@ -1084,9 +1083,6 @@ class DesktopTasksController( } else { WINDOWING_MODE_FREEFORM } - if (Flags.enableWindowingDynamicInitialBounds()) { - wct.setBounds(taskInfo.token, calculateInitialBounds(displayLayout, taskInfo)) - } wct.setWindowingMode(taskInfo.token, targetWindowingMode) wct.reorder(taskInfo.token, true /* onTop */) if (useDesktopOverrideDensity()) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index da886863cc1f..8e5ead9b6e9c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -579,138 +579,6 @@ class DesktopTasksControllerTest : ShellTestCase() { assertThat(controller.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(1) } - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_landscapeDevice_resizable_undefinedOrientation_defaultLandscapeBounds() { - val task = setUpFullscreenTask() - setUpLandscapeDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_landscapeDevice_resizable_landscapeOrientation_defaultLandscapeBounds() { - val task = setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_LANDSCAPE) - setUpLandscapeDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_landscapeDevice_resizable_portraitOrientation_resizablePortraitBounds() { - val task = - setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_PORTRAIT, shouldLetterbox = true) - setUpLandscapeDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(RESIZABLE_PORTRAIT_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_landscapeDevice_unResizable_landscapeOrientation_defaultLandscapeBounds() { - val task = - setUpFullscreenTask(isResizable = false, screenOrientation = SCREEN_ORIENTATION_LANDSCAPE) - setUpLandscapeDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_landscapeDevice_unResizable_portraitOrientation_unResizablePortraitBounds() { - val task = - setUpFullscreenTask( - isResizable = false, - screenOrientation = SCREEN_ORIENTATION_PORTRAIT, - shouldLetterbox = true) - setUpLandscapeDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_PORTRAIT_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_portraitDevice_resizable_undefinedOrientation_defaultPortraitBounds() { - val task = setUpFullscreenTask(deviceOrientation = ORIENTATION_PORTRAIT) - setUpPortraitDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_portraitDevice_resizable_portraitOrientation_defaultPortraitBounds() { - val task = - setUpFullscreenTask( - deviceOrientation = ORIENTATION_PORTRAIT, - screenOrientation = SCREEN_ORIENTATION_PORTRAIT) - setUpPortraitDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_portraitDevice_resizable_landscapeOrientation_resizableLandscapeBounds() { - val task = - setUpFullscreenTask( - deviceOrientation = ORIENTATION_PORTRAIT, - screenOrientation = SCREEN_ORIENTATION_LANDSCAPE, - shouldLetterbox = true) - setUpPortraitDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(RESIZABLE_LANDSCAPE_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_portraitDevice_unResizable_portraitOrientation_defaultPortraitBounds() { - val task = - setUpFullscreenTask( - isResizable = false, - deviceOrientation = ORIENTATION_PORTRAIT, - screenOrientation = SCREEN_ORIENTATION_PORTRAIT) - setUpPortraitDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun moveToDesktop_portraitDevice_unResizable_landscapeOrientation_unResizableLandscapeBounds() { - val task = - setUpFullscreenTask( - isResizable = false, - deviceOrientation = ORIENTATION_PORTRAIT, - screenOrientation = SCREEN_ORIENTATION_LANDSCAPE, - shouldLetterbox = true) - setUpPortraitDisplay() - - controller.moveToDesktop(task, transitionSource = UNKNOWN) - val wct = getLatestEnterDesktopWct() - assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_LANDSCAPE_BOUNDS) - } - @Test fun moveToDesktop_tdaFullscreen_windowingModeSetToFreeform() { val task = setUpFullscreenTask() diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java index d9f11b1635cc..05d4c821c161 100644 --- a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java @@ -226,6 +226,14 @@ class AppCompatAspectRatioOverrides { : getDefaultMinAspectRatio(); } + float getDefaultMinAspectRatioForUnresizableAppsFromConfig() { + return mAppCompatConfiguration.getDefaultMinAspectRatioForUnresizableApps(); + } + + boolean isSplitScreenAspectRatioForUnresizableAppsEnabled() { + return mAppCompatConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled(); + } + private float getDisplaySizeMinAspectRatio() { final DisplayArea displayArea = mActivityRecord.getDisplayArea(); if (displayArea == null) { @@ -278,7 +286,7 @@ class AppCompatAspectRatioOverrides { return getSplitScreenAspectRatio(); } - private float getDefaultMinAspectRatio() { + float getDefaultMinAspectRatio() { if (mActivityRecord.getDisplayArea() == null || !mAppCompatConfiguration .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()) { diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java index f9f5058415c6..3ecdff6b18a0 100644 --- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java +++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java @@ -16,18 +16,33 @@ package com.android.server.wm; +import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; +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.server.wm.AppCompatConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW; +import static com.android.server.wm.AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO; +import static com.android.server.wm.AppCompatUtils.computeAspectRatio; import static com.android.server.wm.LaunchParamsUtil.applyLayoutGravity; import static com.android.server.wm.LaunchParamsUtil.calculateLayoutBounds; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; +import android.app.AppCompatTaskInfo; +import android.app.TaskInfo; import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.SystemProperties; import android.util.Size; import android.view.Gravity; +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; + import java.util.function.Consumer; /** @@ -38,6 +53,8 @@ public final class DesktopModeBoundsCalculator { public static final float DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f; + public static final int DESKTOP_MODE_LANDSCAPE_APP_PADDING = SystemProperties + .getInt("persist.wm.debug.desktop_mode_landscape_app_padding", 25); /** * Updates launch bounds for an activity with respect to its activity options, window layout, @@ -48,12 +65,8 @@ public final class DesktopModeBoundsCalculator { @NonNull Rect outBounds, @NonNull Consumer 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 TaskDisplayArea displayArea = task.getDisplayArea(); - final Rect screenBounds = displayArea.getBounds(); final Rect stableBounds = new Rect(); - displayArea.getStableRect(stableBounds); - final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); - final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + task.getDisplayArea().getStableRect(stableBounds); if (options != null && options.getLaunchBounds() != null) { outBounds.set(options.getLaunchBounds()); @@ -63,37 +76,282 @@ public final class DesktopModeBoundsCalculator { final int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (layout.hasSpecifiedSize()) { calculateLayoutBounds(stableBounds, layout, outBounds, - new Size(desiredWidth, desiredHeight)); + calculateIdealSize(stableBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); applyLayoutGravity(verticalGravity, horizontalGravity, outBounds, stableBounds); logger.accept("layout specifies sizes, inheriting size and applying gravity"); } else if (verticalGravity > 0 || horizontalGravity > 0) { - calculateAndCentreInitialBounds(outBounds, screenBounds); + outBounds.set(calculateInitialBounds(task, activity, stableBounds)); applyLayoutGravity(verticalGravity, horizontalGravity, outBounds, stableBounds); logger.accept("layout specifies gravity, applying desired bounds and gravity"); } } else { - calculateAndCentreInitialBounds(outBounds, screenBounds); + outBounds.set(calculateInitialBounds(task, activity, stableBounds)); logger.accept("layout not specified, applying desired bounds"); } } /** - * Calculates the initial height and width of a task in desktop mode and centers it within the - * window bounds. + * Calculates the initial bounds required for an application to fill a scale of the display + * bounds without any letterboxing. This is done by taking into account the applications + * fullscreen size, aspect ratio, orientation and resizability to calculate an area this is + * compatible with the applications previous configuration. + */ + private static @NonNull Rect calculateInitialBounds(@NonNull Task task, + @NonNull ActivityRecord activity, @NonNull Rect stableBounds + ) { + final TaskInfo taskInfo = task.getTaskInfo(); + // Display bounds not taking into account insets. + final TaskDisplayArea displayArea = task.getDisplayArea(); + final Rect screenBounds = displayArea.getBounds(); + final Size idealSize = calculateIdealSize(screenBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + if (!Flags.enableWindowingDynamicInitialBounds()) { + return centerInScreen(idealSize, screenBounds); + } + // TODO(b/353457301): Replace with app compat aspect ratio method when refactoring complete. + float appAspectRatio = calculateAspectRatio(task, activity); + final float tdaWidth = stableBounds.width(); + final float tdaHeight = stableBounds.height(); + final int activityOrientation = activity.getOverrideOrientation(); + final Size initialSize = switch (taskInfo.configuration.orientation) { + case ORIENTATION_LANDSCAPE -> { + // Device in landscape orientation. + if (appAspectRatio == 0) { + appAspectRatio = 1; + } + if (taskInfo.isResizeable) { + if (isFixedOrientationPortrait(activityOrientation)) { + // For portrait resizeable activities, respect apps fullscreen width but + // apply ideal size height. + yield new Size((int) ((tdaHeight / appAspectRatio) + 0.5f), + idealSize.getHeight()); + } + // For landscape resizeable activities, simply apply ideal size. + yield idealSize; + } + // If activity is unresizeable, regardless of orientation, calculate maximum size + // (within the ideal size) maintaining original aspect ratio. + yield maximizeSizeGivenAspectRatio( + activity.getOverrideOrientation(), idealSize, appAspectRatio); + } + case ORIENTATION_PORTRAIT -> { + // Device in portrait orientation. + final int customPortraitWidthForLandscapeApp = screenBounds.width() + - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2); + if (taskInfo.isResizeable) { + if (isFixedOrientationLandscape(activityOrientation)) { + if (appAspectRatio == 0) { + appAspectRatio = tdaWidth / (tdaWidth - 1); + } + // For landscape resizeable activities, respect apps fullscreen height and + // apply custom app width. + yield new Size(customPortraitWidthForLandscapeApp, + (int) ((tdaWidth / appAspectRatio) + 0.5f)); + } + // For portrait resizeable activities, simply apply ideal size. + yield idealSize; + } + if (appAspectRatio == 0) { + appAspectRatio = 1; + } + if (isFixedOrientationLandscape(activityOrientation)) { + // For landscape unresizeable activities, apply custom app width to ideal size + // and calculate maximum size with this area while maintaining original aspect + // ratio. + yield maximizeSizeGivenAspectRatio(activityOrientation, + new Size(customPortraitWidthForLandscapeApp, idealSize.getHeight()), + appAspectRatio); + } + // For portrait unresizeable activities, calculate maximum size (within the ideal + // size) maintaining original aspect ratio. + yield maximizeSizeGivenAspectRatio(activityOrientation, idealSize, appAspectRatio); + } + default -> idealSize; + }; + return centerInScreen(initialSize, screenBounds); + } + + /** + * Calculates the largest size that can fit in a given area while maintaining a specific aspect + * ratio. + */ + private static @NonNull Size maximizeSizeGivenAspectRatio( + @ActivityInfo.ScreenOrientation int orientation, + @NonNull Size targetArea, + float aspectRatio + ) { + final int targetHeight = targetArea.getHeight(); + final int targetWidth = targetArea.getWidth(); + final int finalHeight; + final int finalWidth; + if (isFixedOrientationPortrait(orientation)) { + // Portrait activity. + // Calculate required width given ideal height and aspect ratio. + int tempWidth = (int) (targetHeight / aspectRatio); + if (tempWidth <= targetWidth) { + // If the calculated width does not exceed the ideal width, overall size is within + // ideal size and can be applied. + finalHeight = targetHeight; + finalWidth = tempWidth; + } else { + // Applying target height cause overall size to exceed ideal size when maintain + // aspect ratio. Instead apply ideal width and calculate required height to respect + // aspect ratio. + finalWidth = targetWidth; + finalHeight = (int) (finalWidth * aspectRatio); + } + } else { + // Landscape activity. + // Calculate required width given ideal height and aspect ratio. + int tempWidth = (int) (targetHeight * aspectRatio); + if (tempWidth <= targetWidth) { + // If the calculated width does not exceed the ideal width, overall size is within + // ideal size and can be applied. + finalHeight = targetHeight; + finalWidth = tempWidth; + } else { + // Applying target height cause overall size to exceed ideal size when maintain + // aspect ratio. Instead apply ideal width and calculate required height to respect + // aspect ratio. + finalWidth = targetWidth; + finalHeight = (int) (finalWidth / aspectRatio); + } + } + return new Size(finalWidth, finalHeight); + } + + /** + * Calculates the aspect ratio of an activity from its fullscreen bounds. + */ + @VisibleForTesting + static float calculateAspectRatio(@NonNull Task task, @NonNull ActivityRecord activity) { + final TaskInfo taskInfo = task.getTaskInfo(); + final float fullscreenWidth = task.getDisplayArea().getBounds().width(); + final float fullscreenHeight = task.getDisplayArea().getBounds().height(); + final float maxAspectRatio = activity.getMaxAspectRatio(); + final float minAspectRatio = activity.getMinAspectRatio(); + float desiredAspectRatio = 0; + if (taskInfo.isRunning) { + final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo; + if (appCompatTaskInfo.topActivityBoundsLetterboxed) { + desiredAspectRatio = (float) Math.max( + appCompatTaskInfo.topActivityLetterboxWidth, + appCompatTaskInfo.topActivityLetterboxHeight) + / Math.min(appCompatTaskInfo.topActivityLetterboxWidth, + appCompatTaskInfo.topActivityLetterboxHeight); + } else { + desiredAspectRatio = Math.max(fullscreenHeight, fullscreenWidth) + / Math.min(fullscreenHeight, fullscreenWidth); + } + } else { + final float letterboxAspectRatioOverride = + getFixedOrientationLetterboxAspectRatio(activity, task); + if (!task.mDisplayContent.getIgnoreOrientationRequest()) { + desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW; + } else if (letterboxAspectRatioOverride + > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) { + desiredAspectRatio = letterboxAspectRatioOverride; + } + } + // If the activity matches display orientation, the display aspect ratio should be used + if (activityMatchesDisplayOrientation( + taskInfo.configuration.orientation, + activity.getOverrideOrientation())) { + desiredAspectRatio = Math.max(fullscreenWidth, fullscreenHeight) + / Math.min(fullscreenWidth, fullscreenHeight); + } + if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) { + desiredAspectRatio = maxAspectRatio; + } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) { + desiredAspectRatio = minAspectRatio; + } + return desiredAspectRatio; + } + + private static boolean activityMatchesDisplayOrientation( + @Configuration.Orientation int deviceOrientation, + @ActivityInfo.ScreenOrientation int activityOrientation) { + if (deviceOrientation == ORIENTATION_PORTRAIT) { + return isFixedOrientationPortrait(activityOrientation); + } + return isFixedOrientationLandscape(activityOrientation); + } + + /** + * Calculates the desired initial bounds for applications in desktop windowing. This is done as + * a scale of the screen bounds. + */ + private static @NonNull Size calculateIdealSize(@NonNull Rect screenBounds, float scale) { + final int width = (int) (screenBounds.width() * scale); + final int height = (int) (screenBounds.height() * scale); + return new Size(width, height); + } + + /** + * Adjusts bounds to be positioned in the middle of the screen. */ - private static void calculateAndCentreInitialBounds(@NonNull Rect outBounds, + private static @NonNull Rect centerInScreen(@NonNull Size desiredSize, @NonNull Rect screenBounds) { - // TODO(b/319819547): Account for app constraints so apps do not become letterboxed - // The desired dimensions that a fully resizable window should take when initially entering - // desktop mode. Calculated as a percentage of the available display area as defined by the - // DESKTOP_MODE_INITIAL_BOUNDS_SCALE. - final int desiredWidth = (int) (screenBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); - final int desiredHeight = (int) (screenBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); - outBounds.right = desiredWidth; - outBounds.bottom = desiredHeight; - outBounds.offset(screenBounds.centerX() - outBounds.centerX(), - screenBounds.centerY() - outBounds.centerY()); + // TODO(b/325240051): Position apps with bottom heavy offset + final int heightOffset = (screenBounds.height() - desiredSize.getHeight()) / 2; + final int widthOffset = (screenBounds.width() - desiredSize.getWidth()) / 2; + final Rect resultBounds = new Rect(0, 0, + desiredSize.getWidth(), desiredSize.getHeight()); + resultBounds.offset(screenBounds.left + widthOffset, screenBounds.top + heightOffset); + return resultBounds; + } + + private static float getFixedOrientationLetterboxAspectRatio(@NonNull ActivityRecord activity, + @NonNull Task task) { + return activity.shouldCreateCompatDisplayInsets() + ? getDefaultMinAspectRatioForUnresizableApps(activity, task) + : activity.mAppCompatController.getAppCompatAspectRatioOverrides() + .getDefaultMinAspectRatio(); + } + + private static float getDefaultMinAspectRatioForUnresizableApps( + @NonNull ActivityRecord activity, + @NonNull Task task) { + final AppCompatAspectRatioOverrides appCompatAspectRatioOverrides = + activity.mAppCompatController.getAppCompatAspectRatioOverrides(); + if (appCompatAspectRatioOverrides.isSplitScreenAspectRatioForUnresizableAppsEnabled()) { + // Default letterbox aspect ratio for unresizable apps. + return getSplitScreenAspectRatio(activity, task); + } + + if (appCompatAspectRatioOverrides.getDefaultMinAspectRatioForUnresizableAppsFromConfig() + > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) { + return appCompatAspectRatioOverrides + .getDefaultMinAspectRatioForUnresizableAppsFromConfig(); + } + + return appCompatAspectRatioOverrides.getDefaultMinAspectRatio(); + } + + /** + * Calculates the aspect ratio of the available display area when an app enters split-screen on + * a given device, taking into account any dividers and insets. + */ + private static float getSplitScreenAspectRatio(@NonNull ActivityRecord activity, + @NonNull Task task) { + final int dividerWindowWidth = + activity.mWmService.mContext.getResources().getDimensionPixelSize( + R.dimen.docked_stack_divider_thickness); + final int dividerInsets = + activity.mWmService.mContext.getResources().getDimensionPixelSize( + R.dimen.docked_stack_divider_insets); + final int dividerSize = dividerWindowWidth - dividerInsets * 2; + final Rect bounds = new Rect(0, 0, + task.mDisplayContent.getDisplayInfo().appWidth, + task.mDisplayContent.getDisplayInfo().appHeight); + if (bounds.width() >= bounds.height()) { + bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0); + bounds.right = bounds.centerX(); + } else { + bounds.inset(/* dx */ 0, /* dy */ dividerSize / 2); + bounds.bottom = bounds.centerY(); + } + return computeAspectRatio(bounds); } } diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java index aacd3c65154f..548addbef39d 100644 --- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java @@ -25,7 +25,6 @@ import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.Context; import android.content.pm.ActivityInfo; -import android.os.SystemProperties; import android.util.Slog; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; @@ -38,19 +37,9 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM; private static final boolean DEBUG = false; - public static final float DESKTOP_MODE_INITIAL_BOUNDS_SCALE = - SystemProperties - .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f; - - /** - * Flag to indicate whether to restrict desktop mode to supported devices. - */ - private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( - "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); - private StringBuilder mLogBuilder; - private final Context mContext; + @NonNull private final Context mContext; DesktopModeLaunchParamsModifier(@NonNull Context context) { mContext = context; 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 23a88a1774f4..b687042edfc3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java @@ -21,9 +21,19 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.server.wm.DesktopModeLaunchParamsModifier.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; +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.calculateAspectRatio; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; @@ -59,6 +69,10 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) public class DesktopModeLaunchParamsModifierTests extends LaunchParamsModifierTestsBase { + private static final Rect LANDSCAPE_DISPLAY_BOUNDS = new Rect(0, 0, 2560, 1600); + private static final Rect PORTRAIT_DISPLAY_BOUNDS = new Rect(0, 0, 1600, 2560); + private static final float LETTERBOX_ASPECT_RATIO = 1.3f; + @Before public void setUp() throws Exception { mActivity = new ActivityBuilder(mAtm).build(); @@ -158,6 +172,7 @@ public class DesktopModeLaunchParamsModifierTests extends @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @DisableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) public void testUsesDesiredBoundsIfEmptyLayoutAndActivityOptionsBounds() { setupDesktopModeLaunchParamsModifier(); @@ -169,6 +184,209 @@ public class DesktopModeLaunchParamsModifierTests extends (int) (DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int desiredHeight = (int) (DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS}) + public void testDefaultLandscapeBounds_landscapeDevice_resizable_undefinedOrientation() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE, + LANDSCAPE_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_UNSPECIFIED, true); + + final int desiredWidth = + (int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = + (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS}) + public void testDefaultLandscapeBounds_landscapeDevice_resizable_landscapeOrientation() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE, + LANDSCAPE_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, true); + + final int desiredWidth = + (int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = + (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) + public void testResizablePortraitBounds_landscapeDevice_resizable_portraitOrientation() { + setupDesktopModeLaunchParamsModifier(); + doReturn(LETTERBOX_ASPECT_RATIO).when(() + -> calculateAspectRatio(any(), any())); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE, + LANDSCAPE_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, true); + + final int desiredWidth = + (int) ((LANDSCAPE_DISPLAY_BOUNDS.height() / LETTERBOX_ASPECT_RATIO) + 0.5f); + final int desiredHeight = + (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS}) + public void testDefaultLandscapeBounds_landscapeDevice_unResizable_landscapeOrientation() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE, + LANDSCAPE_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, false); + + final int desiredWidth = + (int) (LANDSCAPE_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = + (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) + public void testUnResizablePortraitBounds_landscapeDevice_unResizable_portraitOrientation() { + setupDesktopModeLaunchParamsModifier(); + doReturn(LETTERBOX_ASPECT_RATIO).when(() + -> calculateAspectRatio(any(), any())); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_LANDSCAPE, + LANDSCAPE_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, false); + + final int desiredHeight = + (int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredWidth = (int) (desiredHeight / LETTERBOX_ASPECT_RATIO); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS}) + public void testDefaultPortraitBounds_portraitDevice_resizable_undefinedOrientation() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT, + PORTRAIT_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_UNSPECIFIED, true); + + final int desiredWidth = + (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = + (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS}) + public void testDefaultPortraitBounds_portraitDevice_resizable_portraitOrientation() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT, + PORTRAIT_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, true); + + final int desiredWidth = + (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = + (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) + public void testResizableLandscapeBounds_portraitDevice_resizable_landscapeOrientation() { + setupDesktopModeLaunchParamsModifier(); + doReturn(LETTERBOX_ASPECT_RATIO).when(() + -> calculateAspectRatio(any(), any())); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT, + PORTRAIT_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, true); + + final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width() + - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2); + final int desiredHeight = (int) + ((PORTRAIT_DISPLAY_BOUNDS.width() / LETTERBOX_ASPECT_RATIO) + 0.5f); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS}) + public void testDefaultPortraitBounds_portraitDevice_unResizable_portraitOrientation() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT, + PORTRAIT_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_PORTRAIT, false); + + final int desiredWidth = + (int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = + (int) (PORTRAIT_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) + public void testUnResizableLandscapeBounds_portraitDevice_unResizable_landscapeOrientation() { + setupDesktopModeLaunchParamsModifier(); + doReturn(LETTERBOX_ASPECT_RATIO).when(() + -> calculateAspectRatio(any(), any())); + + final TestDisplayContent display = createDisplayContent(ORIENTATION_PORTRAIT, + PORTRAIT_DISPLAY_BOUNDS); + final Task task = createTask(display, SCREEN_ORIENTATION_LANDSCAPE, false); + + final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width() + - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2); + final int desiredHeight = (int) (desiredWidth / LETTERBOX_ASPECT_RATIO); + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task).calculate()); assertEquals(desiredWidth, mResult.mBounds.width()); assertEquals(desiredHeight, mResult.mBounds.height()); @@ -192,6 +410,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_CenterToDisplay() { setupDesktopModeLaunchParamsModifier(); @@ -207,6 +426,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_LeftGravity() { setupDesktopModeLaunchParamsModifier(); @@ -222,6 +442,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_TopGravity() { setupDesktopModeLaunchParamsModifier(); @@ -237,6 +458,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_TopLeftGravity() { setupDesktopModeLaunchParamsModifier(); @@ -252,6 +474,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_RightGravity() { setupDesktopModeLaunchParamsModifier(); @@ -267,6 +490,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_BottomGravity() { setupDesktopModeLaunchParamsModifier(); @@ -282,6 +506,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_RightBottomGravity() { setupDesktopModeLaunchParamsModifier(); @@ -297,6 +522,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutFractionBounds() { setupDesktopModeLaunchParamsModifier(); @@ -312,6 +538,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() { setupDesktopModeLaunchParamsModifier(); @@ -327,6 +554,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() { setupDesktopModeLaunchParamsModifier(); @@ -342,6 +570,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() { setupDesktopModeLaunchParamsModifier(); @@ -359,6 +588,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() { setupDesktopModeLaunchParamsModifier(); @@ -374,6 +604,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() { setupDesktopModeLaunchParamsModifier(); @@ -389,6 +620,7 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() { setupDesktopModeLaunchParamsModifier(); @@ -422,6 +654,38 @@ public class DesktopModeLaunchParamsModifierTests extends assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode); } + private Task createTask(DisplayContent display, int orientation, Boolean isResizeable) { + final int resizeMode = isResizeable ? RESIZE_MODE_RESIZEABLE + : RESIZE_MODE_UNRESIZEABLE; + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + task.setResizeMode(resizeMode); + mActivity = new ActivityBuilder(task.mAtmService) + .setTask(task) + .setScreenOrientation(orientation) + .setOnTop(true).build(); + + mActivity.onDisplayChanged(display); + mActivity.setOccludesParent(true); + mActivity.setVisible(true); + mActivity.setVisibleRequested(true); + mActivity.mDisplayContent.setIgnoreOrientationRequest(/* ignoreOrientationRequest */ true); + + return task; + } + + private TestDisplayContent createDisplayContent(int orientation, Rect displayBounds) { + final TestDisplayContent display = new TestDisplayContent + .Builder(mAtm, displayBounds.width(), displayBounds.height()) + .setPosition(DisplayContent.POSITION_TOP).build(); + display.setBounds(displayBounds); + display.getConfiguration().densityDpi = DENSITY_DEFAULT; + display.getConfiguration().orientation = ORIENTATION_LANDSCAPE; + display.getDefaultTaskDisplayArea().setWindowingMode(orientation); + + return display; + } + private void setupDesktopModeLaunchParamsModifier() { setupDesktopModeLaunchParamsModifier(/*isDesktopModeSupported=*/ true, /*enforceDeviceRestrictions=*/ true); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index a816aa9b7598..d5d284783978 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -203,6 +203,7 @@ public class SystemServicesTestRule implements TestRule { .mockStatic(LockGuard.class, mockStubOnly) .mockStatic(Watchdog.class, mockStubOnly) .spyStatic(DesktopModeHelper.class) + .spyStatic(DesktopModeBoundsCalculator.class) .strictness(Strictness.LENIENT) .startMocking(); -- cgit v1.2.3-59-g8ed1b