diff options
Diffstat (limited to 'libs')
3 files changed, 133 insertions, 12 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 217b1d356122..1bf125938e6f 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 @@ -19,6 +19,8 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo +import android.app.TaskInfo +import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED import android.content.pm.ActivityInfo.isFixedOrientationLandscape import android.content.pm.ActivityInfo.isFixedOrientationPortrait import android.content.res.Configuration.ORIENTATION_LANDSCAPE @@ -105,7 +107,7 @@ fun calculateInitialBounds( * Calculates the largest size that can fit in a given area while maintaining a specific aspect * ratio. */ -private fun maximumSizeMaintainingAspectRatio( +fun maximumSizeMaintainingAspectRatio( taskInfo: RunningTaskInfo, targetArea: Size, aspectRatio: Float @@ -114,7 +116,8 @@ private fun maximumSizeMaintainingAspectRatio( val targetWidth = targetArea.width val finalHeight: Int val finalWidth: Int - if (isFixedOrientationPortrait(taskInfo.topActivityInfo!!.screenOrientation)) { + // Get orientation either through top activity or task's orientation + if (taskInfo.hasPortraitTopActivity()) { val tempWidth = (targetHeight / aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight @@ -137,7 +140,7 @@ private fun maximumSizeMaintainingAspectRatio( } /** Calculates the aspect ratio of an activity from its fullscreen bounds. */ -private fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float { +fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float { if (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed) { val appLetterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxWidth val appLetterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxHeight @@ -171,3 +174,41 @@ private fun positionInScreen(desiredSize: Size, screenBounds: Rect): Rect { desiredSize.height + heightOffset ) } + +/** + * Adjusts bounds to be positioned in the middle of the area provided, not necessarily the + * entire screen, as area can be offset by left and top start. + */ +fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart: Int): Rect { + val heightOffset = (areaBounds.height() - desiredSize.height) / 2 + val widthOffset = (areaBounds.width() - desiredSize.width) / 2 + + val newLeft = leftStart + widthOffset + val newTop = topStart + heightOffset + val newRight = newLeft + desiredSize.width + val newBottom = newTop + desiredSize.height + + return Rect(newLeft, newTop, newRight, newBottom) +} + +fun TaskInfo.hasPortraitTopActivity(): Boolean { + val topActivityScreenOrientation = + topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED + val appBounds = configuration.windowConfiguration.appBounds + + return when { + // First check if activity has portrait screen orientation + topActivityScreenOrientation != SCREEN_ORIENTATION_UNSPECIFIED -> { + isFixedOrientationPortrait(topActivityScreenOrientation) + } + + // Then check if the activity is portrait when letterboxed + appCompatTaskInfo.topActivityBoundsLetterboxed -> appCompatTaskInfo.isTopActivityPillarboxed + + // Then check if the activity is portrait + appBounds != null -> appBounds.height() > appBounds.width() + + // Otherwise just take the orientation of the task + else -> isFixedOrientationPortrait(configuration.orientation) + } +} 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 5813f8513b06..d8e8c57148ab 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 @@ -36,6 +36,7 @@ import android.graphics.Rect import android.graphics.Region import android.os.IBinder import android.os.SystemProperties +import android.util.Size import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE @@ -649,13 +650,21 @@ class DesktopTasksController( fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return - val stableBounds = Rect() - displayLayout.getStableBounds(stableBounds) + val stableBounds = Rect().apply { displayLayout.getStableBounds(this) } + val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds val destinationBounds = Rect() - if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) { - // The desktop task is currently occupying the whole stable bounds. If the bounds - // before the task was toggled to stable bounds were saved, toggle the task to those - // bounds. Otherwise, toggle to the default bounds. + + val isMaximized = if (taskInfo.isResizeable) { + currentTaskBounds == stableBounds + } else { + currentTaskBounds.width() == stableBounds.width() + || currentTaskBounds.height() == stableBounds.height() + } + + if (isMaximized) { + // The desktop task is at the maximized width and/or height of the stable bounds. + // If the task's pre-maximize stable bounds were saved, toggle the task to those bounds. + // Otherwise, toggle to the default bounds. val taskBoundsBeforeMaximize = desktopModeTaskRepository.removeBoundsBeforeMaximize(taskInfo.taskId) if (taskBoundsBeforeMaximize != null) { @@ -670,9 +679,20 @@ class DesktopTasksController( } else { // Save current bounds so that task can be restored back to original bounds if necessary // and toggle to the stable bounds. - val taskBounds = taskInfo.configuration.windowConfiguration.bounds - desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, taskBounds) - destinationBounds.set(stableBounds) + desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds) + + if (taskInfo.isResizeable) { + // if resizable then expand to entire stable bounds (full display minus insets) + destinationBounds.set(stableBounds) + } else { + // if non-resizable then calculate max bounds according to aspect ratio + val activityAspectRatio = calculateAspectRatio(taskInfo) + val newSize = maximumSizeMaintainingAspectRatio(taskInfo, + Size(stableBounds.width(), stableBounds.height()), activityAspectRatio) + val newBounds = centerInArea( + newSize, stableBounds, stableBounds.left, stableBounds.top) + destinationBounds.set(newBounds) + } } val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) 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 5f36e9a5e7b3..0bcbe139e31f 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 @@ -1916,6 +1916,26 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun toggleBounds_togglesToCalculatedBoundsForNonResizable() { + val bounds = Rect(0, 0, 200, 100) + val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply { + topActivityInfo = ActivityInfo().apply { + screenOrientation = SCREEN_ORIENTATION_LANDSCAPE + configuration.windowConfiguration.appBounds = bounds + } + isResizeable = false + } + + // Bounds should be 1000 x 500, vertically centered in the 1000 x 1000 stable bounds + val expectedBounds = Rect(STABLE_BOUNDS.left, 250, STABLE_BOUNDS.right, 750) + + controller.toggleDesktopTaskSize(task) + // Assert bounds set to stable bounds + val wct = getLatestToggleResizeDesktopTaskWct() + assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds) + } + + @Test fun toggleBounds_lastBoundsBeforeMaximizeSaved() { val bounds = Rect(0, 0, 100, 100) val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds) @@ -1942,6 +1962,46 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize_nonResizeableEqualWidth() { + val boundsBeforeMaximize = Rect(0, 0, 100, 100) + val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize).apply { + isResizeable = false + } + + // Maximize + controller.toggleDesktopTaskSize(task) + task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS.left, + boundsBeforeMaximize.top, STABLE_BOUNDS.right, boundsBeforeMaximize.bottom) + + // Restore + controller.toggleDesktopTaskSize(task) + + // Assert bounds set to last bounds before maximize + val wct = getLatestToggleResizeDesktopTaskWct() + assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize) + } + + @Test + fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize_nonResizeableEqualHeight() { + val boundsBeforeMaximize = Rect(0, 0, 100, 100) + val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize).apply { + isResizeable = false + } + + // Maximize + controller.toggleDesktopTaskSize(task) + task.configuration.windowConfiguration.bounds.set(boundsBeforeMaximize.left, + STABLE_BOUNDS.top, boundsBeforeMaximize.right, STABLE_BOUNDS.bottom) + + // Restore + controller.toggleDesktopTaskSize(task) + + // Assert bounds set to last bounds before maximize + val wct = getLatestToggleResizeDesktopTaskWct() + assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize) + } + + @Test fun toggleBounds_removesLastBoundsBeforeMaximizeAfterRestoringBounds() { val boundsBeforeMaximize = Rect(0, 0, 100, 100) val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize) |