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

Commit 8d9c58a6 authored by Louis Chang's avatar Louis Chang
Browse files

Fixes flicker while starting new task from a bubble

Starting a new Bubble from an existing Bubble will immediately hide
the existing Bubble since the new Bubble Task bounds are the same
as its parent root task. So the transition will contain two changes,
one for the new open task, the second change is for the other bubble
task (TO_BACK).

Keep the task surface in the TaskView or it will be reparented to
the transition root during the transition and showing out of the
TaskView.

Bug: 407669465
Test: start bubble from an existing bubble
Flag: com.android.window.flags.root_task_for_bubble
Change-Id: Idea8cddc232e7d47b6f9a31b49f53db3a0de3724
parent c9a9dc62
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ import com.android.wm.shell.bubbles.appinfo.BubbleAppInfoProvider;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.common.HomeIntentProvider;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.taskview.TaskView;
import com.android.wm.shell.taskview.TaskViewRepository;
@@ -687,13 +688,14 @@ public class BubbleTransitions {
            mPlayConvertTaskAnimation = false;
            for (int i = info.getChanges().size() - 1; i >= 0; i--) {
                final TransitionInfo.Change chg = info.getChanges().get(i);
                final boolean isLaunchedTask = (chg.getTaskInfo() != null)
                final ActivityManager.RunningTaskInfo taskInfo = chg.getTaskInfo();
                final boolean isLaunchedTask = (taskInfo != null)
                        && (chg.getMode() == TRANSIT_CHANGE || isOpeningMode(chg.getMode()));
                if (isLaunchedTask) {
                    mStartBounds.set(chg.getStartAbsBounds());
                    // Converting a task into taskview, so treat as "new"
                    mFinishWct = new WindowContainerTransaction();
                    mTaskInfo = chg.getTaskInfo();
                    mTaskInfo = taskInfo;
                    mFinishT = finishTransaction;
                    mTaskLeash = chg.getLeash();
                    mSnapshot = chg.getSnapshot();
@@ -701,6 +703,16 @@ public class BubbleTransitions {
                    //  is no snapshot, so fallback to the open transition for now
                    mPlayConvertTaskAnimation = false;
                    found = true;
                } else if (BubbleAnythingFlagHelper.enableRootTaskForBubble() && taskInfo != null
                        && mBubbleController.shouldBeAppBubble(taskInfo)) {
                    // Starting a new bubble from an existing expanded bubble may immediately hide
                    // the currently expanded bubble in the same transition. Ensure the surfaces
                    // stays in the TaskView vs. under the transition root.
                    final Bubble b = mBubbleData.getBubbleInStackWithTaskId(taskInfo.taskId);
                    if (b != null) {
                        startTransaction.reparent(chg.getLeash(),
                                b.getTaskView().getSurfaceControl());
                    }
                } else {
                    // In core-initiated launches, the transition is of an OPEN type, and we need to
                    // manually show the surfaces behind the newly bubbled task
+64 −0
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

import static com.android.window.flags.Flags.FLAG_ROOT_TASK_FOR_BUBBLE;
import static com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR;
import static com.android.wm.shell.Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE;
import static com.android.wm.shell.bubbles.util.BubbleTestUtils.verifyEnterBubbleTransaction;
import static com.android.wm.shell.transition.Transitions.TRANSIT_BUBBLE_CONVERT_FLOATING_TO_BAR;
import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE;
@@ -1239,4 +1241,66 @@ public class BubbleTransitionsTest extends ShellTestCase {

        assertThat(mBubbleTransitions.getClosingBubbleTask(info)).isNull();
    }

    @Test
    @EnableFlags({FLAG_ENABLE_CREATE_ANY_BUBBLE, FLAG_ROOT_TASK_FOR_BUBBLE})
    public void testStartNewBubbleTaskFromExistingBubble() {
        // Setup a Bubble that's currently expanded
        final Bubble expandedBubble = mock(Bubble.class);
        setUpBubbleBarExpandedView(expandedBubble);
        final TaskView expandedTaskView = setUpBubbleTaskView(expandedBubble);
        final SurfaceControl expandedTaskViewLeash = expandedTaskView.getSurfaceControl();
        final ActivityManager.RunningTaskInfo expandedTaskInfo = setupAppBubble(
                expandedBubble, expandedTaskView, mTaskViewTaskController);
        expandedTaskInfo.taskId = 10;
        // Setup a new open Bubble
        final TaskView openingTaskView = setUpBubbleTaskView(mBubble);
        final ActivityManager.RunningTaskInfo openingTaskInfo = setupAppBubble(
                mBubble, openingTaskView, mTaskViewTaskController);
        // Setup Transition
        final IBinder transitionToken = mock(IBinder.class);
        final Consumer<Transitions.TransitionHandler> onInflatedCallback = mock(Consumer.class);
        final SurfaceControl openingTaskLeash =
                new SurfaceControl.Builder().setName("openingTaskLeash").build();
        final TransitionInfo.Change openingChg = new TransitionInfo.Change(openingTaskInfo.token,
                openingTaskLeash);
        openingChg.setTaskInfo(openingTaskInfo);
        openingChg.setMode(TRANSIT_OPEN);
        final SurfaceControl expandedTaskLeash =
                new SurfaceControl.Builder().setName("expandedTaskLeash").build();
        final TransitionInfo.Change expandedChg = new TransitionInfo.Change(expandedTaskInfo.token,
                expandedTaskLeash);
        expandedChg.setTaskInfo(expandedTaskInfo);
        expandedChg.setMode(TRANSIT_TO_BACK);
        doReturn(expandedBubble).when(mBubbleData).getBubbleInStackWithTaskId(
                expandedTaskInfo.taskId);
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        info.addChange(openingChg);
        info.addChange(expandedChg);
        info.addRoot(new TransitionInfo.Root(openingTaskInfo.displayId, openingTaskLeash, 0, 0));
        final SurfaceControl.Transaction startT = spy(new SurfaceControl.Transaction());
        final SurfaceControl.Transaction finishT = spy(new SurfaceControl.Transaction());
        doNothing().when(startT).apply();
        doNothing().when(finishT).apply();
        final Transitions.TransitionFinishCallback finishCb =
                mock(Transitions.TransitionFinishCallback.class);

        final BubbleTransitions.LaunchNewTaskBubbleForExistingTransition bt =
                (BubbleTransitions.LaunchNewTaskBubbleForExistingTransition) mBubbleTransitions
                        .startLaunchNewTaskBubbleForExistingTransition(mBubble,
                                mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
                                mStackView, mLayerView, mIconFactory, false /* inflateSync */,
                                transitionToken, onInflatedCallback);

        verify(mBubble).setPreparingTransition(bt);

        bt.onInflated(mBubble);

        // Start playing the transition
        bt.startAnimation(transitionToken, info, startT, finishT, finishCb);

        // Verify that the to-back leash is in TaskView
        verify(startT).reparent(expandedTaskLeash, expandedTaskViewLeash);
        verify(startT).apply();
    }
}