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

Commit f6dae5ef authored by Jorge Gil's avatar Jorge Gil
Browse files

Desks: Do not assume moveToFront means moving to desk

DesktopTasksController#moveToFront may be used on fullscreen or split
tasks that aren't focused (on display or globally) to bring them to the
front when the App Handle is touched. Do not assume that means they need
to be moved into a default desk and that a desk needs to be deactivated.

Flag: com.android.window.flags.enable_multiple_desktops_backend
Bug: 410180972
Test: open task, make it unfocused, touch the app handle - no crash
Change-Id: I18ce831984d6e869f89af5ba5d2db2ae97a16f13
parent 7a79cec7
Loading
Loading
Loading
Loading
+38 −18
Original line number Diff line number Diff line
@@ -1328,10 +1328,7 @@ class DesktopTasksController(
        remoteTransition: RemoteTransition? = null,
        unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
    ) {
        val deskId =
            taskRepository.getDeskIdForTask(taskInfo.taskId)
                ?: getOrCreateDefaultDeskId(taskInfo.displayId)
                ?: return
        val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
        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.
@@ -1339,10 +1336,12 @@ class DesktopTasksController(
            return
        }
        val wct = WindowContainerTransaction()
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            desksOrganizer.reorderTaskToFront(wct, deskId, taskInfo)
        } else {
        if (deskId == null || !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            // Not a desktop task, just move to the front.
            wct.reorder(taskInfo.token, /* onTop= */ true, /* includingParents= */ true)
        } else {
            // A desktop task with multiple desks enabled, reorder it within its desk.
            desksOrganizer.reorderTaskToFront(wct, deskId, taskInfo)
        }
        startLaunchTransition(
            transitionType = TRANSIT_TO_FRONT,
@@ -1355,13 +1354,26 @@ class DesktopTasksController(
        )
    }

    /**
     * Starts a launch transition with [transitionType] using [wct].
     *
     * @param transitionType the type of transition to start.
     * @param wct the wct to use in the transition, which may already container changes.
     * @param launchingTaskId the id of task launching, may be null if starting the task through an
     *   intent in the [wct].
     * @param remoteTransition the remote transition associated with this transition start.
     * @param deskId may be null if the launching task isn't launching into a desk, such as when
     *   fullscreen or split tasks are just moved to front.
     * @param displayId the display in which the launch is happening.
     * @param unminimizeReason the reason to unminimize.
     */
    @VisibleForTesting
    fun startLaunchTransition(
        transitionType: Int,
        wct: WindowContainerTransaction,
        launchingTaskId: Int?,
        remoteTransition: RemoteTransition? = null,
        deskId: Int,
        deskId: Int?,
        displayId: Int,
        unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
    ): IBinder {
@@ -1376,12 +1388,14 @@ class DesktopTasksController(
        var launchTransaction = wct
        // TODO: b/32994943 - remove dead code when cleaning up task_limit_separate_transition flag
        val taskIdToMinimize =
            deskId?.let {
                addAndGetMinimizeChanges(
                deskId,
                launchTransaction,
                    deskId = it,
                    wct = launchTransaction,
                    newTaskId = launchingTaskId,
                    launchingNewIntent = launchingTaskId == null,
                )
            }
        val exitImmersiveResult =
            desktopImmersiveController.exitImmersiveIfApplicable(
                wct = launchTransaction,
@@ -1392,11 +1406,11 @@ class DesktopTasksController(
        var activationRunOnTransitStart: RunOnTransitStart? = null
        val shouldActivateDesk =
            when {
                deskId == null -> false
                DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ->
                    !taskRepository.isDeskActive(deskId)
                DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue -> {
                DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue ->
                    !isAnyDeskActive(displayId)
                }
                else -> false
            }
        if (shouldActivateDesk) {
@@ -1404,7 +1418,11 @@ class DesktopTasksController(
            // TODO: b/391485148 - pass in the launching task here to apply task-limit policy,
            //  but make sure to not do it twice since it is also done at the start of this
            //  function.
            activationRunOnTransitStart = addDeskActivationChanges(deskId, activateDeskWct)
            activationRunOnTransitStart =
                addDeskActivationChanges(
                    deskId = checkNotNull(deskId) { "Desk id must be non-null when activating" },
                    wct = activateDeskWct,
                )
            // Desk activation must be handled before app launch-related transactions.
            activateDeskWct.merge(launchTransaction, /* transfer= */ true)
            launchTransaction = activateDeskWct
@@ -1442,7 +1460,9 @@ class DesktopTasksController(
        if (taskIdToMinimize != null) {
            addPendingMinimizeTransition(t, taskIdToMinimize, MinimizeReason.TASK_LIMIT)
        }
        if (deskId != null) {
            addPendingTaskLimitTransition(t, deskId, launchingTaskId)
        }
        if (launchingTaskId != null && taskRepository.isMinimizedTask(launchingTaskId)) {
            addPendingUnminimizeTransition(t, displayId, launchingTaskId, unminimizeReason)
        }
+6 −0
Original line number Diff line number Diff line
@@ -1252,6 +1252,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,

        private void moveTaskToFront(RunningTaskInfo taskInfo) {
            if (!mFocusTransitionObserver.hasGlobalFocus(taskInfo)) {
                ProtoLog.d(WM_SHELL_DESKTOP_MODE,
                        "%s: task#%d in display#%d does not have global focus, moving to front "
                                + "globallyFocusedTaskId=%d globallyFocusedDisplayId=%d",
                        TAG, taskInfo.taskId, taskInfo.displayId,
                        mFocusTransitionObserver.getGloballyFocusedTaskId(),
                        mFocusTransitionObserver.getGloballyFocusedDisplayId());
                mDesktopModeUiEventLogger.log(taskInfo,
                        DesktopUiEventEnum.DESKTOP_WINDOW_HEADER_TAP_TO_REFOCUS);
                mDesktopTasksController.moveTaskToFront(taskInfo);
+57 −5
Original line number Diff line number Diff line
@@ -1516,6 +1516,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING)
    fun launchIntent_taskInDesktopMode_onSecondaryDisplay_transitionStarted() {
        setUpLandscapeDisplay()
        taskRepository.addDesk(SECOND_DISPLAY, deskId = 2)
@@ -2709,7 +2710,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun moveTaskToFront_reordersToFront() {
    fun moveTaskToFront_desktopTask_reordersToFront() {
        val task1 = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
        setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
        whenever(
@@ -2728,6 +2729,50 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        verify(desksOrganizer).reorderTaskToFront(any(), eq(0), eq(task1))
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun moveTaskToFront_nonDesktopTask_reordersToFront() {
        val task = setUpFullscreenTask(displayId = DEFAULT_DISPLAY)
        whenever(
                desktopMixedTransitionHandler.startLaunchTransition(
                    eq(TRANSIT_TO_FRONT),
                    any(),
                    eq(task.taskId),
                    anyOrNull(),
                    anyOrNull(),
                )
            )
            .thenReturn(Binder())

        controller.moveTaskToFront(task, remoteTransition = null)

        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
        assertNotNull(wct)
        wct.assertReorder(task = task, toTop = true, includingParents = true)
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun moveTaskToFront_nonDesktopTask_doesNotActivateDesk() {
        val task = setUpFullscreenTask(displayId = DEFAULT_DISPLAY)
        whenever(
                desktopMixedTransitionHandler.startLaunchTransition(
                    eq(TRANSIT_TO_FRONT),
                    any(),
                    eq(task.taskId),
                    anyOrNull(),
                    anyOrNull(),
                )
            )
            .thenReturn(Binder())

        controller.moveTaskToFront(task, remoteTransition = null)

        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
        assertNotNull(wct)
        verify(desksOrganizer, never()).activateDesk(eq(wct), any())
    }

    @Test
    @DisableFlags(
        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
@@ -8471,6 +8516,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
        Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING,
    )
    fun startLaunchTransition_desktopNotShowing_movesWallpaperToFront() {
        taskRepository.setDeskInactive(deskId = 0)
@@ -9149,11 +9195,15 @@ private fun WindowContainerTransaction.indexOfReorder(
    return indexOfReorder(task.token, toTop)
}

private class ReorderPredicate(val token: WindowContainerToken, val toTop: Boolean? = null) :
    ((WindowContainerTransaction.HierarchyOp) -> Boolean) {
private class ReorderPredicate(
    val token: WindowContainerToken,
    val toTop: Boolean? = null,
    val includingParents: Boolean? = null,
) : ((WindowContainerTransaction.HierarchyOp) -> Boolean) {
    override fun invoke(hop: WindowContainerTransaction.HierarchyOp): Boolean =
        hop.type == HIERARCHY_OP_TYPE_REORDER &&
            (toTop == null || hop.toTop == toTop) &&
            (includingParents == null || hop.includingParents() == includingParents) &&
            hop.container == token.asBinder()
}

@@ -9172,15 +9222,17 @@ private class ReparentPredicate(
private fun WindowContainerTransaction.assertReorder(
    task: RunningTaskInfo,
    toTop: Boolean? = null,
    includingParents: Boolean? = null,
) {
    assertReorder(task.token, toTop)
    assertReorder(task.token, toTop, includingParents)
}

private fun WindowContainerTransaction.assertReorder(
    token: WindowContainerToken,
    toTop: Boolean? = null,
    includingParents: Boolean? = null,
) {
    assertHop(ReorderPredicate(token, toTop))
    assertHop(ReorderPredicate(token, toTop, includingParents))
}

private fun WindowContainerTransaction.assertReorderAt(