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

Commit d1c7aa54 authored by Qijing Yao's avatar Qijing Yao Committed by Android (Google) Code Review
Browse files

Merge "Ensure drag indicators are cleared on transition abort" into main

parents 1e9f6b80 82185530
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -136,4 +136,16 @@ class MultiDisplayDragMoveIndicatorController(
                }
            }
    }

    /**
     * Disposes all of the indicator surfaces with the [transaction].
     */
    fun disposeAllIndicators(transaction: SurfaceControl.Transaction) {
        dragIndicators.values.forEach { innerIndicatorMap ->
            innerIndicatorMap.values.forEach { indicator ->
                indicator.dispose(transaction)
            }
        }
        dragIndicators.clear()
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -66,4 +66,23 @@ class WindowDragTransitionHandler(
        finishCallback.onTransitionFinished(null)
        return true
    }

    override fun onTransitionConsumed(
        transition: IBinder,
        aborted: Boolean,
        finishTransaction: SurfaceControl.Transaction?,
    ) {
        // Cleans up drag indicators when a transition is consumed or aborted.
        // TODO: b/444066236 - Track pending transitions to clear indicators for the correct task.
        // The taskId is not available in this callback, so we must dispose of all indicators
        // across all displays. This has a known side effect: in the rare edge case that a user is
        // dragging multiple windows simultaneously and one drag transition aborts, the indicators
        // for all dragged windows will be removed. This is an acceptable trade-off due to the low
        // probability of this scenario.
        if (DesktopExperienceFlags.ENABLE_WINDOW_DROP_SMOOTH_TRANSITION.isTrue) {
            finishTransaction?.let {
                multiDisplayDragMoveIndicatorController.disposeAllIndicators(finishTransaction)
            }
        }
    }
}
+51 −0
Original line number Diff line number Diff line
@@ -56,10 +56,13 @@ class MultiDisplayDragMoveIndicatorControllerTest : ShellTestCase() {
    private val shellDesktopState = FakeShellDesktopState(FakeDesktopState())
    private val indicatorSurface0 = mock<MultiDisplayDragMoveIndicatorSurface>()
    private val indicatorSurface1 = mock<MultiDisplayDragMoveIndicatorSurface>()
    private val indicatorSurface2 = mock<MultiDisplayDragMoveIndicatorSurface>()
    private val transaction = mock<SurfaceControl.Transaction>()
    private val transactionSupplier = mock<Supplier<SurfaceControl.Transaction>>()
    private val taskInfo = mock<RunningTaskInfo>()
    private val taskInfo2 = mock<RunningTaskInfo>()
    private val taskLeash = mock<SurfaceControl>()
    private val taskLeash2 = mock<SurfaceControl>()
    private val displayContext0 = mock<Context>()
    private val displayContext1 = mock<Context>()
    private lateinit var spyDisplayLayout0: DisplayLayout
@@ -89,6 +92,7 @@ class MultiDisplayDragMoveIndicatorControllerTest : ShellTestCase() {
        spyDisplayLayout1 = TestDisplay.DISPLAY_1.getSpyDisplayLayout(resources.resources)

        taskInfo.taskId = TASK_ID
        taskInfo2.taskId = TASK_ID_2
        whenever(displayController.getDisplayLayout(0)).thenReturn(spyDisplayLayout0)
        whenever(displayController.getDisplayLayout(1)).thenReturn(spyDisplayLayout1)
        whenever(displayController.getDisplayContext(0)).thenReturn(displayContext0)
@@ -97,6 +101,8 @@ class MultiDisplayDragMoveIndicatorControllerTest : ShellTestCase() {
            .thenReturn(indicatorSurface0)
        whenever(indicatorSurfaceFactory.create(eq(displayContext1), eq(taskLeash)))
            .thenReturn(indicatorSurface1)
        whenever(indicatorSurfaceFactory.create(eq(displayContext0), eq(taskLeash2)))
            .thenReturn(indicatorSurface2)
        whenever(transactionSupplier.get()).thenReturn(transaction)
        shellDesktopState.canBeWindowDropTarget = true
    }
@@ -239,7 +245,52 @@ class MultiDisplayDragMoveIndicatorControllerTest : ShellTestCase() {
        verify(indicatorSurface1).dispose(transaction)
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_WINDOW_DROP_SMOOTH_TRANSITION,
        Flags.FLAG_ENABLE_BLOCK_NON_DESKTOP_DISPLAY_WINDOW_DRAG_BUGFIX,
    )
    fun disposeAllIndicators_verifyAllIndicatorsDisposed() {
        // Drag a first task to create indicators on two displays
        controller.onDragMove(
            RectF(100f, -100f, 200f, 200f), // intersect with display 0 and 1
            currentDisplayId = 1,
            startDisplayId = 0,
            taskLeash,
            taskInfo,
            displayIds = setOf(0, 1),
        ) {
            transaction
        }

        // Drag the second task to create an indicator on one display
        controller.onDragMove(
            RectF(150f, 150f, 250f, 250f), // intersect with display 0 only
            currentDisplayId = 0,
            startDisplayId = 0,
            taskLeash2,
            taskInfo2,
            displayIds = setOf(0, 1),
        ) {
            transaction
        }

        // Verify indicators for both tasks are created
        verify(indicatorSurfaceFactory).create(eq(displayContext0), eq(taskLeash))
        verify(indicatorSurfaceFactory).create(eq(displayContext1), eq(taskLeash))
        verify(indicatorSurfaceFactory).create(eq(displayContext0), eq(taskLeash2))

        // Dispose all indicators
        controller.disposeAllIndicators(transaction)

        // Verify indicators for both tasks are disposed
        verify(indicatorSurface0).dispose(transaction)
        verify(indicatorSurface1).dispose(transaction)
        verify(indicatorSurface2).dispose(transaction)
    }

    companion object {
        private const val TASK_ID = 10
        private const val TASK_ID_2 = 11
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -117,4 +117,12 @@ class WindowDragTransitionHandlerTest : ShellTestCase() {
        verify(mockMultiDisplayDragMoveIndicatorController)
            .onDragEnd(eq(10), eq(mockFinishTransaction))
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_WINDOW_DROP_SMOOTH_TRANSITION)
    fun onTransitionConsumed_disposesIndicators() {
        handler.onTransitionConsumed(mockTransition, false, mockFinishTransaction)
        verify(mockMultiDisplayDragMoveIndicatorController)
            .disposeAllIndicators(mockFinishTransaction)
    }
}