Merge "Fix transition when leaving a split pair by home key" into udc-dev

This commit is contained in:
Jerry Chang
2023-03-31 01:12:52 +00:00
committed by Android (Google) Code Review
6 changed files with 66 additions and 91 deletions

View File

@@ -66,13 +66,11 @@ class SplitScreenTransitions {
private final Transitions mTransitions;
private final Runnable mOnFinish;
DismissTransition mPendingDismiss = null;
DismissSession mPendingDismiss = null;
TransitSession mPendingEnter = null;
TransitSession mPendingRecent = null;
TransitSession mPendingResize = null;
private IBinder mAnimatingTransition = null;
OneShotRemoteHandler mPendingRemoteHandler = null;
private OneShotRemoteHandler mActiveRemoteHandler = null;
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
@@ -101,27 +99,30 @@ class SplitScreenTransitions {
mFinishCallback = finishCallback;
mAnimatingTransition = transition;
mFinishTransaction = finishTransaction;
if (mPendingRemoteHandler != null) {
mPendingRemoteHandler.startAnimation(transition, info, startTransaction,
finishTransaction, mRemoteFinishCB);
mActiveRemoteHandler = mPendingRemoteHandler;
mPendingRemoteHandler = null;
return;
final TransitSession pendingTransition = getPendingTransition(transition);
if (pendingTransition != null) {
if (pendingTransition.mCanceled) {
// The pending transition was canceled, so skip playing animation.
startTransaction.apply();
onFinish(null /* wct */, null /* wctCB */);
return;
}
if (pendingTransition.mRemoteHandler != null) {
pendingTransition.mRemoteHandler.startAnimation(transition, info, startTransaction,
finishTransaction, mRemoteFinishCB);
mActiveRemoteHandler = pendingTransition.mRemoteHandler;
return;
}
}
playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot, topRoot);
}
private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
@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
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -260,10 +261,6 @@ class SplitScreenTransitions {
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;
}
@@ -276,8 +273,6 @@ class SplitScreenTransitions {
private TransitSession getPendingTransition(IBinder transition) {
if (isPendingEnter(transition)) {
return mPendingEnter;
} else if (isPendingRecent(transition)) {
return mPendingRecent;
} else if (isPendingDismiss(transition)) {
return mPendingDismiss;
} else if (isPendingResize(transition)) {
@@ -311,14 +306,8 @@ class SplitScreenTransitions {
@Nullable RemoteTransition remoteTransition,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback) {
mPendingEnter = new TransitSession(transition, consumedCallback, finishedCallback);
if (remoteTransition != null) {
// Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
mPendingRemoteHandler = new OneShotRemoteHandler(
mTransitions.getMainExecutor(), remoteTransition);
mPendingRemoteHandler.setTransition(transition);
}
mPendingEnter = new TransitSession(
transition, consumedCallback, finishedCallback, remoteTransition);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Enter split screen");
@@ -344,7 +333,7 @@ class SplitScreenTransitions {
/** Sets a transition to dismiss split. */
void setDismissTransition(@NonNull IBinder transition, @SplitScreen.StageType int dismissTop,
@SplitScreenController.ExitReason int reason) {
mPendingDismiss = new DismissTransition(transition, reason, dismissTop);
mPendingDismiss = new DismissSession(transition, reason, dismissTop);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Dismiss due to %s. toTop=%s",
@@ -372,32 +361,10 @@ class SplitScreenTransitions {
+ " deduced Resize split screen");
}
void setRecentTransition(@NonNull IBinder transition,
@Nullable RemoteTransition remoteTransition,
@Nullable TransitionFinishedCallback finishCallback) {
mPendingRecent = new TransitSession(transition, null /* consumedCb */, finishCallback);
if (remoteTransition != null) {
// Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
mPendingRemoteHandler = new OneShotRemoteHandler(
mTransitions.getMainExecutor(), remoteTransition);
mPendingRemoteHandler.setTransition(transition);
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Enter recent panel");
}
void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
if (mergeTarget != mAnimatingTransition) return;
if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) {
// Since there's an entering transition merged, recent transition no longer
// need to handle entering split screen after the transition finished.
mPendingRecent.setFinishedCallback(null);
}
if (mActiveRemoteHandler != null) {
mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
} else {
@@ -425,19 +392,13 @@ class SplitScreenTransitions {
// An entering transition got merged, appends the rest operations to finish entering
// split screen.
mStageCoordinator.finishEnterSplitScreen(finishT);
mPendingRemoteHandler = null;
}
mPendingEnter.onConsumed(aborted);
mPendingEnter = null;
mPendingRemoteHandler = null;
} else if (isPendingDismiss(transition)) {
mPendingDismiss.onConsumed(aborted);
mPendingDismiss = null;
} else if (isPendingRecent(transition)) {
mPendingRecent.onConsumed(aborted);
mPendingRecent = null;
mPendingRemoteHandler = null;
} else if (isPendingResize(transition)) {
mPendingResize.onConsumed(aborted);
mPendingResize = null;
@@ -451,9 +412,6 @@ class SplitScreenTransitions {
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;
@@ -462,7 +420,6 @@ class SplitScreenTransitions {
mPendingResize = null;
}
mPendingRemoteHandler = null;
mActiveRemoteHandler = null;
mAnimatingTransition = null;
@@ -568,10 +525,11 @@ class SplitScreenTransitions {
}
/** Session for a transition and its clean-up callback. */
static class TransitSession {
class TransitSession {
final IBinder mTransition;
TransitionConsumedCallback mConsumedCallback;
TransitionFinishedCallback mFinishedCallback;
OneShotRemoteHandler mRemoteHandler;
/** Whether the transition was canceled. */
boolean mCanceled;
@@ -579,10 +537,24 @@ class SplitScreenTransitions {
TransitSession(IBinder transition,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback) {
this(transition, consumedCallback, finishedCallback, null /* remoteTransition */);
}
TransitSession(IBinder transition,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback,
@Nullable RemoteTransition remoteTransition) {
mTransition = transition;
mConsumedCallback = consumedCallback;
mFinishedCallback = finishedCallback;
if (remoteTransition != null) {
// Wrapping the remote transition for ease-of-use. (OneShot handles all the binder
// linking/death stuff)
mRemoteHandler = new OneShotRemoteHandler(
mTransitions.getMainExecutor(), remoteTransition);
mRemoteHandler.setTransition(transition);
}
}
/** Sets transition consumed callback. */
@@ -621,11 +593,11 @@ class SplitScreenTransitions {
}
/** Bundled information of dismiss transition. */
static class DismissTransition extends TransitSession {
class DismissSession extends TransitSession {
final int mReason;
final @SplitScreen.StageType int mDismissTop;
DismissTransition(IBinder transition, int reason, int dismissTop) {
DismissSession(IBinder transition, int reason, int dismissTop) {
super(transition, null /* consumedCallback */, null /* finishedCallback */);
this.mReason = reason;
this.mDismissTop = dismissTop;

View File

@@ -2226,15 +2226,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} else if (isOpening && inFullscreen) {
final int activityType = triggerTask.getActivityType();
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
if (request.getRemoteTransition() != null) {
// starting recents/home, so don't handle this and let it fall-through to
// the remote handler.
return null;
}
// Need to use the old stuff for non-remote animations, otherwise we don't
// exit split-screen.
mSplitTransitions.setRecentTransition(transition, null /* remote */,
this::onRecentsInSplitAnimationFinish);
// starting recents/home, so don't handle this and let it fall-through to
// the remote handler.
return null;
}
}
} else {
@@ -2363,8 +2357,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSplitTransitions.isPendingEnter(transition)) {
shouldAnimate = startPendingEnterAnimation(
transition, info, startTransaction, finishTransaction);
} else if (mSplitTransitions.isPendingRecent(transition)) {
onRecentsInSplitAnimationStart(startTransaction);
} else if (mSplitTransitions.isPendingDismiss(transition)) {
shouldAnimate = startPendingDismissAnimation(
mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
@@ -2589,7 +2581,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
private boolean startPendingDismissAnimation(
@NonNull SplitScreenTransitions.DismissTransition dismissTransition,
@NonNull SplitScreenTransitions.DismissSession dismissTransition,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
@NonNull SurfaceControl.Transaction finishT) {
prepareDismissAnimation(dismissTransition.mDismissTop, dismissTransition.mReason, info,
@@ -2626,7 +2618,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
/** Call this when the recents animation during split-screen finishes. */
public void onRecentsInSplitAnimationFinish(WindowContainerTransaction finishWct,
SurfaceControl.Transaction finishT) {
SurfaceControl.Transaction finishT, TransitionInfo info) {
// 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) {
@@ -2643,8 +2635,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
// TODO(b/275664132): Remove dismissing split screen here to fit in back-to-split support.
// Dismiss the split screen if it's not returning to split.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct);
for (TransitionInfo.Change change : info.getChanges()) {
if (change.getTaskInfo() != null && TransitionUtil.isClosingType(change.getMode())) {
finishT.setCrop(change.getLeash(), null).hide(change.getLeash());
}
}
setSplitsVisible(false);
setDividerVisibility(false, finishT);
logExit(EXIT_REASON_UNKNOWN);

View File

@@ -187,17 +187,18 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
&& isOpeningType(request.getType())
&& request.getTriggerTask() != null
&& request.getTriggerTask().getWindowingMode() == WINDOWING_MODE_FULLSCREEN
&& (request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_HOME
|| request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_RECENTS)
&& request.getRemoteTransition() != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
&& request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_HOME) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a going-home request while "
+ "Split-Screen is active, so treat it as Mixed.");
Pair<Transitions.TransitionHandler, WindowContainerTransaction> handler =
mPlayer.dispatchRequest(transition, request, this);
if (handler == null) {
android.util.Log.e(Transitions.TAG, " No handler for remote? This is unexpected"
+ ", there should at-least be RemoteHandler.");
return null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
" Lean on the remote transition handler to fetch a proper remote via"
+ " TransitionFilter");
handler = new Pair<>(
mPlayer.getRemoteTransitionHandler(),
new WindowContainerTransaction());
}
final MixedTransition mixed = new MixedTransition(
MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
@@ -515,7 +516,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
// If pair-to-pair switching, the post-recents clean-up isn't needed.
if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) {
wct = wct != null ? wct : new WindowContainerTransaction();
mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction);
mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction, info);
}
mSplitHandler.onTransitionAnimationComplete();
finishCallback.onTransitionFinished(wct, wctCB);

View File

@@ -324,6 +324,10 @@ public class Transitions implements RemoteCallable<Transitions> {
mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
RemoteTransitionHandler getRemoteTransitionHandler() {
return mRemoteTransitionHandler;
}
/** Registers an observer on the lifecycle of transitions. */
public void registerObserver(@NonNull TransitionObserver observer) {
mObservers.add(observer);

View File

@@ -71,7 +71,7 @@ class DismissSplitScreenByGoHome(flicker: FlickerTest) : SplitScreenBase(flicker
// TODO(b/245472831): Move back to presubmit after shell transitions landing.
@FlakyTest(bugId = 245472831)
@Test
fun secondaryAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(primaryApp)
fun secondaryAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(secondaryApp)
// TODO(b/245472831): Move back to presubmit after shell transitions landing.
@FlakyTest(bugId = 245472831)

View File

@@ -278,7 +278,7 @@ public class SplitTransitionTests extends ShellTestCase {
// Make sure it cleans-up if recents doesn't restore
WindowContainerTransaction commitWCT = new WindowContainerTransaction();
mStageCoordinator.onRecentsInSplitAnimationFinish(commitWCT,
mock(SurfaceControl.Transaction.class));
mock(SurfaceControl.Transaction.class), mock(TransitionInfo.class));
assertFalse(mStageCoordinator.isSplitScreenVisible());
}
@@ -317,7 +317,7 @@ public class SplitTransitionTests extends ShellTestCase {
mMainStage.onTaskAppeared(mMainChild, mock(SurfaceControl.class));
mSideStage.onTaskAppeared(mSideChild, mock(SurfaceControl.class));
mStageCoordinator.onRecentsInSplitAnimationFinish(restoreWCT,
mock(SurfaceControl.Transaction.class));
mock(SurfaceControl.Transaction.class), mock(TransitionInfo.class));
assertTrue(mStageCoordinator.isSplitScreenVisible());
}