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

Commit 0e1e0e73 authored by Jorge Gil's avatar Jorge Gil
Browse files

[37/N] Desks: Unminimize when moving task to front

moveTaskToFront() may be used for minimized tasks. When multiple
desktops is enabled, these need to be reparented from the minimization
container to the desk container, otherwise they will only go to the
front of the minimized tasks, but remaing behind non-minimized tasks and
the Home/DesktopWallpaper.

Flag: com.android.window.flags.enable_multiple_desktops_backend
Bug: 391485148
Bug: 393978427
Test: Open 2 desktop apps, minimize one, unminimize it from the taskbar
- verify it becomes visible in front of all tasks

Change-Id: Idcb266a6215ef82efbed6f5d003335b26216361d
parent 842c71c6
Loading
Loading
Loading
Loading
+34 −8
Original line number Diff line number Diff line
@@ -962,10 +962,13 @@ class DesktopTasksController(
                .apply { launchWindowingMode = WINDOWING_MODE_FREEFORM }
                .toBundle(),
        )
        val deskId = taskRepository.getDeskIdForTask(taskId) ?: getDefaultDeskId(DEFAULT_DISPLAY)
        startLaunchTransition(
            TRANSIT_OPEN,
            wct,
            taskId,
            deskId = deskId,
            displayId = DEFAULT_DISPLAY,
            remoteTransition = remoteTransition,
            unminimizeReason = unminimizeReason,
        )
@@ -983,19 +986,26 @@ class DesktopTasksController(
        remoteTransition: RemoteTransition? = null,
        unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
    ) {
        logV("moveTaskToFront taskId=%s", taskInfo.taskId)
        val deskId =
            taskRepository.getDeskIdForTask(taskInfo.taskId) ?: getDefaultDeskId(taskInfo.displayId)
        logV("moveTaskToFront taskId=%s deskId=%s", taskInfo.taskId, deskId)
        // If a task is tiled, another task should be brought to foreground with it so let
        // tiling controller handle the request.
        if (snapEventHandler.moveTaskToFrontIfTiled(taskInfo)) {
            return
        }
        val wct = WindowContainerTransaction()
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            desksOrganizer.reorderTaskToFront(wct, deskId, taskInfo)
        } else {
            wct.reorder(taskInfo.token, /* onTop= */ true, /* includingParents= */ true)
        }
        startLaunchTransition(
            transitionType = TRANSIT_TO_FRONT,
            wct = wct,
            launchingTaskId = taskInfo.taskId,
            remoteTransition = remoteTransition,
            deskId = deskId,
            displayId = taskInfo.displayId,
            unminimizeReason = unminimizeReason,
        )
@@ -1007,12 +1017,10 @@ class DesktopTasksController(
        wct: WindowContainerTransaction,
        launchingTaskId: Int?,
        remoteTransition: RemoteTransition? = null,
        displayId: Int = DEFAULT_DISPLAY,
        deskId: Int,
        displayId: Int,
        unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
    ): IBinder {
        val deskId =
            launchingTaskId?.let { taskId -> taskRepository.getDeskIdForTask(taskId) }
                ?: getDefaultDeskId(displayId)
        logV(
            "startLaunchTransition type=%s launchingTaskId=%d deskId=%d displayId=%d",
            WindowManager.transitTypeToString(transitionType),
@@ -1162,7 +1170,14 @@ class DesktopTasksController(
            }

        wct.sendPendingIntent(pendingIntent, intent, ops.toBundle())
        startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
        val deskId = getDefaultDeskId(displayId)
        startLaunchTransition(
            TRANSIT_OPEN,
            wct,
            launchingTaskId = null,
            deskId = deskId,
            displayId = displayId,
        )
    }

    /**
@@ -2151,10 +2166,14 @@ class DesktopTasksController(
            WINDOWING_MODE_FREEFORM -> {
                val wct = WindowContainerTransaction()
                wct.sendPendingIntent(launchIntent, fillIn, options.toBundle())
                val deskId =
                    taskRepository.getDeskIdForTask(callingTaskInfo.taskId)
                        ?: getDefaultDeskId(callingTaskInfo.displayId)
                startLaunchTransition(
                    transitionType = TRANSIT_OPEN,
                    wct = wct,
                    launchingTaskId = null,
                    deskId = deskId,
                    displayId = callingTaskInfo.displayId,
                )
            }
@@ -3405,7 +3424,14 @@ class DesktopTasksController(
        if (windowingMode == WINDOWING_MODE_FREEFORM) {
            if (DesktopModeFlags.ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX.isTrue()) {
                // TODO b/376389593: Use a custom tab tearing transition/animation
                startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
                val deskId = getDefaultDeskId(DEFAULT_DISPLAY)
                startLaunchTransition(
                    TRANSIT_OPEN,
                    wct,
                    launchingTaskId = null,
                    deskId = deskId,
                    displayId = DEFAULT_DISPLAY,
                )
            } else {
                desktopModeDragAndDropTransitionHandler.handleDropEvent(wct)
            }
+7 −0
Original line number Diff line number Diff line
@@ -40,6 +40,13 @@ interface DesksOrganizer {
        task: ActivityManager.RunningTaskInfo,
    )

    /** Reorders a desk's task to the front. */
    fun reorderTaskToFront(
        wct: WindowContainerTransaction,
        deskId: Int,
        task: ActivityManager.RunningTaskInfo,
    )

    /** Minimizes the given task of the given deskId. */
    fun minimizeTask(
        wct: WindowContainerTransaction,
+23 −0
Original line number Diff line number Diff line
@@ -110,6 +110,29 @@ class RootTaskDesksOrganizer(
        wct.reparent(task.token, root.taskInfo.token, /* onTop= */ true)
    }

    override fun reorderTaskToFront(
        wct: WindowContainerTransaction,
        deskId: Int,
        task: RunningTaskInfo,
    ) {
        logV("reorderTaskToFront task=${task.taskId} desk=$deskId")
        val root = deskRootsByDeskId[deskId] ?: error("Root not found for desk: $deskId")
        if (task.taskId in root.children) {
            wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
            return
        }
        val minimizationRoot =
            checkNotNull(deskMinimizationRootsByDeskId[deskId]) {
                "Minimization root not found for desk: $deskId"
            }
        if (task.taskId in minimizationRoot.children) {
            unminimizeTask(wct, deskId, task)
            wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
            return
        }
        logE("Attempted to reorder task=${task.taskId} in desk=$deskId but it was not a child")
    }

    override fun minimizeTask(wct: WindowContainerTransaction, deskId: Int, task: RunningTaskInfo) {
        logV("minimizeTask task=${task.taskId} desk=$deskId")
        val deskRoot =
+73 −5
Original line number Diff line number Diff line
@@ -2364,6 +2364,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun moveTaskToFront_postsWctWithReorderOp() {
        val task1 = setUpFreeformTask()
        setUpFreeformTask()
@@ -2385,6 +2386,27 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        wct.assertReorderAt(index = 0, task1)
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun moveTaskToFront_reordersToFront() {
        val task1 = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
        setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
        whenever(
                desktopMixedTransitionHandler.startLaunchTransition(
                    eq(TRANSIT_TO_FRONT),
                    any(),
                    eq(task1.taskId),
                    anyOrNull(),
                    anyOrNull(),
                )
            )
            .thenReturn(Binder())

        controller.moveTaskToFront(task1, remoteTransition = null)

        verify(desksOrganizer).reorderTaskToFront(any(), eq(0), eq(task1))
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun moveTaskToFront_bringsTasksOverLimit_multiDesksDisabled_minimizesBackTask() {
@@ -5820,7 +5842,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
    fun openInstance_fromFreeformAddsNewWindow() {
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun openInstance_fromFreeformAddsNewWindow_multiDesksDisabled() {
        setUpLandscapeDisplay()
        val task = setUpFreeformTask()
        val taskToRequest = setUpFreeformTask()
@@ -5834,7 +5857,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
                )
            )
            .thenReturn(Binder())

        runOpenInstance(task, taskToRequest.taskId)

        verify(desktopMixedTransitionHandler)
            .startLaunchTransition(anyInt(), any(), anyInt(), anyOrNull(), anyOrNull())
        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
@@ -5842,6 +5867,33 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        wct.assertReorderAt(index = 0, taskToRequest)
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES,
        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
    )
    fun openInstance_fromFreeformAddsNewWindow_multiDesksEnabled() {
        setUpLandscapeDisplay()
        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
        val taskToRequest = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
        whenever(
                desktopMixedTransitionHandler.startLaunchTransition(
                    eq(TRANSIT_TO_FRONT),
                    any(),
                    eq(taskToRequest.taskId),
                    anyOrNull(),
                    anyOrNull(),
                )
            )
            .thenReturn(Binder())

        runOpenInstance(task, taskToRequest.taskId)

        verify(desktopMixedTransitionHandler)
            .startLaunchTransition(anyInt(), any(), anyInt(), anyOrNull(), anyOrNull())
        verify(desksOrganizer).reorderTaskToFront(any(), eq(0), eq(taskToRequest))
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
@@ -6868,7 +6920,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
    )
    fun startLaunchTransition_desktopNotShowing_movesWallpaperToFront() {
        val launchingTask = createFreeformTask()
        val launchingTask = createFreeformTask(displayId = DEFAULT_DISPLAY)
        val wct = WindowContainerTransaction()
        wct.reorder(launchingTask.token, /* onTop= */ true)
        whenever(
@@ -6882,7 +6934,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            )
            .thenReturn(Binder())

        controller.startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
        controller.startLaunchTransition(
            transitionType = TRANSIT_OPEN,
            wct = wct,
            launchingTaskId = null,
            deskId = 0,
            displayId = DEFAULT_DISPLAY,
        )

        val latestWct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
        val launchingTaskReorderIndex = latestWct.indexOfReorder(launchingTask, toTop = true)
@@ -6906,6 +6964,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            transitionType = TRANSIT_OPEN,
            wct = WindowContainerTransaction(),
            launchingTaskId = null,
            deskId = 0,
            displayId = DEFAULT_DISPLAY,
        )

        verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(any())
@@ -6941,6 +7001,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            transitionType = TRANSIT_OPEN,
            wct = wct,
            launchingTaskId = launchingTask.taskId,
            deskId = inactiveDesk,
            displayId = DEFAULT_DISPLAY,
        )

        verify(desksOrganizer).activateDesk(any(), eq(inactiveDesk))
@@ -6972,8 +7034,14 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            )
            .thenReturn(Binder())

        setUpFreeformTask()
        controller.startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
        setUpFreeformTask(deskId = 0, displayId = DEFAULT_DISPLAY)
        controller.startLaunchTransition(
            transitionType = TRANSIT_OPEN,
            wct = wct,
            launchingTaskId = null,
            deskId = 0,
            displayId = DEFAULT_DISPLAY,
        )

        val latestWct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
        assertNull(latestWct.hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() })
+63 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.Change
import android.window.WindowContainerTransaction.HierarchyOp
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTaskOrganizer
@@ -544,6 +545,68 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
        assertThat(wct.hasUnminimizationHops(desk, task.token)).isFalse()
    }

    @Test
    fun reorderTaskToFront() {
        val desk = createDesk()
        val task = createFreeformTask().apply { parentTaskId = desk.deskRoot.deskId }
        val wct = WindowContainerTransaction()
        organizer.onTaskAppeared(task, SurfaceControl())

        organizer.reorderTaskToFront(wct, desk.deskRoot.deskId, task)

        assertThat(
                wct.hierarchyOps.singleOrNull { hop ->
                    hop.container == task.token.asBinder() &&
                        hop.type == HIERARCHY_OP_TYPE_REORDER &&
                        hop.toTop &&
                        hop.includingParents()
                }
            )
            .isNotNull()
    }

    @Test
    fun reorderTaskToFront_notInDesk_noOp() {
        val desk = createDesk()
        val task = createFreeformTask()
        val wct = WindowContainerTransaction()

        organizer.reorderTaskToFront(wct, desk.deskRoot.deskId, task)

        assertThat(
                wct.hierarchyOps.singleOrNull { hop ->
                    hop.container == task.token.asBinder() &&
                        hop.type == HIERARCHY_OP_TYPE_REORDER &&
                        hop.toTop &&
                        hop.includingParents()
                }
            )
            .isNull()
    }

    @Test
    fun reorderTaskToFront_minimized_unminimizesAndReorders() {
        val desk = createDesk()
        val task = createFreeformTask().apply { parentTaskId = desk.deskRoot.deskId }
        val wct = WindowContainerTransaction()
        organizer.onTaskAppeared(task, SurfaceControl())
        task.parentTaskId = desk.minimizationRoot.rootId
        organizer.onTaskInfoChanged(task)

        organizer.reorderTaskToFront(wct, desk.deskRoot.deskId, task)

        assertThat(wct.hasUnminimizationHops(desk, task.token)).isTrue()
        assertThat(
                wct.hierarchyOps.singleOrNull { hop ->
                    hop.container == task.token.asBinder() &&
                        hop.type == HIERARCHY_OP_TYPE_REORDER &&
                        hop.toTop &&
                        hop.includingParents()
                }
            )
            .isNotNull()
    }

    private data class DeskRoots(
        val deskRoot: DeskRoot,
        val minimizationRoot: DeskMinimizationRoot,