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

Commit 91abba1a authored by Jorge Gil's avatar Jorge Gil
Browse files

Handle drag-to-deskop of translucent tasks

If a translucent task is dragged to desktop, a visible task behind it
may be included in the transition changes. Instead of throwing an
exception because that state was unexpected, this change layers it at
the bottom during the animation and caches it to be restored in the
drag-cancelled case.

Bug: 317116172
Test: open Chrome fullscreen, open Nearby Share dialog from quick
settings, start drag-to-desktop gesture - verify no crash on both the
commit and cancel cases

Change-Id: Ica05c8c6798c66d3d1e612fc97efcce4bdf63b80
parent 8652ad6e
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -239,7 +239,7 @@ class DragToDesktopTransitionHandler(
                    show(change.leash)
                }
            } else if (TransitionInfo.isIndependent(change, info)) {
                // Root.
                // Root(s).
                when (state) {
                    is TransitionState.FromSplit -> {
                        state.splitRootChange = change
@@ -256,6 +256,9 @@ class DragToDesktopTransitionHandler(
                        }
                    }
                    is TransitionState.FromFullscreen -> {
                        // Most of the time we expect one change/task here, which should be the
                        // same that initiated the drag and that should be layered on top of
                        // everything.
                        if (change.taskInfo?.taskId == state.draggedTaskId) {
                            state.draggedTaskChange = change
                            val bounds = change.endAbsBounds
@@ -265,7 +268,18 @@ class DragToDesktopTransitionHandler(
                                show(change.leash)
                            }
                        } else {
                            throw IllegalStateException("Expected root to be dragged task")
                            // It's possible to see an additional change that isn't the dragged
                            // task when the dragged task is translucent and so the task behind it
                            // is included in the transition since it was visible and is now being
                            // occluded by the Home task. Just layer it at the bottom and save it
                            // in case we need to restore order if the drag is cancelled.
                            state.otherRootChanges.add(change)
                            val bounds = change.endAbsBounds
                            startTransaction.apply {
                                setLayer(change.leash, appLayers - i)
                                setWindowCrop(change.leash, bounds.width(), bounds.height())
                                show(change.leash)
                            }
                        }
                    }
                }
@@ -515,8 +529,18 @@ class DragToDesktopTransitionHandler(
        val wct = WindowContainerTransaction()
        when (state) {
            is TransitionState.FromFullscreen -> {
                // There may have been tasks sent behind home that are not the dragged task (like
                // when the dragged task is translucent and that makes the task behind it visible).
                // Restore the order of those first.
                state.otherRootChanges.mapNotNull { it.container }.forEach { wc ->
                    // TODO(b/322852244): investigate why even though these "other" tasks are
                    //  reordered in front of home and behind the translucent dragged task, its
                    //  surface is not visible on screen.
                    wct.reorder(wc, true /* toTop */)
                }
                val wc = state.draggedTaskChange?.container
                        ?: error("Dragged task should be non-null before cancelling")
                // Then the dragged task a the very top.
                wct.reorder(wc, true /* toTop */)
            }
            is TransitionState.FromSplit -> {
@@ -574,6 +598,7 @@ class DragToDesktopTransitionHandler(
                override var draggedTaskChange: Change? = null,
                override var cancelled: Boolean = false,
                override var startAborted: Boolean = false,
                var otherRootChanges: MutableList<Change> = mutableListOf()
        ) : TransitionState()
        data class FromSplit(
                override val draggedTaskId: Int,
+12 −1
Original line number Diff line number Diff line
@@ -843,7 +843,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

    @Nullable
    private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
        if (mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible()) {
        final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
        if (focusedDecor == null) {
            return null;
        }
        final boolean splitScreenVisible = mSplitScreenController != null
                && mSplitScreenController.isSplitScreenVisible();
        // It's possible that split tasks are visible but neither is focused, such as when there's
        // a fullscreen translucent window on top of them. In that case, the relevant decor should
        // just be that translucent focused window.
        final boolean focusedTaskInSplit = mSplitScreenController != null
                && mSplitScreenController.isTaskInSplitScreen(focusedDecor.mTaskInfo.taskId);
        if (splitScreenVisible && focusedTaskInSplit) {
            // We can't look at focused task here as only one task will have focus.
            DesktopModeWindowDecoration splitTaskDecor = getSplitScreenDecor(ev);
            return splitTaskDecor == null ? getFocusedDecor() : splitTaskDecor;