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

Commit 11ecf4e2 authored by Eric Lin's avatar Eric Lin
Browse files

Fix bubble relaunch by deferring TaskView animation.

When launching a recycled task into a TaskView that lacks a surface,
such as reopening a collapsed bubble via a trampoline activity in
desktop mode, the transition could be initiated before the TaskView was
ready. TaskViewTransitions would handle the animation by hiding the
task.

This change introduces a readiness check to ensure that all TaskViews
involved in a transition are prepared for animation. A TaskView is
considered not ready if its surface has been destroyed. If any TaskView
is not ready, TaskViewTransitions now returns false from
startAnimation(), deferring the transition to another handler. It allows
LaunchNewTaskBubbleForExistingTransition in DefaultMixedHandler to
correctly process the transition, ensuring the bubble reopens as
expected.

Bug: 432606505
Flag: EXEMPT BUGFIX
Test: atest WMShellUnitTests:TaskViewTest
Test: atest WMShellUnitTests:TaskViewTransitionStartAnimationTest
Test: atest WMShellUnitTests:BubbleTransitionsTest
Change-Id: Ia1d71b6f55bd1fd7f80a72dd9b34702e10cedd24
parent 67b6b390
Loading
Loading
Loading
Loading
+29 −8
Original line number Diff line number Diff line
@@ -816,6 +816,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
        }

        // Prepare taskViews for animation
        boolean isReadyForAnimation = true;
        for (int i = 0; i < taskViews.size(); ++i) {
            final TransitionInfo.Change task = taskViews.get(i);
            final ActivityManager.RunningTaskInfo taskInfo = task.getTaskInfo();
@@ -849,11 +850,13 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
                        // The task is being moved into taskView, so it is still "new" from
                        // TaskView's perspective (e.g. task being moved into a bubble)
                        stillNeedsMatchingLaunch = false;
                        prepareOpenAnimation(pending.mTaskView, true /* isNewInTaskView */,
                                startTransaction, finishTransaction, taskInfo, leash, wct);
                        isReadyForAnimation &= prepareOpenAnimation(pending.mTaskView,
                                true /* isNewInTaskView */, startTransaction, finishTransaction,
                                taskInfo, leash, wct);
                    } else {
                        prepareOpenAnimation(infoTv, false /* isNewInTaskView */,
                                startTransaction, finishTransaction, taskInfo, leash, wct);
                        isReadyForAnimation &= prepareOpenAnimation(infoTv,
                                false /* isNewInTaskView */, startTransaction, finishTransaction,
                                taskInfo, leash, wct);
                    }
                    break;
                case TRANSIT_CHANGE:
@@ -879,6 +882,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
                    break;
            }
        }
        isReadyForAnimation &= (wct == null || taskViews.size() == info.getChanges().size());

        // Check for unexpected changes in transition
        for (int i = 0; i < alienChanges.size(); ++i) {
@@ -907,8 +911,10 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
                    + "cleaning up the task view");
            // Didn't find a task so the task must have never launched
            pending.mTaskView.setTaskNotFound();
        } else if (wct == null && pending == null && taskViews.size() != info.getChanges().size()) {
            // Just some house-keeping, let another handler animate.
        } else if (pending == null && !isReadyForAnimation) {
            // Animation could not be fully prepared. The surface for one or more TaskViews was
            // destroyed before the animation could start, let another handler animate.
            Slog.w(TAG, "Animation not ready for all TaskViews, deferring to another handler.");
            return false;
        }
        if (changingDisplayId > -1) {
@@ -1092,8 +1098,21 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
        return true;
    }

    /**
     * Prepares the TaskView for an open animation.
     *
     * @param taskView the {@link TaskViewTaskController} for the TaskView being opened.
     * @param newTask whether the task is considered new within this {@link TaskView}.
     * @param startTransaction the transaction to apply before the animation starts.
     * @param finishTransaction the transaction to apply after the animation finishes.
     * @param taskInfo information about the running task to animate.
     * @param leash the surface leash representing the task's surface.
     * @param wct a {@link WindowContainerTransaction} to apply changes.
     * @return {@code true} if the TaskView's surface is created and ready for animation,
     * {@code false} if the surface was destroyed and the animation should be deferred.
     */
    @VisibleForTesting
    public void prepareOpenAnimation(TaskViewTaskController taskView,
    public boolean prepareOpenAnimation(TaskViewTaskController taskView,
            final boolean newTask,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
@@ -1102,7 +1121,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
        final Rect boundsOnScreen = taskView.prepareOpen(taskInfo, leash);
        ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "Transitions.prepareOpenAnimation(): taskView=%d "
                        + "newTask=%b bounds=%s", taskView.hashCode(), newTask, boundsOnScreen);
        if (boundsOnScreen != null) {
        final boolean isSurfaceCreated = boundsOnScreen != null;
        if (isSurfaceCreated) {
            updateBounds(taskView, boundsOnScreen, startTransaction, finishTransaction, taskInfo,
                    leash, wct);
        } else {
@@ -1126,6 +1146,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
        wct.setTaskTrimmableFromRecents(taskInfo.token, false /* isTrimmableFromRecents */);

        taskView.notifyAppeared(newTask);
        return isSurfaceCreated;
    }

    /**
+17 −0
Original line number Diff line number Diff line
@@ -364,6 +364,23 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase {
        prepareOpenAnimationAssertions(pending, wct, false /* newTask */, mTokenBinder);
    }

    @Test
    public void showTaskView_whenSurfaceDestroyed_notHandled() {
        assumeTrue(taskViewTransitionsRefactor());

        // Simulate the surface being destroyed (e.g. a collapsed bubble being relaunched).
        when(mTaskViewTaskController.prepareOpen(any(), any())).thenReturn(null);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT)
                .addChange(getTaskView(TRANSIT_TO_FRONT)).build();

        final boolean handled = mTaskViewTransitions.startAnimation(mock(IBinder.class), info,
                mStartTransaction, mFinishTransaction, mFinishCallback);

        assertWithMessage("Handler should defer the transition when the surface is not ready")
                .that(handled).isFalse();
        verify(mFinishCallback, never()).onTransitionFinished(any());
    }

    @Test
    public void taskToTaskViewHandled() {
        assumeTrue(BubbleAnythingFlagHelper.enableCreateAnyBubble());