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

Commit 9264b8c5 authored by Maryam Dehaini's avatar Maryam Dehaini Committed by Android (Google) Code Review
Browse files

Merge "Restore bounds when returning from maximized window bounds" into main

parents d2b16574 63efc310
Loading
Loading
Loading
Loading
+18 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.wm.shell.desktopmode
package com.android.wm.shell.desktopmode


import android.graphics.Rect
import android.graphics.Region
import android.graphics.Region
import android.util.ArrayMap
import android.util.ArrayMap
import android.util.ArraySet
import android.util.ArraySet
@@ -55,6 +56,8 @@ class DesktopModeTaskRepository {
    private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>()
    private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>()
    // Track corner/caption regions of desktop tasks, used to determine gesture exclusion
    // Track corner/caption regions of desktop tasks, used to determine gesture exclusion
    private val desktopExclusionRegions = SparseArray<Region>()
    private val desktopExclusionRegions = SparseArray<Region>()
    // Track last bounds of task before toggled to stable bounds
    private val boundsBeforeMaximizeByTaskId = SparseArray<Rect>()
    private var desktopGestureExclusionListener: Consumer<Region>? = null
    private var desktopGestureExclusionListener: Consumer<Region>? = null
    private var desktopGestureExclusionExecutor: Executor? = null
    private var desktopGestureExclusionExecutor: Executor? = null


@@ -307,6 +310,7 @@ class DesktopModeTaskRepository {
            taskId
            taskId
        )
        )
        freeformTasksInZOrder.remove(taskId)
        freeformTasksInZOrder.remove(taskId)
        boundsBeforeMaximizeByTaskId.remove(taskId)
        KtProtoLog.d(
        KtProtoLog.d(
            WM_SHELL_DESKTOP_MODE,
            WM_SHELL_DESKTOP_MODE,
            "DesktopTaskRepo: remaining freeform tasks: " + freeformTasksInZOrder.toDumpString()
            "DesktopTaskRepo: remaining freeform tasks: " + freeformTasksInZOrder.toDumpString()
@@ -357,6 +361,20 @@ class DesktopModeTaskRepository {
        }
        }
    }
    }


    /**
     * Removes and returns the bounds saved before maximizing the given task.
     */
    fun removeBoundsBeforeMaximize(taskId: Int): Rect? {
        return boundsBeforeMaximizeByTaskId.removeReturnOld(taskId)
    }

    /**
     * Saves the bounds of the given task before maximizing.
     */
    fun saveBoundsBeforeMaximize(taskId: Int, bounds: Rect) {
        boundsBeforeMaximizeByTaskId.set(taskId, Rect(bounds))
    }

    /**
    /**
     * Check if display with id [displayId] has desktop tasks stashed
     * Check if display with id [displayId] has desktop tasks stashed
     */
     */
+18 −6
Original line number Original line Diff line number Diff line
@@ -120,7 +120,6 @@ class DesktopTasksController(
    private var visualIndicator: DesktopModeVisualIndicator? = null
    private var visualIndicator: DesktopModeVisualIndicator? = null
    private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler =
    private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler =
        DesktopModeShellCommandHandler(this)
        DesktopModeShellCommandHandler(this)

    private val mOnAnimationFinishedCallback = Consumer<SurfaceControl.Transaction> {
    private val mOnAnimationFinishedCallback = Consumer<SurfaceControl.Transaction> {
        t: SurfaceControl.Transaction ->
        t: SurfaceControl.Transaction ->
        visualIndicator?.releaseVisualIndicator(t)
        visualIndicator?.releaseVisualIndicator(t)
@@ -570,7 +569,10 @@ class DesktopTasksController(
        }
        }
    }
    }


    /** Quick-resizes a desktop task, toggling between the stable bounds and the default bounds. */
    /**
     * Quick-resizes a desktop task, toggling between the stable bounds and the last saved bounds
     * if available or the default bounds otherwise.
     */
    fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) {
    fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) {
        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return


@@ -578,11 +580,21 @@ class DesktopTasksController(
        displayLayout.getStableBounds(stableBounds)
        displayLayout.getStableBounds(stableBounds)
        val destinationBounds = Rect()
        val destinationBounds = Rect()
        if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
        if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
            // The desktop task is currently occupying the whole stable bounds, toggle to the
            // The desktop task is currently occupying the whole stable bounds. If the bounds
            // default bounds.
            // before the task was toggled to 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) {
                destinationBounds.set(taskBoundsBeforeMaximize)
            } else {
                getDefaultDesktopTaskBounds(displayLayout, destinationBounds)
                getDefaultDesktopTaskBounds(displayLayout, destinationBounds)
            }
        } else {
        } else {
            // Toggle to the stable bounds.
            // 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)
            destinationBounds.set(stableBounds)
        }
        }


+26 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.wm.shell.desktopmode
package com.android.wm.shell.desktopmode


import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
import android.view.Display.DEFAULT_DISPLAY
import android.view.Display.INVALID_DISPLAY
import android.view.Display.INVALID_DISPLAY
@@ -406,6 +407,31 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
        assertThat(listener.stashedOnSecondaryDisplay).isTrue()
        assertThat(listener.stashedOnSecondaryDisplay).isTrue()
    }
    }


    @Test
    fun removeFreeformTask_removesTaskBoundsBeforeMaximize() {
        val taskId = 1
        repo.saveBoundsBeforeMaximize(taskId, Rect(0, 0, 200, 200))
        repo.removeFreeformTask(taskId)
        assertThat(repo.removeBoundsBeforeMaximize(taskId)).isNull()
    }

    @Test
    fun saveBoundsBeforeMaximize_boundsSavedByTaskId() {
        val taskId = 1
        val bounds = Rect(0, 0, 200, 200)
        repo.saveBoundsBeforeMaximize(taskId, bounds)
        assertThat(repo.removeBoundsBeforeMaximize(taskId)).isEqualTo(bounds)
    }

    @Test
    fun removeBoundsBeforeMaximize_returnsNullAfterBoundsRemoved() {
        val taskId = 1
        val bounds = Rect(0, 0, 200, 200)
        repo.saveBoundsBeforeMaximize(taskId, bounds)
        repo.removeBoundsBeforeMaximize(taskId)
        assertThat(repo.removeBoundsBeforeMaximize(taskId)).isNull()
    }

    class TestListener : DesktopModeTaskRepository.ActiveTasksListener {
    class TestListener : DesktopModeTaskRepository.ActiveTasksListener {
        var activeChangesOnDefaultDisplay = 0
        var activeChangesOnDefaultDisplay = 0
        var activeChangesOnSecondaryDisplay = 0
        var activeChangesOnSecondaryDisplay = 0
+88 −10
Original line number Original line Diff line number Diff line
@@ -95,9 +95,10 @@ import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
import org.mockito.kotlin.times
import org.mockito.kotlin.atLeastOnce
import org.mockito.Mockito.`when` as whenever
import org.mockito.kotlin.capture
import org.mockito.quality.Strictness
import org.mockito.quality.Strictness
import org.mockito.Mockito.`when` as whenever


/**
/**
 * Test class for {@link DesktopTasksController}
 * Test class for {@link DesktopTasksController}
@@ -116,13 +117,14 @@ class DesktopTasksControllerTest : ShellTestCase() {
    @Mock lateinit var shellCommandHandler: ShellCommandHandler
    @Mock lateinit var shellCommandHandler: ShellCommandHandler
    @Mock lateinit var shellController: ShellController
    @Mock lateinit var shellController: ShellController
    @Mock lateinit var displayController: DisplayController
    @Mock lateinit var displayController: DisplayController
    @Mock lateinit var displayLayout: DisplayLayout
    @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
    @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
    @Mock lateinit var syncQueue: SyncTransactionQueue
    @Mock lateinit var syncQueue: SyncTransactionQueue
    @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
    @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
    @Mock lateinit var transitions: Transitions
    @Mock lateinit var transitions: Transitions
    @Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
    @Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
    @Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
    @Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
    @Mock lateinit var mToggleResizeDesktopTaskTransitionHandler:
    @Mock lateinit var toggleResizeDesktopTaskTransitionHandler:
            ToggleResizeDesktopTaskTransitionHandler
            ToggleResizeDesktopTaskTransitionHandler
    @Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler
    @Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler
    @Mock lateinit var launchAdjacentController: LaunchAdjacentController
    @Mock lateinit var launchAdjacentController: LaunchAdjacentController
@@ -154,6 +156,10 @@ class DesktopTasksControllerTest : ShellTestCase() {


        whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
        whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
        whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
        whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
        whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
        whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
                (i.arguments.first() as Rect).set(STABLE_BOUNDS)
            }


        controller = createController()
        controller = createController()
        controller.setSplitScreenController(splitScreenController)
        controller.setSplitScreenController(splitScreenController)
@@ -179,7 +185,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
            transitions,
            transitions,
            enterDesktopTransitionHandler,
            enterDesktopTransitionHandler,
            exitDesktopTransitionHandler,
            exitDesktopTransitionHandler,
            mToggleResizeDesktopTaskTransitionHandler,
            toggleResizeDesktopTaskTransitionHandler,
            dragToDesktopTransitionHandler,
            dragToDesktopTransitionHandler,
            desktopModeTaskRepository,
            desktopModeTaskRepository,
            desktopModeLoggerTransitionObserver,
            desktopModeLoggerTransitionObserver,
@@ -936,8 +942,67 @@ class DesktopTasksControllerTest : ShellTestCase() {
        )
        )
    }
    }


    private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
    @Test
        val task = createFreeformTask(displayId)
    fun toggleBounds_togglesToStableBounds() {
        val bounds = Rect(0, 0, 100, 100)
        val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)

        controller.toggleDesktopTaskSize(task)
        // Assert bounds set to stable bounds
        val wct = getLatestToggleResizeDesktopTaskWct()
        assertThat(wct.changes[task.token.asBinder()]?.configuration?.windowConfiguration?.bounds)
                .isEqualTo(STABLE_BOUNDS)
    }

    @Test
    fun toggleBounds_lastBoundsBeforeMaximizeSaved() {
        val bounds = Rect(0, 0, 100, 100)
        val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)

        controller.toggleDesktopTaskSize(task)
        assertThat(desktopModeTaskRepository.removeBoundsBeforeMaximize(task.taskId))
                .isEqualTo(bounds)
    }

    @Test
    fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize() {
        val boundsBeforeMaximize = Rect(0, 0, 100, 100)
        val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)

        // Maximize
        controller.toggleDesktopTaskSize(task)
        task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)

        // Restore
        controller.toggleDesktopTaskSize(task)

        // Assert bounds set to last bounds before maximize
        val wct = getLatestToggleResizeDesktopTaskWct()
        assertThat(wct.changes[task.token.asBinder()]?.configuration?.windowConfiguration?.bounds)
                .isEqualTo(boundsBeforeMaximize)
    }

    @Test
    fun toggleBounds_removesLastBoundsBeforeMaximizeAfterRestoringBounds() {
        val boundsBeforeMaximize = Rect(0, 0, 100, 100)
        val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)

        // Maximize
        controller.toggleDesktopTaskSize(task)
        task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)

        // Restore
        controller.toggleDesktopTaskSize(task)

        // Assert last bounds before maximize removed after use
        assertThat(desktopModeTaskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull()
    }

    private fun setUpFreeformTask(
            displayId: Int = DEFAULT_DISPLAY,
            bounds: Rect? = null
    ): RunningTaskInfo {
        val task = createFreeformTask(displayId, bounds)
        whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
        whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
        desktopModeTaskRepository.addActiveTask(displayId, task.taskId)
        desktopModeTaskRepository.addActiveTask(displayId, task.taskId)
        desktopModeTaskRepository.addOrMoveFreeformTaskToTop(task.taskId)
        desktopModeTaskRepository.addOrMoveFreeformTaskToTop(task.taskId)
@@ -1004,6 +1069,18 @@ class DesktopTasksControllerTest : ShellTestCase() {
        return arg.value
        return arg.value
    }
    }


    private fun getLatestToggleResizeDesktopTaskWct(): WindowContainerTransaction {
        val arg: ArgumentCaptor<WindowContainerTransaction> =
                ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        if (ENABLE_SHELL_TRANSITIONS) {
            verify(toggleResizeDesktopTaskTransitionHandler, atLeastOnce())
                    .startTransition(capture(arg))
        } else {
            verify(shellTaskOrganizer).applyTransaction(capture(arg))
        }
        return arg.value
    }

    private fun getLatestMoveToDesktopWct(): WindowContainerTransaction {
    private fun getLatestMoveToDesktopWct(): WindowContainerTransaction {
        val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        if (ENABLE_SHELL_TRANSITIONS) {
        if (ENABLE_SHELL_TRANSITIONS) {
@@ -1042,6 +1119,7 @@ class DesktopTasksControllerTest : ShellTestCase() {


    companion object {
    companion object {
        const val SECOND_DISPLAY = 2
        const val SECOND_DISPLAY = 2
        private val STABLE_BOUNDS = Rect(0, 0, 1000, 1000)
    }
    }
}
}


+6 −1
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.graphics.Rect
import android.view.Display.DEFAULT_DISPLAY
import android.view.Display.DEFAULT_DISPLAY
import com.android.wm.shell.MockToken
import com.android.wm.shell.MockToken
import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.TestRunningTaskInfoBuilder
@@ -31,13 +32,17 @@ class DesktopTestHelpers {
        /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
        /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
        @JvmStatic
        @JvmStatic
        @JvmOverloads
        @JvmOverloads
        fun createFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
        fun createFreeformTask(
                displayId: Int = DEFAULT_DISPLAY,
                bounds: Rect? = null
        ): RunningTaskInfo {
            return TestRunningTaskInfoBuilder()
            return TestRunningTaskInfoBuilder()
                    .setDisplayId(displayId)
                    .setDisplayId(displayId)
                    .setToken(MockToken().token())
                    .setToken(MockToken().token())
                    .setActivityType(ACTIVITY_TYPE_STANDARD)
                    .setActivityType(ACTIVITY_TYPE_STANDARD)
                    .setWindowingMode(WINDOWING_MODE_FREEFORM)
                    .setWindowingMode(WINDOWING_MODE_FREEFORM)
                    .setLastActiveTime(100)
                    .setLastActiveTime(100)
                    .apply { bounds?.let { setBounds(it) }}
                    .build()
                    .build()
        }
        }