Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe06ce7a authored by Eghosa Ewansiha-Vlachavas's avatar Eghosa Ewansiha-Vlachavas Committed by Android (Google) Code Review
Browse files

Merge "Recalculate desktop bounds for runtime orientation change" into main

parents 09e40abb 3ce53c5e
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1213,7 +1213,8 @@ public abstract class WMShellModule {
            ShellTaskOrganizer shellTaskOrganizer,
            TaskStackListenerImpl taskStackListener,
            ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
            @DynamicOverride DesktopUserRepositories desktopUserRepositories) {
            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
            DisplayController displayController) {
        if (DesktopModeStatus.canEnterDesktopMode(context)) {
            return Optional.of(
                    new DesktopActivityOrientationChangeHandler(
@@ -1222,7 +1223,8 @@ public abstract class WMShellModule {
                            shellTaskOrganizer,
                            taskStackListener,
                            toggleResizeDesktopTaskTransitionHandler,
                            desktopUserRepositories));
                            desktopUserRepositories,
                            displayController));
        }
        return Optional.empty();
    }
+18 −5
Original line number Diff line number Diff line
@@ -23,10 +23,10 @@ import android.content.pm.ActivityInfo.ScreenOrientation
import android.content.res.Configuration.ORIENTATION_LANDSCAPE
import android.content.res.Configuration.ORIENTATION_PORTRAIT
import android.graphics.Rect
import android.util.Size
import android.window.WindowContainerTransaction
import com.android.window.flags.Flags
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.TaskStackListenerCallback
import com.android.wm.shell.common.TaskStackListenerImpl
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
@@ -40,6 +40,7 @@ class DesktopActivityOrientationChangeHandler(
    private val taskStackListener: TaskStackListenerImpl,
    private val resizeHandler: ToggleResizeDesktopTaskTransitionHandler,
    private val desktopUserRepositories: DesktopUserRepositories,
    private val displayController: DisplayController,
) {

    init {
@@ -101,12 +102,24 @@ class DesktopActivityOrientationChangeHandler(
                orientation == ORIENTATION_LANDSCAPE &&
                    ActivityInfo.isFixedOrientationPortrait(requestedOrientation)
        ) {
            val displayLayout = displayController.getDisplayLayout(task.displayId) ?: return
            val captionInsets =
                task.configuration.windowConfiguration.appBounds?.let {
                    it.top - task.configuration.windowConfiguration.bounds.top
                } ?: 0
            val newOrientationBounds =
                calculateInitialBounds(
                    displayLayout = displayLayout,
                    taskInfo = task,
                    captionInsets = captionInsets,
                    requestedScreenOrientation = requestedOrientation,
                )

            val finalSize = Size(taskHeight, taskWidth)
            // Use the center x as the resizing anchor point.
            val left = taskBounds.centerX() - finalSize.width / 2
            val right = left + finalSize.width
            val finalBounds = Rect(left, taskBounds.top, right, taskBounds.top + finalSize.height)
            val left = taskBounds.centerX() - newOrientationBounds.width() / 2
            val right = left + newOrientationBounds.width()
            val finalBounds =
                Rect(left, taskBounds.top, right, taskBounds.top + newOrientationBounds.height())

            val wct = WindowContainerTransaction().setBounds(task.token, finalBounds)
            resizeHandler.startTransition(wct)
+20 −8
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ fun calculateInitialBounds(
    taskInfo: RunningTaskInfo,
    scale: Float = DESKTOP_MODE_INITIAL_BOUNDS_SCALE,
    captionInsets: Int = 0,
    requestedScreenOrientation: Int? = null,
): Rect {
    val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height())
    val appAspectRatio = calculateAspectRatio(taskInfo)
@@ -85,12 +86,13 @@ fun calculateInitialBounds(
    }
    val topActivityInfo =
        taskInfo.topActivityInfo ?: return positionInScreen(idealSize, stableBounds)
    val screenOrientation = requestedScreenOrientation ?: topActivityInfo.screenOrientation

    val initialSize: Size =
        when (taskInfo.configuration.orientation) {
            ORIENTATION_LANDSCAPE -> {
                if (taskInfo.canChangeAspectRatio) {
                    if (isFixedOrientationPortrait(topActivityInfo.screenOrientation)) {
                    if (isFixedOrientationPortrait(screenOrientation)) {
                        // For portrait resizeable activities, respect apps fullscreen width but
                        // apply ideal size height.
                        Size(
@@ -104,14 +106,20 @@ fun calculateInitialBounds(
                } else {
                    // If activity is unresizeable, regardless of orientation, calculate maximum
                    // size (within the ideal size) maintaining original aspect ratio.
                    maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio, captionInsets)
                    maximizeSizeGivenAspectRatio(
                        taskInfo,
                        idealSize,
                        appAspectRatio,
                        captionInsets,
                        screenOrientation,
                    )
                }
            }
            ORIENTATION_PORTRAIT -> {
                val customPortraitWidthForLandscapeApp =
                    screenBounds.width() - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2)
                if (taskInfo.canChangeAspectRatio) {
                    if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) {
                    if (isFixedOrientationLandscape(screenOrientation)) {
                        // For landscape resizeable activities, respect apps fullscreen height and
                        // apply custom app width.
                        Size(
@@ -123,7 +131,7 @@ fun calculateInitialBounds(
                        idealSize
                    }
                } else {
                    if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) {
                    if (isFixedOrientationLandscape(screenOrientation)) {
                        // For landscape unresizeable activities, apply custom app width to ideal
                        // size and calculate maximum size with this area while maintaining original
                        // aspect ratio.
@@ -132,6 +140,7 @@ fun calculateInitialBounds(
                            Size(customPortraitWidthForLandscapeApp, idealSize.height),
                            appAspectRatio,
                            captionInsets,
                            screenOrientation,
                        )
                    } else {
                        // For portrait unresizeable activities, calculate maximum size (within the
@@ -141,6 +150,7 @@ fun calculateInitialBounds(
                            idealSize,
                            appAspectRatio,
                            captionInsets,
                            screenOrientation,
                        )
                    }
                }
@@ -190,13 +200,16 @@ fun maximizeSizeGivenAspectRatio(
    targetArea: Size,
    aspectRatio: Float,
    captionInsets: Int = 0,
    requestedScreenOrientation: Int? = null,
): Size {
    val targetHeight = targetArea.height - captionInsets
    val targetWidth = targetArea.width
    val finalHeight: Int
    val finalWidth: Int
    // Get orientation either through top activity or task's orientation
    if (taskInfo.hasPortraitTopActivity()) {
    val screenOrientation =
        requestedScreenOrientation ?: taskInfo.topActivityInfo?.screenOrientation
    if (taskInfo.hasPortraitTopActivity(screenOrientation)) {
        val tempWidth = ceil(targetHeight / aspectRatio).toInt()
        if (tempWidth <= targetWidth) {
            finalHeight = targetHeight
@@ -354,9 +367,8 @@ fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart:
    return Rect(newLeft, newTop, newRight, newBottom)
}

private fun TaskInfo.hasPortraitTopActivity(): Boolean {
    val topActivityScreenOrientation =
        topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED
private fun TaskInfo.hasPortraitTopActivity(screenOrientation: Int?): Boolean {
    val topActivityScreenOrientation = screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED
    val appBounds = configuration.windowConfiguration.appBounds

    return when {
+18 −0
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
import com.android.window.flags.Flags.FLAG_RESPECT_ORIENTATION_CHANGE_FOR_UNRESIZEABLE
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.TaskStackListenerImpl
import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
@@ -96,12 +98,15 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
    @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
    @Mock lateinit var userManager: UserManager
    @Mock lateinit var shellController: ShellController
    @Mock lateinit var displayController: DisplayController
    @Mock lateinit var displayLayout: DisplayLayout

    private lateinit var mockitoSession: StaticMockitoSession
    private lateinit var handler: DesktopActivityOrientationChangeHandler
    private lateinit var shellInit: ShellInit
    private lateinit var userRepositories: DesktopUserRepositories
    private lateinit var testScope: CoroutineScope

    // Mock running tasks are registered here so we can get the list from mock shell task organizer.
    private val runningTasks = mutableListOf<RunningTaskInfo>()

@@ -131,6 +136,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
        whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
        whenever(runBlocking { persistentRepository.readDesktop(any(), any()) })
            .thenReturn(Desktop.getDefaultInstance())
        whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)

        handler =
            DesktopActivityOrientationChangeHandler(
@@ -140,6 +146,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
                taskStackListener,
                resizeTransitionHandler,
                userRepositories,
                displayController,
            )

        shellInit.init()
@@ -171,6 +178,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
                taskStackListener,
                resizeTransitionHandler,
                userRepositories,
                displayController,
            )

        verify(shellInit, never())
@@ -251,6 +259,11 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
        val oldBounds = task.configuration.windowConfiguration.bounds
        val newTask =
            setUpFreeformTask(isResizeable = false, orientation = SCREEN_ORIENTATION_LANDSCAPE)
        whenever(displayLayout.height()).thenReturn(800)
        whenever(displayLayout.width()).thenReturn(2000)
        whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
            (i.arguments.first() as Rect).set(Rect(0, 0, 2000, 800))
        }

        handler.handleActivityOrientationChange(task, newTask)

@@ -279,6 +292,11 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
                bounds = oldBounds,
            )
        val newTask = setUpFreeformTask(isResizeable = false, bounds = oldBounds)
        whenever(displayLayout.height()).thenReturn(2000)
        whenever(displayLayout.width()).thenReturn(800)
        whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
            (i.arguments.first() as Rect).set(Rect(0, 0, 800, 2000))
        }

        handler.handleActivityOrientationChange(task, newTask)