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

Commit 3a1f3422 authored by Jerry Chang's avatar Jerry Chang Committed by Automerger Merge Worker
Browse files

Merge "Consolidate drag to split gesture with shell transition" into tm-qpr-dev am: 14376ccd

parents 0e6836f5 14376ccd
Loading
Loading
Loading
Loading
+19 −41
Original line number Diff line number Diff line
@@ -352,15 +352,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,

    public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
            @SplitPosition int position, @Nullable Bundle options) {
        if (!ENABLE_SHELL_TRANSITIONS) {
            startIntentLegacy(intent, fillInIntent, position, options);
            return;
        }

        try {
            options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
                    null /* wct */);

        if (fillInIntent == null) {
            fillInIntent = new Intent();
        }
@@ -376,17 +367,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
        }

            intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
                    null /* requiredPermission */, options);
        } catch (PendingIntent.CanceledException e) {
            Slog.e(TAG, "Failed to launch task", e);
        if (!ENABLE_SHELL_TRANSITIONS) {
            startIntentLegacy(intent, fillInIntent, position, options);
            return;
        }

        mStageCoordinator.startIntent(intent, fillInIntent, position, options);
    }

    private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
    private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
            @SplitPosition int position, @Nullable Bundle options) {
        boolean startSameActivityAdjacently = isLaunchingAdjacently(intent.getIntent(), position);

        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        mStageCoordinator.prepareEvictChildTasks(position, evictWct);

@@ -397,8 +387,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
                    IRemoteAnimationFinishedCallback finishedCallback,
                    SurfaceControl.Transaction t) {
                if (apps == null || apps.length == 0) {
                    if (startSameActivityAdjacently) {
                        // Switch split position if dragging the same activity to another side.
                    // Switch the split position if launching as MULTIPLE_TASK failed.
                    if ((fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                        setSideStagePosition(SplitLayout.reversePosition(
                                mStageCoordinator.getSideStagePosition()));
                    }
@@ -432,18 +422,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);

        // Flag this as a no-user-action launch to prevent sending user leaving event to the current
        // top activity since it's going to be put into another side of the split. This prevents the
        // current top activity from going into pip mode due to user leaving event.
        if (fillInIntent == null) {
            fillInIntent = new Intent();
        }
        fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
        if (startSameActivityAdjacently) {
            fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
        }

        wct.sendPendingIntent(intent, fillInIntent, options);
        mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
    }
+108 −33
Original line number Diff line number Diff line
@@ -62,13 +62,12 @@ class SplitScreenTransitions {
    private final Runnable mOnFinish;

    DismissTransition mPendingDismiss = null;
    IBinder mPendingEnter = null;
    IBinder mPendingRecent = null;
    TransitSession mPendingEnter = null;
    TransitSession mPendingRecent = null;

    private IBinder mAnimatingTransition = null;
    OneShotRemoteHandler mPendingRemoteHandler = null;
    private OneShotRemoteHandler mActiveRemoteHandler = null;
    private boolean mEnterTransitionMerged;

    private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;

@@ -145,7 +144,7 @@ class SplitScreenTransitions {
                continue;
            }

            if (transition == mPendingEnter && (mainRoot.equals(change.getContainer())
            if (isPendingEnter(transition) && (mainRoot.equals(change.getContainer())
                    || sideRoot.equals(change.getContainer()))) {
                t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
                t.setWindowCrop(leash, change.getEndAbsBounds().width(),
@@ -171,12 +170,40 @@ class SplitScreenTransitions {
        onFinish(null /* wct */, null /* wctCB */);
    }

    boolean isPendingTransition(IBinder transition) {
        return isPendingEnter(transition)
                || isPendingDismiss(transition)
                || isPendingRecent(transition);
    }

    boolean isPendingEnter(IBinder transition) {
        return mPendingEnter != null && mPendingEnter.mTransition == transition;
    }

    boolean isPendingRecent(IBinder transition) {
        return mPendingRecent != null && mPendingRecent.mTransition == transition;
    }

    boolean isPendingDismiss(IBinder transition) {
        return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
    }

    /** Starts a transition to enter split with a remote transition animator. */
    IBinder startEnterTransition(@WindowManager.TransitionType int transitType,
            @NonNull WindowContainerTransaction wct, @Nullable RemoteTransition remoteTransition,
            @NonNull Transitions.TransitionHandler handler) {
    IBinder startEnterTransition(
            @WindowManager.TransitionType int transitType,
            WindowContainerTransaction wct,
            @Nullable RemoteTransition remoteTransition,
            Transitions.TransitionHandler handler,
            @Nullable TransitionCallback callback) {
        final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
        mPendingEnter = transition;
        setEnterTransition(transition, remoteTransition, callback);
        return transition;
    }

    /** Sets a transition to enter split. */
    void setEnterTransition(@NonNull IBinder transition,
            @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) {
        mPendingEnter = new TransitSession(transition, callback);

        if (remoteTransition != null) {
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -184,7 +211,9 @@ class SplitScreenTransitions {
                    mTransitions.getMainExecutor(), remoteTransition);
            mPendingRemoteHandler.setTransition(transition);
        }
        return transition;

        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
                + " deduced Enter split screen");
    }

    /** Starts a transition to dismiss split. */
@@ -209,8 +238,8 @@ class SplitScreenTransitions {
    }

    void setRecentTransition(@NonNull IBinder transition,
            @Nullable RemoteTransition remoteTransition) {
        mPendingRecent = transition;
            @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) {
        mPendingRecent = new TransitSession(transition, callback);

        if (remoteTransition != null) {
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -226,6 +255,18 @@ class SplitScreenTransitions {
    void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
            IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
        if (mergeTarget != mAnimatingTransition) return;

        if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) {
            mPendingRecent.mCallback = new TransitionCallback() {
                @Override
                public void onTransitionFinished(WindowContainerTransaction finishWct,
                        SurfaceControl.Transaction finishT) {
                    // Since there's an entering transition merged, recent transition no longer
                    // need to handle entering split screen after the transition finished.
                }
            };
        }

        if (mActiveRemoteHandler != null) {
            mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
        } else {
@@ -247,38 +288,55 @@ class SplitScreenTransitions {
    }

    void onTransitionConsumed(@NonNull IBinder transition, boolean aborted) {
        if (aborted) return;

        // Once a pending enter transition got merged, make sure to append the reset of finishing
        // operations to the finish transition.
        if (transition == mPendingEnter) {
        if (isPendingEnter(transition)) {
            if (!aborted) {
                // An enter transition got merged, appends the rest operations to finish entering
                // split screen.
                // TODO (b/238856352): Passed-in the proper finish transition to merge instead.
                if (mFinishTransaction == null) {
                    mFinishTransaction = mTransactionPool.acquire();
                }
                mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
            }

            mPendingEnter.mCallback.onTransitionConsumed(aborted);
            mPendingEnter = null;
            mPendingRemoteHandler = null;
            mEnterTransitionMerged = true;
        } else if (isPendingDismiss(transition)) {
            mPendingDismiss.mCallback.onTransitionConsumed(aborted);
            mPendingDismiss = null;
        } else if (isPendingRecent(transition)) {
            mPendingRecent.mCallback.onTransitionConsumed(aborted);
            mPendingRecent = null;
            mPendingRemoteHandler = null;
        }
    }

    void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
        if (!mAnimations.isEmpty()) return;
        if (mAnimatingTransition == mPendingEnter) {

        TransitionCallback callback = null;
        if (isPendingEnter(mAnimatingTransition)) {
            callback = mPendingEnter.mCallback;
            mPendingEnter = null;
        }
        if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
        if (isPendingDismiss(mAnimatingTransition)) {
            callback = mPendingDismiss.mCallback;
            mPendingDismiss = null;
        }
        if (mAnimatingTransition == mPendingRecent) {
            if (!mEnterTransitionMerged) {
                if (wct == null) wct = new WindowContainerTransaction();
                mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction);
            }
        if (isPendingRecent(mAnimatingTransition)) {
            callback = mPendingRecent.mCallback;
            mPendingRecent = null;
        }

        if (callback != null) {
            if (wct == null) wct = new WindowContainerTransaction();
            callback.onTransitionFinished(wct, mFinishTransaction);
        }

        mPendingRemoteHandler = null;
        mActiveRemoteHandler = null;
        mAnimatingTransition = null;
        mEnterTransitionMerged = false;

        mOnFinish.run();
        if (mFinishTransaction != null) {
@@ -382,17 +440,34 @@ class SplitScreenTransitions {
                || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
    }

    /** Bundled information of dismiss transition. */
    static class DismissTransition {
        IBinder mTransition;
    /** Clean-up callbacks for transition. */
    interface TransitionCallback {
        /** Calls when the transition got consumed. */
        default void onTransitionConsumed(boolean aborted) {}

        /** Calls when the transition finished. */
        default void onTransitionFinished(WindowContainerTransaction finishWct,
                SurfaceControl.Transaction finishT) {}
    }

        int mReason;
    /** Session for a transition and its clean-up callback. */
    static class TransitSession {
        final IBinder mTransition;
        TransitionCallback mCallback;

        @SplitScreen.StageType
        int mDismissTop;
        TransitSession(IBinder transition, @Nullable TransitionCallback callback) {
            mTransition = transition;
            mCallback = callback != null ? callback : new TransitionCallback() {};
        }
    }

    /** Bundled information of dismiss transition. */
    static class DismissTransition extends TransitSession {
        final int mReason;
        final @SplitScreen.StageType int mDismissTop;

        DismissTransition(IBinder transition, int reason, int dismissTop) {
            this.mTransition = transition;
            super(transition, null /* callback */);
            this.mReason = reason;
            this.mDismissTop = dismissTop;
        }
+92 −45
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -214,6 +215,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                }
            };

    private final SplitScreenTransitions.TransitionCallback mRecentTransitionCallback =
            new SplitScreenTransitions.TransitionCallback() {
        @Override
        public void onTransitionFinished(WindowContainerTransaction finishWct,
                SurfaceControl.Transaction finishT) {
            // Check if the recent transition is finished by returning to the current split, so we
            // can restore the divider bar.
            for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) {
                final WindowContainerTransaction.HierarchyOp op =
                        finishWct.getHierarchyOps().get(i);
                final IBinder container = op.getContainer();
                if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
                        && (mMainStage.containsContainer(container)
                        || mSideStage.containsContainer(container))) {
                    setDividerVisibility(true, finishT);
                    return;
                }
            }

            // Dismiss the split screen if it's not returning to split.
            prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct);
            setSplitsVisible(false);
            setDividerVisibility(false, finishT);
            logExit(EXIT_REASON_UNKNOWN);
        }
    };

    StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
            ShellTaskOrganizer taskOrganizer, DisplayController displayController,
            DisplayImeController displayImeController,
@@ -337,15 +365,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        targetStage.evictAllChildren(evictWct);
        targetStage.addTask(task, wct);
        if (!evictWct.isEmpty()) {
            wct.merge(evictWct, true /* transfer */);
        }

        if (ENABLE_SHELL_TRANSITIONS) {
            prepareEnterSplitScreen(wct);
            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE,
                    wct, null, this);
            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct,
                    null, this, new SplitScreenTransitions.TransitionCallback() {
                        @Override
                        public void onTransitionFinished(WindowContainerTransaction finishWct,
                                SurfaceControl.Transaction finishT) {
                            if (!evictWct.isEmpty()) {
                                finishWct.merge(evictWct, true);
                            }
                        }
                    });
        } else {
            if (!evictWct.isEmpty()) {
                wct.merge(evictWct, true /* transfer */);
            }
            mTaskOrganizer.applyTransaction(wct);
        }
        return true;
@@ -365,6 +401,39 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        return result;
    }

    /** Launches an activity into split. */
    void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
            @Nullable Bundle options) {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        prepareEvictChildTasks(position, evictWct);

        options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
        wct.sendPendingIntent(intent, fillInIntent, options);
        prepareEnterSplitScreen(wct, null /* taskInfo */, position);

        mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, null, this,
                new SplitScreenTransitions.TransitionCallback() {
                    @Override
                    public void onTransitionConsumed(boolean aborted) {
                        // Switch the split position if launching as MULTIPLE_TASK failed.
                        if (aborted
                                && (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                            setSideStagePositionAnimated(
                                    SplitLayout.reversePosition(mSideStagePosition));
                        }
                    }

                    @Override
                    public void onTransitionFinished(WindowContainerTransaction finishWct,
                            SurfaceControl.Transaction finishT) {
                        if (!evictWct.isEmpty()) {
                            finishWct.merge(evictWct, true);
                        }
                    }
                });
    }

    /** Starts 2 tasks in one transition. */
    void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
            @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
@@ -395,7 +464,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        wct.startTask(sideTaskId, sideOptions);

        mSplitTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this);
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null);
    }

    /** Starts 2 tasks in one legacy transition. */
@@ -617,11 +686,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    }

    int getTaskId(@SplitPosition int splitPosition) {
        if (mSideStagePosition == splitPosition) {
            return mSideStage.getTopVisibleChildTaskId();
        } else {
            return mMainStage.getTopVisibleChildTaskId();
        if (splitPosition == SPLIT_POSITION_UNDEFINED) {
            return INVALID_TASK_ID;
        }

        return mSideStagePosition == splitPosition
                ? mSideStage.getTopVisibleChildTaskId()
                : mMainStage.getTopVisibleChildTaskId();
    }

    void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) {
@@ -861,6 +932,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mSplitLayout.init();
        setDividerVisibility(true, t);
        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
        t.show(mRootTaskLeash);
        setSplitsVisible(true);
        mShouldUpdateRecents = true;
        updateRecentTasksSplitPair();
@@ -1543,14 +1615,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                } else if (activityType == ACTIVITY_TYPE_HOME
                        || activityType == ACTIVITY_TYPE_RECENTS) {
                    // Enter overview panel, so start recent transition.
                    mSplitTransitions.setRecentTransition(transition,
                            request.getRemoteTransition());
                    mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(),
                            mRecentTransitionCallback);
                } else if (mSplitTransitions.mPendingRecent == null) {
                    // If split-task is not controlled by recents animation
                    // and occluded by the other fullscreen task, dismiss both.
                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
                    mSplitTransitions.setDismissTransition(transition,
                            STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
                    mSplitTransitions.setDismissTransition(
                            transition, STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
                }
            }
        } else {
@@ -1558,7 +1630,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                // One task is appearing into split, prepare to enter split screen.
                out = new WindowContainerTransaction();
                prepareEnterSplitScreen(out);
                mSplitTransitions.mPendingEnter = transition;
                mSplitTransitions.setEnterTransition(
                        transition, request.getRemoteTransition(), null /* callback */);
            }
        }
        return out;
@@ -1614,10 +1687,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        if (transition != mSplitTransitions.mPendingEnter
                && transition != mSplitTransitions.mPendingRecent
                && (mSplitTransitions.mPendingDismiss == null
                        || mSplitTransitions.mPendingDismiss.mTransition != transition)) {
        if (!mSplitTransitions.isPendingTransition(transition)) {
            // Not entering or exiting, so just do some house-keeping and validation.

            // If we're not in split-mode, just abort so something else can handle it.
@@ -1664,12 +1734,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }

        boolean shouldAnimate = true;
        if (mSplitTransitions.mPendingEnter == transition) {
        if (mSplitTransitions.isPendingEnter(transition)) {
            shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
        } else if (mSplitTransitions.mPendingRecent == transition) {
        } else if (mSplitTransitions.isPendingRecent(transition)) {
            shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
        } else if (mSplitTransitions.mPendingDismiss != null
                && mSplitTransitions.mPendingDismiss.mTransition == transition) {
        } else if (mSplitTransitions.isPendingDismiss(transition)) {
            shouldAnimate = startPendingDismissAnimation(
                    mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
        }
@@ -1837,28 +1906,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        return true;
    }

    void onRecentTransitionFinished(WindowContainerTransaction wct,
            SurfaceControl.Transaction finishT) {
        // Check if the recent transition is finished by returning to the current split so we can
        // restore the divider bar.
        for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
            final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
            final IBinder container = op.getContainer();
            if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
                    && (mMainStage.containsContainer(container)
                    || mSideStage.containsContainer(container))) {
                setDividerVisibility(true, finishT);
                return;
            }
        }

        // Dismiss the split screen is it's not returning to split.
        prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
        setSplitsVisible(false);
        setDividerVisibility(false, finishT);
        logExit(EXIT_REASON_UNKNOWN);
    }

    private void addDividerBarToTransition(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, boolean show) {
        final SurfaceControl leash = mSplitLayout.getDividerLeash();
+2 −2
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class SplitTransitionTests extends ShellTestCase {

        IBinder transition = mSplitScreenTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
                new RemoteTransition(testRemote), mStageCoordinator);
                new RemoteTransition(testRemote), mStageCoordinator, null);
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -422,7 +422,7 @@ public class SplitTransitionTests extends ShellTestCase {
        TransitionInfo enterInfo = createEnterPairInfo();
        IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
                new RemoteTransition(new TestRemoteTransition()), mStageCoordinator);
                new RemoteTransition(new TestRemoteTransition()), mStageCoordinator, null);
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        mStageCoordinator.startAnimation(enterTransit, enterInfo,