Merge "Add fallback logic to cancel entering split screen" into tm-qpr-dev

This commit is contained in:
Jerry Chang
2022-10-27 03:55:19 +00:00
committed by Android (Google) Code Review
3 changed files with 175 additions and 128 deletions

View File

@@ -108,6 +108,14 @@ class SplitScreenTransitions {
private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot, @NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
@NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) { @NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) {
final TransitSession pendingTransition = getPendingTransition(transition);
if (pendingTransition != null && pendingTransition.mCanceled) {
// The pending transition was canceled, so skip playing animation.
t.apply();
onFinish(null /* wct */, null /* wctCB */);
return;
}
// Play some place-holder fade animations // Play some place-holder fade animations
for (int i = info.getChanges().size() - 1; i >= 0; --i) { for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i); final TransitionInfo.Change change = info.getChanges().get(i);
@@ -170,9 +178,7 @@ class SplitScreenTransitions {
} }
boolean isPendingTransition(IBinder transition) { boolean isPendingTransition(IBinder transition) {
return isPendingEnter(transition) return getPendingTransition(transition) != null;
|| isPendingDismiss(transition)
|| isPendingRecent(transition);
} }
boolean isPendingEnter(IBinder transition) { boolean isPendingEnter(IBinder transition) {
@@ -187,22 +193,38 @@ class SplitScreenTransitions {
return mPendingDismiss != null && mPendingDismiss.mTransition == transition; return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
} }
@Nullable
private TransitSession getPendingTransition(IBinder transition) {
if (isPendingEnter(transition)) {
return mPendingEnter;
} else if (isPendingRecent(transition)) {
return mPendingRecent;
} else if (isPendingDismiss(transition)) {
return mPendingDismiss;
}
return null;
}
/** Starts a transition to enter split with a remote transition animator. */ /** Starts a transition to enter split with a remote transition animator. */
IBinder startEnterTransition( IBinder startEnterTransition(
@WindowManager.TransitionType int transitType, @WindowManager.TransitionType int transitType,
WindowContainerTransaction wct, WindowContainerTransaction wct,
@Nullable RemoteTransition remoteTransition, @Nullable RemoteTransition remoteTransition,
Transitions.TransitionHandler handler, Transitions.TransitionHandler handler,
@Nullable TransitionCallback callback) { @Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback) {
final IBinder transition = mTransitions.startTransition(transitType, wct, handler); final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
setEnterTransition(transition, remoteTransition, callback); setEnterTransition(transition, remoteTransition, consumedCallback, finishedCallback);
return transition; return transition;
} }
/** Sets a transition to enter split. */ /** Sets a transition to enter split. */
void setEnterTransition(@NonNull IBinder transition, void setEnterTransition(@NonNull IBinder transition,
@Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) { @Nullable RemoteTransition remoteTransition,
mPendingEnter = new TransitSession(transition, callback); @Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback) {
mPendingEnter = new TransitSession(transition, consumedCallback, finishedCallback);
if (remoteTransition != null) { if (remoteTransition != null) {
// Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff) // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -237,8 +259,9 @@ class SplitScreenTransitions {
} }
void setRecentTransition(@NonNull IBinder transition, void setRecentTransition(@NonNull IBinder transition,
@Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) { @Nullable RemoteTransition remoteTransition,
mPendingRecent = new TransitSession(transition, callback); @Nullable TransitionFinishedCallback finishCallback) {
mPendingRecent = new TransitSession(transition, null /* consumedCb */, finishCallback);
if (remoteTransition != null) { if (remoteTransition != null) {
// Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff) // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -256,14 +279,9 @@ class SplitScreenTransitions {
if (mergeTarget != mAnimatingTransition) return; if (mergeTarget != mAnimatingTransition) return;
if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) { 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 // Since there's an entering transition merged, recent transition no longer
// need to handle entering split screen after the transition finished. // need to handle entering split screen after the transition finished.
} mPendingRecent.setFinishedCallback(null);
};
} }
if (mActiveRemoteHandler != null) { if (mActiveRemoteHandler != null) {
@@ -277,7 +295,7 @@ class SplitScreenTransitions {
} }
boolean end() { boolean end() {
// If its remote, there's nothing we can do right now. // If It's remote, there's nothing we can do right now.
if (mActiveRemoteHandler != null) return false; if (mActiveRemoteHandler != null) return false;
for (int i = mAnimations.size() - 1; i >= 0; --i) { for (int i = mAnimations.size() - 1; i >= 0; --i) {
final Animator anim = mAnimations.get(i); final Animator anim = mAnimations.get(i);
@@ -290,20 +308,20 @@ class SplitScreenTransitions {
@Nullable SurfaceControl.Transaction finishT) { @Nullable SurfaceControl.Transaction finishT) {
if (isPendingEnter(transition)) { if (isPendingEnter(transition)) {
if (!aborted) { if (!aborted) {
// An enter transition got merged, appends the rest operations to finish entering // An entering transition got merged, appends the rest operations to finish entering
// split screen. // split screen.
mStageCoordinator.finishEnterSplitScreen(finishT); mStageCoordinator.finishEnterSplitScreen(finishT);
mPendingRemoteHandler = null; mPendingRemoteHandler = null;
} }
mPendingEnter.mCallback.onTransitionConsumed(aborted); mPendingEnter.onConsumed(aborted);
mPendingEnter = null; mPendingEnter = null;
mPendingRemoteHandler = null; mPendingRemoteHandler = null;
} else if (isPendingDismiss(transition)) { } else if (isPendingDismiss(transition)) {
mPendingDismiss.mCallback.onTransitionConsumed(aborted); mPendingDismiss.onConsumed(aborted);
mPendingDismiss = null; mPendingDismiss = null;
} else if (isPendingRecent(transition)) { } else if (isPendingRecent(transition)) {
mPendingRecent.mCallback.onTransitionConsumed(aborted); mPendingRecent.onConsumed(aborted);
mPendingRecent = null; mPendingRecent = null;
mPendingRemoteHandler = null; mPendingRemoteHandler = null;
} }
@@ -312,23 +330,16 @@ class SplitScreenTransitions {
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) { void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
if (!mAnimations.isEmpty()) return; if (!mAnimations.isEmpty()) return;
TransitionCallback callback = null;
if (isPendingEnter(mAnimatingTransition)) {
callback = mPendingEnter.mCallback;
mPendingEnter = null;
}
if (isPendingDismiss(mAnimatingTransition)) {
callback = mPendingDismiss.mCallback;
mPendingDismiss = null;
}
if (isPendingRecent(mAnimatingTransition)) {
callback = mPendingRecent.mCallback;
mPendingRecent = null;
}
if (callback != null) {
if (wct == null) wct = new WindowContainerTransaction(); if (wct == null) wct = new WindowContainerTransaction();
callback.onTransitionFinished(wct, mFinishTransaction); if (isPendingEnter(mAnimatingTransition)) {
mPendingEnter.onFinished(wct, mFinishTransaction);
mPendingEnter = null;
} else if (isPendingRecent(mAnimatingTransition)) {
mPendingRecent.onFinished(wct, mFinishTransaction);
mPendingRecent = null;
} else if (isPendingDismiss(mAnimatingTransition)) {
mPendingDismiss.onFinished(wct, mFinishTransaction);
mPendingDismiss = null;
} }
mPendingRemoteHandler = null; mPendingRemoteHandler = null;
@@ -363,10 +374,7 @@ class SplitScreenTransitions {
onFinish(null /* wct */, null /* wctCB */); onFinish(null /* wct */, null /* wctCB */);
}); });
}; };
va.addListener(new Animator.AnimatorListener() { va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) { }
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
finisher.run(); finisher.run();
@@ -376,9 +384,6 @@ class SplitScreenTransitions {
public void onAnimationCancel(Animator animation) { public void onAnimationCancel(Animator animation) {
finisher.run(); finisher.run();
} }
@Override
public void onAnimationRepeat(Animator animation) { }
}); });
mAnimations.add(va); mAnimations.add(va);
mTransitions.getAnimExecutor().execute(va::start); mTransitions.getAnimExecutor().execute(va::start);
@@ -432,24 +437,66 @@ class SplitScreenTransitions {
|| info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN; || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
} }
/** Clean-up callbacks for transition. */
interface TransitionCallback {
/** Calls when the transition got consumed. */ /** Calls when the transition got consumed. */
default void onTransitionConsumed(boolean aborted) {} interface TransitionConsumedCallback {
void onConsumed(boolean aborted);
}
/** Calls when the transition finished. */ /** Calls when the transition finished. */
default void onTransitionFinished(WindowContainerTransaction finishWct, interface TransitionFinishedCallback {
SurfaceControl.Transaction finishT) {} void onFinished(WindowContainerTransaction wct, SurfaceControl.Transaction t);
} }
/** Session for a transition and its clean-up callback. */ /** Session for a transition and its clean-up callback. */
static class TransitSession { static class TransitSession {
final IBinder mTransition; final IBinder mTransition;
TransitionCallback mCallback; TransitionConsumedCallback mConsumedCallback;
TransitionFinishedCallback mFinishedCallback;
TransitSession(IBinder transition, @Nullable TransitionCallback callback) { /** Whether the transition was canceled. */
boolean mCanceled;
TransitSession(IBinder transition,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback) {
mTransition = transition; mTransition = transition;
mCallback = callback != null ? callback : new TransitionCallback() {}; mConsumedCallback = consumedCallback;
mFinishedCallback = finishedCallback;
}
/** Sets transition consumed callback. */
void setConsumedCallback(@Nullable TransitionConsumedCallback callback) {
mConsumedCallback = callback;
}
/** Sets transition finished callback. */
void setFinishedCallback(@Nullable TransitionFinishedCallback callback) {
mFinishedCallback = callback;
}
/**
* Cancels the transition. This should be called before playing animation. A canceled
* transition will skip playing animation.
*
* @param finishedCb new finish callback to override.
*/
void cancel(@Nullable TransitionFinishedCallback finishedCb) {
mCanceled = true;
setFinishedCallback(finishedCb);
}
void onConsumed(boolean aborted) {
if (mConsumedCallback != null) {
mConsumedCallback.onConsumed(aborted);
}
}
void onFinished(WindowContainerTransaction finishWct,
SurfaceControl.Transaction finishT) {
if (mFinishedCallback != null) {
mFinishedCallback.onFinished(finishWct, finishT);
}
} }
} }
@@ -459,7 +506,7 @@ class SplitScreenTransitions {
final @SplitScreen.StageType int mDismissTop; final @SplitScreen.StageType int mDismissTop;
DismissTransition(IBinder transition, int reason, int dismissTop) { DismissTransition(IBinder transition, int reason, int dismissTop) {
super(transition, null /* callback */); super(transition, null /* consumedCallback */, null /* finishedCallback */);
this.mReason = reason; this.mReason = reason;
this.mDismissTop = dismissTop; this.mDismissTop = dismissTop;
} }

View File

@@ -226,12 +226,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} }
}; };
private final SplitScreenTransitions.TransitionCallback mRecentTransitionCallback = private final SplitScreenTransitions.TransitionFinishedCallback
new SplitScreenTransitions.TransitionCallback() { mRecentTransitionFinishedCallback =
new SplitScreenTransitions.TransitionFinishedCallback() {
@Override @Override
public void onTransitionFinished(WindowContainerTransaction finishWct, public void onFinished(WindowContainerTransaction finishWct,
SurfaceControl.Transaction finishT) { SurfaceControl.Transaction finishT) {
// Check if the recent transition is finished by returning to the current split, so we // Check if the recent transition is finished by returning to the current
// split, so we
// can restore the divider bar. // can restore the divider bar.
for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) {
final WindowContainerTransaction.HierarchyOp op = final WindowContainerTransaction.HierarchyOp op =
@@ -240,7 +242,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
&& (mMainStage.containsContainer(container) && (mMainStage.containsContainer(container)
|| mSideStage.containsContainer(container))) { || mSideStage.containsContainer(container))) {
updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */); updateSurfaceBounds(mSplitLayout, finishT,
false /* applyResizingOffset */);
setDividerVisibility(true, finishT); setDividerVisibility(true, finishT);
return; return;
} }
@@ -389,15 +392,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (ENABLE_SHELL_TRANSITIONS) { if (ENABLE_SHELL_TRANSITIONS) {
prepareEnterSplitScreen(wct); prepareEnterSplitScreen(wct);
mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct,
null, this, new SplitScreenTransitions.TransitionCallback() { null, this, null /* consumedCallback */, (finishWct, finishT) -> {
@Override
public void onTransitionFinished(WindowContainerTransaction finishWct,
SurfaceControl.Transaction finishT) {
if (!evictWct.isEmpty()) { if (!evictWct.isEmpty()) {
finishWct.merge(evictWct, true); finishWct.merge(evictWct, true);
} }
} } /* finishedCallback */);
});
} else { } else {
if (!evictWct.isEmpty()) { if (!evictWct.isEmpty()) {
wct.merge(evictWct, true /* transfer */); wct.merge(evictWct, true /* transfer */);
@@ -434,28 +433,25 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */); options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
wct.sendPendingIntent(intent, fillInIntent, options); wct.sendPendingIntent(intent, fillInIntent, options);
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int transitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
prepareEnterSplitScreen(wct, null /* taskInfo */, position); prepareEnterSplitScreen(wct, null /* taskInfo */, position);
mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, null, this, mSplitTransitions.startEnterTransition(transitType, wct, null, this,
new SplitScreenTransitions.TransitionCallback() { aborted -> {
@Override
public void onTransitionConsumed(boolean aborted) {
// Switch the split position if launching as MULTIPLE_TASK failed. // Switch the split position if launching as MULTIPLE_TASK failed.
if (aborted if (aborted && (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
&& (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
setSideStagePositionAnimated( setSideStagePositionAnimated(
SplitLayout.reversePosition(mSideStagePosition)); SplitLayout.reversePosition(mSideStagePosition));
} }
} } /* consumedCallback */,
(finishWct, finishT) -> {
@Override
public void onTransitionFinished(WindowContainerTransaction finishWct,
SurfaceControl.Transaction finishT) {
if (!evictWct.isEmpty()) { if (!evictWct.isEmpty()) {
finishWct.merge(evictWct, true); finishWct.merge(evictWct, true);
} }
} } /* finishedCallback */);
});
} }
/** Launches an activity into split by legacy transition. */ /** Launches an activity into split by legacy transition. */
@@ -592,7 +588,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.startTask(mainTaskId, mainOptions); wct.startTask(mainTaskId, mainOptions);
mSplitTransitions.startEnterTransition( mSplitTransitions.startEnterTransition(
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null); TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null, null);
setEnterInstanceId(instanceId); setEnterInstanceId(instanceId);
} }
@@ -1839,7 +1835,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|| activityType == ACTIVITY_TYPE_RECENTS) { || activityType == ACTIVITY_TYPE_RECENTS) {
// Enter overview panel, so start recent transition. // Enter overview panel, so start recent transition.
mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(), mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(),
mRecentTransitionCallback); mRecentTransitionFinishedCallback);
} else if (mSplitTransitions.mPendingRecent == null) { } else if (mSplitTransitions.mPendingRecent == null) {
// If split-task is not controlled by recents animation // If split-task is not controlled by recents animation
// and occluded by the other fullscreen task, dismiss both. // and occluded by the other fullscreen task, dismiss both.
@@ -1853,8 +1849,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// One task is appearing into split, prepare to enter split screen. // One task is appearing into split, prepare to enter split screen.
out = new WindowContainerTransaction(); out = new WindowContainerTransaction();
prepareEnterSplitScreen(out); prepareEnterSplitScreen(out);
mSplitTransitions.setEnterTransition( mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
transition, request.getRemoteTransition(), null /* callback */); null /* consumedCallback */, null /* finishedCallback */);
} }
} }
return out; return out;
@@ -2031,17 +2027,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} }
} }
// TODO(b/250853925): fallback logic. Probably start a new transition to exit split before
// applying anything here. Ideally consolidate with transition-merging.
if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) { if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
if (mainChild == null && sideChild == null) { if (mainChild == null && sideChild == null) {
throw new IllegalStateException("Launched a task in split, but didn't receive any" Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
+ " task in transition."); mSplitTransitions.mPendingEnter.cancel(null /* finishedCb */);
return true;
} }
} else { } else {
if (mainChild == null || sideChild == null) { if (mainChild == null || sideChild == null) {
throw new IllegalStateException("Launched 2 tasks in split, but didn't receive" Log.w(TAG, "Launched 2 tasks in split, but didn't receive"
+ " 2 tasks in transition. Possibly one of them failed to launch"); + " 2 tasks in transition. Possibly one of them failed to launch");
final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
(sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
mSplitTransitions.mPendingEnter.cancel(
(cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
return true;
} }
} }
@@ -2305,7 +2305,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(stageType, wct); prepareExitSplitScreen(stageType, wct);
mSplitTransitions.startDismissTransition(wct,StageCoordinator.this, stageType, mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
mSplitUnsupportedToast.show(); mSplitUnsupportedToast.show();
} }

View File

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