Consolidate drag to split gesture with shell transition
Refine SplitScreenTransitions with TransitionCallback to consolidate
transition handling logic.
1. Support to replace previous pairing app with drag-to-split gesture.
2. Support to switch split position by drag and drop a single-instance
app to another side of the split.
Fix: 236814427
Fix: 236814471
Test: atest WMShellUnitTests
Test: enable shell transition, enter split screen, verified
1. drag and drop gesture can replace apps in split
2. drag and drop single-instance app to another side switch
split position
3. quick switch and overview switch works as expected
Change-Id: Icde96369b79947e93a53ac589e64201aa32cf337
This commit is contained in:
@@ -352,41 +352,31 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
||||
|
||||
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
|
||||
@SplitPosition int position, @Nullable Bundle options) {
|
||||
if (fillInIntent == null) {
|
||||
fillInIntent = new Intent();
|
||||
}
|
||||
// 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.
|
||||
fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
|
||||
|
||||
// Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the
|
||||
// split.
|
||||
if (isLaunchingAdjacently(intent.getIntent(), position)) {
|
||||
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
// 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.
|
||||
fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
|
||||
|
||||
// Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the
|
||||
// split.
|
||||
if (isLaunchingAdjacently(intent.getIntent(), position)) {
|
||||
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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);
|
||||
}
|
||||
|
||||
// Once a pending enter transition got merged, make sure to append the reset of finishing
|
||||
// operations to the finish transition.
|
||||
if (transition == mPendingEnter) {
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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) {}
|
||||
}
|
||||
|
||||
/** Session for a transition and its clean-up callback. */
|
||||
static class TransitSession {
|
||||
final IBinder mTransition;
|
||||
TransitionCallback mCallback;
|
||||
|
||||
TransitSession(IBinder transition, @Nullable TransitionCallback callback) {
|
||||
mTransition = transition;
|
||||
mCallback = callback != null ? callback : new TransitionCallback() {};
|
||||
}
|
||||
}
|
||||
|
||||
/** Bundled information of dismiss transition. */
|
||||
static class DismissTransition {
|
||||
IBinder mTransition;
|
||||
|
||||
int mReason;
|
||||
|
||||
@SplitScreen.StageType
|
||||
int mDismissTop;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user