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

Commit 986e9143 authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Hide the all apps UI when moving the last task from a display

Previously, moving the final task away from a display after launching it
from the all apps UI unintentionally revealed the all apps UI again.
This occurred because the UI remained active behind the desktop
wallpaper. Removing the last task exposed it.

For other scenarios where the launcher becomes visible, an Intent is
sent to hide the all apps UI. However, this was disabled for
moveToDisplay to prevent the source display from incorrectly gaining
focus instead of the destination.

This change removes that workaround, allowing the launcher to hide the
all apps UI. Additionally, the wct.reorder(/* includingParents= */ true)
call is moved after performDesktopExitCleanupIfNeeded (which sends the
Intent). This ensures the destination display receives focus after the
Intent changes the focus to the source.

Bug: 410463040
Test: DesktopTasksControllerTest
Test: run CD smoke tests
Flag: com.android.window.flags.enable_display_focus_in_shell_transitions
Flag: com.android.window.flags.enable_move_to_next_display_shortcut
Change-Id: I2fa9bb284596cbc5a7b9d3cd8149df42cb37c3f0
parent cb399230
Loading
Loading
Loading
Loading
+11 −14
Original line number Diff line number Diff line
@@ -1724,13 +1724,6 @@ class DesktopTasksController(

        val activationRunnable = addDeskActivationChanges(destinationDeskId, wct, task)

        if (DesktopExperienceFlags.ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS.isTrue) {
            // Bring the destination display to top with includingParents=true, so that the
            // destination display gains the display focus, which makes the top task in the display
            // gains the global focus.
            wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
        }

        val sourceDisplayId = task.displayId
        val sourceDeskId = taskRepository.getDeskIdForTask(task.taskId)
        val shouldExitDesktopIfNeeded =
@@ -1744,15 +1737,20 @@ class DesktopTasksController(
                    displayId = sourceDisplayId,
                    wct = wct,
                    forceToFullscreen = false,
                    // TODO: b/371096166 - Temporary turing home relaunch off to prevent home
                    // stealing
                    // display focus. Remove shouldEndUpAtHome = false when home focus handling
                    // with connected display is implemented in wm core.
                    shouldEndUpAtHome = false,
                )
            } else {
                null
            }
        if (DesktopExperienceFlags.ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS.isTrue) {
            // Bring the destination display to top with includingParents=true, so that the
            // destination display gains the display focus, which makes the top task in the display
            // gains the global focus. This must be done after performDesktopExitCleanupIfNeeded.
            // The method launches Launcher on the source display when the last task is moved, which
            // brings the source display to the top. Calling reorder after
            // performDesktopExitCleanupIfNeeded ensures that the destination display becomes the
            // top (focused) display.
            wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
        }
        val transition =
            transitions.startTransition(
                TRANSIT_CHANGE,
@@ -2361,7 +2359,6 @@ class DesktopTasksController(
        displayId: Int,
        wct: WindowContainerTransaction,
        forceToFullscreen: Boolean,
        shouldEndUpAtHome: Boolean = true,
    ): RunOnTransitStart? {
        if (!willExitDesktop(taskId, displayId, forceToFullscreen)) {
            return null
@@ -2373,7 +2370,7 @@ class DesktopTasksController(
            deskId = deskId,
            displayId = displayId,
            willExitDesktop = true,
            shouldEndUpAtHome = shouldEndUpAtHome,
            shouldEndUpAtHome = true,
        )
    }

+47 −12
Original line number Diff line number Diff line
@@ -3424,18 +3424,19 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
        controller.moveToNextDisplay(task.taskId)

        val taskChange =
        val wct =
            getLatestWct(
                type = TRANSIT_CHANGE,
                handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
            )
                .hierarchyOps
                .find {
                    it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER
                }
        assertNotNull(taskChange)
        assertThat(taskChange.toTop).isTrue()
        assertThat(taskChange.includingParents()).isTrue()
        wct.assertReorderAt(
            // Reorder should be the last change so that other hierarchyOps do not change the
            // display focus after moving the destination display top.
            index = wct.hierarchyOps.size - 1,
            task,
            toTop = true,
            includingParents = true,
        )
    }

    @Test
@@ -3642,6 +3643,29 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            )
    }

    @Test
    @EnableFlags(
        FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
        FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
    )
    fun moveToNextDisplay_resetLauncherOnSourceDisplay() {
        taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
        // Set up two display ids
        whenever(rootTaskDisplayAreaOrganizer.displayIds)
            .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))

        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
        controller.moveToNextDisplay(task.taskId)

        val wct =
            getLatestWct(
                type = TRANSIT_CHANGE,
                handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
            )
        wct.assertPendingIntent(launchHomeIntent(DEFAULT_DISPLAY))
        wct.assertPendingIntentActivityOptionsLaunchDisplayId(DEFAULT_DISPLAY)
    }

    @Test
    fun moveToNextDisplay_movingToDesktop_sendsTaskbarRoundingUpdate() {
        val transition = Binder()
@@ -9800,12 +9824,14 @@ private fun WindowContainerTransaction.assertReorderAt(
    index: Int,
    task: RunningTaskInfo,
    toTop: Boolean? = null,
    includingParents: Boolean? = null,
) {
    assertIndexInBounds(index)
    val op = hierarchyOps[index]
    assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REORDER)
    assertThat(op.container).isEqualTo(task.token.asBinder())
    toTop?.let { assertThat(op.toTop).isEqualTo(it) }
    includingParents?.let { assertThat(op.includingParents()).isEqualTo(it) }
}

private fun WindowContainerTransaction.assertReorderAt(
@@ -9869,7 +9895,8 @@ private fun WindowContainerTransaction.hasRemoveAt(index: Int, token: WindowCont
private fun WindowContainerTransaction.assertPendingIntent(intent: Intent) {
    assertHop { hop ->
        hop.type == HIERARCHY_OP_TYPE_PENDING_INTENT &&
            hop.pendingIntent?.intent?.component == intent.component
            hop.pendingIntent?.intent?.component == intent.component &&
            hop.pendingIntent?.intent?.categories == intent.categories
    }
}

@@ -9888,6 +9915,14 @@ private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent:
    assertThat(op.pendingIntent?.intent?.categories).isEqualTo(intent.categories)
}

private fun WindowContainerTransaction.assertPendingIntentActivityOptionsLaunchDisplayId(
    displayId: Int
) {
    assertHop { hop ->
        hop.launchOptions != null && ActivityOptions(hop.launchOptions).launchDisplayId == displayId
    }
}

private fun WindowContainerTransaction.assertPendingIntentActivityOptionsLaunchDisplayIdAt(
    index: Int,
    displayId: Int,