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

Commit 0481902a authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Add external gate transition to TaskViewTransitions" into main

parents 16e1b2d2 dfe8620f
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -217,8 +217,8 @@ public class BubbleTransitions {
            ProtoLog.d(
                    WM_SHELL_BUBBLES, "notifyUnfoldTransitionStarting transition=%s", transition);
            Bubble bubble = (Bubble) mBubbleData.getSelectedBubble();
            mTaskViewTransitions.enqueueExternal(
                    bubble.getTaskView().getController(), () -> transition);
            mTaskViewTransitions.enqueueRunningExternal(bubble.getTaskView().getController(),
                    transition);
        }
    }

@@ -539,7 +539,7 @@ public class BubbleTransitions {
            // Remove any intermediate queued transitions that were started as a result of the
            // inflation (the task view will be in the right bounds)
            mTaskViewTransitions.removePendingTransitions(tv.getController());
            mTaskViewTransitions.enqueueExternal(tv.getController(), () -> mTransition);
            mTaskViewTransitions.enqueueRunningExternal(tv.getController(), mTransition);
        }

        @Override
@@ -826,6 +826,7 @@ public class BubbleTransitions {
                }
                opts.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
                opts.setLaunchBounds(launchBounds);
                // TODO(b/437451940): start the pending intent or shortcut via WCT
                if (mBubble.isShortcut()) {
                    final LauncherApps launcherApps = mContext.getSystemService(
                            LauncherApps.class);
@@ -1769,7 +1770,8 @@ public class BubbleTransitions {
            final TaskView tv = mBubble.getTaskView();
            mTransition = mTransitions.startTransition(TRANSIT_BUBBLE_CONVERT_FLOATING_TO_BAR,
                    mWct, this);
            mTaskViewTransitions.enqueueExternal(tv.getController(), () -> mTransition);
            mTaskViewTransitions.removePendingTransitions(tv.getController());
            mTaskViewTransitions.enqueueRunningExternal(tv.getController(), mTransition);
        }

        @Override
+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ public class BubblesTransitionObserver implements Transitions.TransitionObserver
            // Notify the task removal, but block all TaskViewTransitions during removal so we can
            // clear them without triggering
            final IBinder gate = new Binder();
            mTaskViewTransitions.enqueueExternal(controller, () -> gate);
            mTaskViewTransitions.enqueueRunningExternal(controller, gate);

            taskOrganizer.applyTransaction(wct);
            controller.notifyTaskRemovalStarted(taskInfo);
+19 −0
Original line number Diff line number Diff line
@@ -217,6 +217,25 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
        startNextTransition();
    }

    /**
     * Add an already running external transition into the pending queue.
     * This transition has to be started externally. And it will block any new transitions from
     * starting in the pending queue.
     *
     * The external operation *must* call {@link #onExternalDone(IBinder)} once it has finished.
     */
    public void enqueueRunningExternal(@NonNull TaskViewTaskController taskView,
            IBinder transition) {
        ProtoLog.d(WM_SHELL_BUBBLES_NOISY,
                "Transitions.enqueueRunningExternal(): taskView=%d pending=%d",
                taskView.hashCode(), mPending.size());
        final PendingTransition pending = new PendingTransition(
                TRANSIT_NONE, null /* wct */, taskView, null /* cookie */);
        pending.mExternalTransition = () -> transition;
        pending.mClaimed = transition;
        mPending.add(pending);
    }

    /**
     * An external transition run in this "queue" is required to call this once it becomes ready.
     */
+79 −6
Original line number Diff line number Diff line
@@ -164,22 +164,32 @@ public class BubbleTransitionsTest extends ShellTestCase {
    }

    private ActivityManager.RunningTaskInfo setupBubble() {
        return setupBubble(mTaskView, mTaskViewTaskController);
    }

    private ActivityManager.RunningTaskInfo setupBubble(TaskView taskView,
            TaskViewTaskController taskViewTaskController) {
        final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
        final WindowContainerToken token = new MockToken().token();
        taskInfo.token = token;
        when(mTaskViewTaskController.getTaskInfo()).thenReturn(taskInfo);
        when(mTaskView.getController()).thenReturn(mTaskViewTaskController);
        when(mBubble.getTaskView()).thenReturn(mTaskView);
        when(mTaskView.getTaskInfo()).thenReturn(taskInfo);
        mRepository.add(mTaskViewTaskController);
        when(taskViewTaskController.getTaskInfo()).thenReturn(taskInfo);
        when(taskView.getController()).thenReturn(taskViewTaskController);
        when(mBubble.getTaskView()).thenReturn(taskView);
        when(taskView.getTaskInfo()).thenReturn(taskInfo);
        mRepository.add(taskViewTaskController);
        return taskInfo;
    }

    private ActivityManager.RunningTaskInfo setupAppBubble() {
        return setupAppBubble(mTaskView, mTaskViewTaskController);
    }

    private ActivityManager.RunningTaskInfo setupAppBubble(TaskView taskView,
            TaskViewTaskController taskViewTaskController) {
        when(mBubble.isApp()).thenReturn(true);
        when(mBubble.getIntent()).thenReturn(new Intent());
        when(mBubble.getUser()).thenReturn(new UserHandle(0));
        return setupBubble();
        return setupBubble(taskView, taskViewTaskController);
    }

    private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo,
@@ -966,4 +976,67 @@ public class BubbleTransitionsTest extends ShellTestCase {
        verify(mBubble).setPreparingTransition(null);
        assertThat(mTaskViewTransitions.hasPending()).isFalse();
    }

    /**
     * Test a scenario where the TaskViewTransitions queue has a pending TaskView transition. And
     * a new transition for launching a different bubble comes in during it. Once both transitions
     * are handled, the TaskViewTransitions pending queue should be empty.
     */
    @Test
    public void launchNewTaskBubbleForExistingTransition_withExistingTransitionInQueue() {
        // Set up a bubble and have it queue a transition in the queue that will remain pending
        TaskView existingTaskView = mock(TaskView.class);
        TaskViewTaskController existingTvc = mock(TaskViewTaskController.class);
        setupAppBubble(existingTaskView, existingTvc);
        final IBinder existingTransition = mock(IBinder.class);
        when(mTransitions.startTransition(anyInt(), any(), any())).thenReturn(existingTransition);
        mTaskViewTransitions.setTaskViewVisible(existingTvc, true);

        // Check that there is a pending transition before we create the new bubble
        assertThat(mTaskViewTransitions.hasPending()).isTrue();

        when(mLayerView.canExpandView(mBubble)).thenReturn(true);

        final ActivityManager.RunningTaskInfo bubbleTask = setupAppBubble();
        final IBinder transition = mock(IBinder.class);
        final BubbleTransitions.LaunchNewTaskBubbleForExistingTransition bt =
                (BubbleTransitions.LaunchNewTaskBubbleForExistingTransition) mBubbleTransitions
                        .startLaunchNewTaskBubbleForExistingTransition(
                                mBubble, mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
                                mStackView, mLayerView, mIconFactory, false /* inflateSync */,
                                transition, transitionHandler -> {});

        verify(mBubble).setPreparingTransition(bt);

        // Prepare for startAnimation call
        final SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build();
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change chg = new TransitionInfo.Change(bubbleTask.token, taskLeash);
        chg.setTaskInfo(bubbleTask);
        chg.setMode(TRANSIT_CHANGE);
        info.addChange(chg);
        info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0));

        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        final Transitions.TransitionFinishCallback finishCb = wct -> {};

        // Start playing the new bubble transition
        bt.startAnimation(transition, info, startT, finishT, finishCb);
        verify(mBubble, never()).setPreparingTransition(null);
        bt.onInflated(mBubble);
        bt.surfaceCreated();
        bt.continueExpand();

        // The pending queue should still have the transition from the existing bubble
        assertThat(mTaskViewTransitions.hasPending()).isTrue();

        // Now start the existing bubble transition
        mTaskViewTransitions.startAnimation(existingTransition,
                new TransitionInfo(TRANSIT_CHANGE, 0), startT, finishT, wct -> {
                });

        // Now the queue should be empty
        assertThat(mTaskViewTransitions.hasPending()).isFalse();
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -446,6 +446,32 @@ public class TaskViewTransitionsTest extends ShellTestCase {
        assertThat(mTaskViewTransitions.hasPending()).isFalse();
    }

    @Test
    public void enqueueRunningExternal_clearedFromPendingWithoutStarting() {
        // Add a normal transition to the queue first.
        mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
        assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController,
                TRANSIT_TO_FRONT)).isNotNull();

        // Simulate an already running external transition by adding its binder ref.
        IBinder externalTransition = new Binder();
        mTaskViewTransitions.enqueueRunningExternal(mTaskViewTaskController, externalTransition);

        // Verify that both transitions are in the pending queue.
        assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController,
                TRANSIT_TO_FRONT)).isNotNull();
        assertThat(mTaskViewTransitions.findPending(externalTransition)).isNotNull();

        // Now, clear the external gate transition.
        mTaskViewTransitions.onExternalDone(externalTransition);

        // Verify that the external gate is removed, but the original transition is still pending.
        assertThat(mTaskViewTransitions.findPending(externalTransition)).isNull();
        assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController,
                TRANSIT_TO_FRONT)).isNotNull();
        assertThat(mTaskViewTransitions.hasPending()).isTrue();
    }

    private ActivityManager.RunningTaskInfo createMockTaskInfo(int taskId,
            WindowContainerToken token) {
        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();