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

Commit 51cffcda authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Ensures the destination display gains global focus

This change fulfills a UX requirement where pressing the "move to next
display" shortcut twice should move the same window.

When DesktopTasksController handles keyboard shortcuts, it moves the
task that has the global focus. This concept was recently introduced
with the display focus feature.

Previously, the display focus remained on the source display even after
a task was moved. This caused the next task on the source display to
gain global focus. This CL rectifies this by adding reorder requests to
the reparent transaction. This ensures the destination display moves to
the top and receives the display focus.

Bug: 381763302
Flag: com.android.window.flags.enable_move_to_next_display_shortcut
Flag: com.android.window.flags.enable_display_focus_in_shell_transitions
Test: DesktopTasksControllerTest
Change-Id: I4270b5a3dc60ab07604dd3b1c6b95f8f9c06ac04
parent 166ad296
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -881,6 +881,12 @@ class DesktopTasksController(
            applyFreeformDisplayChange(wct, task, displayId)
        }
        wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)
        if (Flags.enableDisplayFocusInShellTransitions()) {
            // 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)
        }

        if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
            performDesktopExitCleanupIfNeeded(task.taskId, task.displayId, wct)
+42 −14
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.internal.jank.InteractionJankMonitor
import com.android.window.flags.Flags
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS
import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP
import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT
import com.android.window.flags.Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY
@@ -1703,13 +1704,14 @@ class DesktopTasksControllerTest : ShellTestCase() {

        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
        controller.moveToNextDisplay(task.taskId)
        with(getLatestWct(type = TRANSIT_CHANGE)) {
            assertThat(hierarchyOps).hasSize(1)
            assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
            assertThat(hierarchyOps[0].isReparent).isTrue()
            assertThat(hierarchyOps[0].newParent).isEqualTo(secondDisplayArea.token.asBinder())
            assertThat(hierarchyOps[0].toTop).isTrue()

        val taskChange =
            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
                it.container == task.token.asBinder() && it.isReparent
            }
        assertNotNull(taskChange)
        assertThat(taskChange.newParent).isEqualTo(secondDisplayArea.token.asBinder())
        assertThat(taskChange.toTop).isTrue()
    }

    @Test
@@ -1725,13 +1727,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
        val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
        controller.moveToNextDisplay(task.taskId)

        with(getLatestWct(type = TRANSIT_CHANGE)) {
            assertThat(hierarchyOps).hasSize(1)
            assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
            assertThat(hierarchyOps[0].isReparent).isTrue()
            assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder())
            assertThat(hierarchyOps[0].toTop).isTrue()
        val taskChange =
            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
                it.container == task.token.asBinder() && it.isReparent
            }
        assertNotNull(taskChange)
        assertThat(taskChange.newParent).isEqualTo(defaultDisplayArea.token.asBinder())
        assertThat(taskChange.toTop).isTrue()
    }

    @Test
@@ -1907,6 +1909,32 @@ class DesktopTasksControllerTest : ShellTestCase() {
        }
    }

    @Test
    @EnableFlags(
        FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
        FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
    )
    fun moveToNextDisplay_destinationGainGlobalFocus() {
        // Set up two display ids
        whenever(rootTaskDisplayAreaOrganizer.displayIds)
            .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
        // Create a mock for the target display area: second display
        val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
        whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
            .thenReturn(secondDisplayArea)

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

        val taskChange =
            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
                it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER
            }
        assertNotNull(taskChange)
        assertThat(taskChange.toTop).isTrue()
        assertThat(taskChange.includingParents()).isTrue()
    }

    @Test
    fun getTaskWindowingMode() {
        val fullscreenTask = setUpFullscreenTask()