Merge "Consolidate drag to split gesture with shell transition" into tm-qpr-dev
This commit is contained in:
@@ -352,41 +352,31 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
|||||||
|
|
||||||
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
|
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
|
||||||
@SplitPosition int position, @Nullable Bundle options) {
|
@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) {
|
if (!ENABLE_SHELL_TRANSITIONS) {
|
||||||
startIntentLegacy(intent, fillInIntent, position, options);
|
startIntentLegacy(intent, fillInIntent, position, options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
mStageCoordinator.startIntent(intent, fillInIntent, position, options);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
|
private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
|
||||||
@SplitPosition int position, @Nullable Bundle options) {
|
@SplitPosition int position, @Nullable Bundle options) {
|
||||||
boolean startSameActivityAdjacently = isLaunchingAdjacently(intent.getIntent(), position);
|
|
||||||
|
|
||||||
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
|
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
|
||||||
mStageCoordinator.prepareEvictChildTasks(position, evictWct);
|
mStageCoordinator.prepareEvictChildTasks(position, evictWct);
|
||||||
|
|
||||||
@@ -397,8 +387,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
|||||||
IRemoteAnimationFinishedCallback finishedCallback,
|
IRemoteAnimationFinishedCallback finishedCallback,
|
||||||
SurfaceControl.Transaction t) {
|
SurfaceControl.Transaction t) {
|
||||||
if (apps == null || apps.length == 0) {
|
if (apps == null || apps.length == 0) {
|
||||||
if (startSameActivityAdjacently) {
|
// Switch the split position if launching as MULTIPLE_TASK failed.
|
||||||
// Switch split position if dragging the same activity to another side.
|
if ((fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
|
||||||
setSideStagePosition(SplitLayout.reversePosition(
|
setSideStagePosition(SplitLayout.reversePosition(
|
||||||
mStageCoordinator.getSideStagePosition()));
|
mStageCoordinator.getSideStagePosition()));
|
||||||
}
|
}
|
||||||
@@ -432,18 +422,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
|||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
|
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);
|
wct.sendPendingIntent(intent, fillInIntent, options);
|
||||||
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
|
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,13 +62,12 @@ class SplitScreenTransitions {
|
|||||||
private final Runnable mOnFinish;
|
private final Runnable mOnFinish;
|
||||||
|
|
||||||
DismissTransition mPendingDismiss = null;
|
DismissTransition mPendingDismiss = null;
|
||||||
IBinder mPendingEnter = null;
|
TransitSession mPendingEnter = null;
|
||||||
IBinder mPendingRecent = null;
|
TransitSession mPendingRecent = null;
|
||||||
|
|
||||||
private IBinder mAnimatingTransition = null;
|
private IBinder mAnimatingTransition = null;
|
||||||
OneShotRemoteHandler mPendingRemoteHandler = null;
|
OneShotRemoteHandler mPendingRemoteHandler = null;
|
||||||
private OneShotRemoteHandler mActiveRemoteHandler = null;
|
private OneShotRemoteHandler mActiveRemoteHandler = null;
|
||||||
private boolean mEnterTransitionMerged;
|
|
||||||
|
|
||||||
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
|
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
|
||||||
|
|
||||||
@@ -145,7 +144,7 @@ class SplitScreenTransitions {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transition == mPendingEnter && (mainRoot.equals(change.getContainer())
|
if (isPendingEnter(transition) && (mainRoot.equals(change.getContainer())
|
||||||
|| sideRoot.equals(change.getContainer()))) {
|
|| sideRoot.equals(change.getContainer()))) {
|
||||||
t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
|
t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
|
||||||
t.setWindowCrop(leash, change.getEndAbsBounds().width(),
|
t.setWindowCrop(leash, change.getEndAbsBounds().width(),
|
||||||
@@ -171,12 +170,40 @@ class SplitScreenTransitions {
|
|||||||
onFinish(null /* wct */, null /* wctCB */);
|
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. */
|
/** Starts a transition to enter split with a remote transition animator. */
|
||||||
IBinder startEnterTransition(@WindowManager.TransitionType int transitType,
|
IBinder startEnterTransition(
|
||||||
@NonNull WindowContainerTransaction wct, @Nullable RemoteTransition remoteTransition,
|
@WindowManager.TransitionType int transitType,
|
||||||
@NonNull Transitions.TransitionHandler handler) {
|
WindowContainerTransaction wct,
|
||||||
|
@Nullable RemoteTransition remoteTransition,
|
||||||
|
Transitions.TransitionHandler handler,
|
||||||
|
@Nullable TransitionCallback callback) {
|
||||||
final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
|
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) {
|
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)
|
||||||
@@ -184,7 +211,9 @@ class SplitScreenTransitions {
|
|||||||
mTransitions.getMainExecutor(), remoteTransition);
|
mTransitions.getMainExecutor(), remoteTransition);
|
||||||
mPendingRemoteHandler.setTransition(transition);
|
mPendingRemoteHandler.setTransition(transition);
|
||||||
}
|
}
|
||||||
return transition;
|
|
||||||
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
|
||||||
|
+ " deduced Enter split screen");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts a transition to dismiss split. */
|
/** Starts a transition to dismiss split. */
|
||||||
@@ -209,8 +238,8 @@ class SplitScreenTransitions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setRecentTransition(@NonNull IBinder transition,
|
void setRecentTransition(@NonNull IBinder transition,
|
||||||
@Nullable RemoteTransition remoteTransition) {
|
@Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) {
|
||||||
mPendingRecent = transition;
|
mPendingRecent = new TransitSession(transition, callback);
|
||||||
|
|
||||||
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)
|
||||||
@@ -226,6 +255,18 @@ class SplitScreenTransitions {
|
|||||||
void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
|
void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
|
||||||
IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
|
IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
|
||||||
if (mergeTarget != mAnimatingTransition) return;
|
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) {
|
if (mActiveRemoteHandler != null) {
|
||||||
mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
|
mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
|
||||||
} else {
|
} else {
|
||||||
@@ -247,38 +288,55 @@ class SplitScreenTransitions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onTransitionConsumed(@NonNull IBinder transition, boolean aborted) {
|
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
|
mPendingEnter.mCallback.onTransitionConsumed(aborted);
|
||||||
// operations to the finish transition.
|
|
||||||
if (transition == mPendingEnter) {
|
|
||||||
mFinishTransaction = mTransactionPool.acquire();
|
|
||||||
mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
|
|
||||||
mPendingEnter = null;
|
mPendingEnter = null;
|
||||||
mPendingRemoteHandler = 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) {
|
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
|
||||||
if (!mAnimations.isEmpty()) return;
|
if (!mAnimations.isEmpty()) return;
|
||||||
if (mAnimatingTransition == mPendingEnter) {
|
|
||||||
|
TransitionCallback callback = null;
|
||||||
|
if (isPendingEnter(mAnimatingTransition)) {
|
||||||
|
callback = mPendingEnter.mCallback;
|
||||||
mPendingEnter = null;
|
mPendingEnter = null;
|
||||||
}
|
}
|
||||||
if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
|
if (isPendingDismiss(mAnimatingTransition)) {
|
||||||
|
callback = mPendingDismiss.mCallback;
|
||||||
mPendingDismiss = null;
|
mPendingDismiss = null;
|
||||||
}
|
}
|
||||||
if (mAnimatingTransition == mPendingRecent) {
|
if (isPendingRecent(mAnimatingTransition)) {
|
||||||
if (!mEnterTransitionMerged) {
|
callback = mPendingRecent.mCallback;
|
||||||
if (wct == null) wct = new WindowContainerTransaction();
|
|
||||||
mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction);
|
|
||||||
}
|
|
||||||
mPendingRecent = null;
|
mPendingRecent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callback != null) {
|
||||||
|
if (wct == null) wct = new WindowContainerTransaction();
|
||||||
|
callback.onTransitionFinished(wct, mFinishTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
mPendingRemoteHandler = null;
|
mPendingRemoteHandler = null;
|
||||||
mActiveRemoteHandler = null;
|
mActiveRemoteHandler = null;
|
||||||
mAnimatingTransition = null;
|
mAnimatingTransition = null;
|
||||||
mEnterTransitionMerged = false;
|
|
||||||
|
|
||||||
mOnFinish.run();
|
mOnFinish.run();
|
||||||
if (mFinishTransaction != null) {
|
if (mFinishTransaction != null) {
|
||||||
@@ -382,17 +440,34 @@ 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. */
|
||||||
|
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. */
|
/** Bundled information of dismiss transition. */
|
||||||
static class DismissTransition {
|
static class DismissTransition extends TransitSession {
|
||||||
IBinder mTransition;
|
final int mReason;
|
||||||
|
final @SplitScreen.StageType int mDismissTop;
|
||||||
int mReason;
|
|
||||||
|
|
||||||
@SplitScreen.StageType
|
|
||||||
int mDismissTop;
|
|
||||||
|
|
||||||
DismissTransition(IBinder transition, int reason, int dismissTop) {
|
DismissTransition(IBinder transition, int reason, int dismissTop) {
|
||||||
this.mTransition = transition;
|
super(transition, null /* callback */);
|
||||||
this.mReason = reason;
|
this.mReason = reason;
|
||||||
this.mDismissTop = dismissTop;
|
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_HOME;
|
||||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
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.Display.DEFAULT_DISPLAY;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
|
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
|
||||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
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,
|
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
|
||||||
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
|
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
|
||||||
DisplayImeController displayImeController,
|
DisplayImeController displayImeController,
|
||||||
@@ -337,15 +365,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
|
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
|
||||||
targetStage.evictAllChildren(evictWct);
|
targetStage.evictAllChildren(evictWct);
|
||||||
targetStage.addTask(task, wct);
|
targetStage.addTask(task, wct);
|
||||||
if (!evictWct.isEmpty()) {
|
|
||||||
wct.merge(evictWct, true /* transfer */);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ENABLE_SHELL_TRANSITIONS) {
|
if (ENABLE_SHELL_TRANSITIONS) {
|
||||||
prepareEnterSplitScreen(wct);
|
prepareEnterSplitScreen(wct);
|
||||||
mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE,
|
mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct,
|
||||||
wct, null, this);
|
null, this, new SplitScreenTransitions.TransitionCallback() {
|
||||||
|
@Override
|
||||||
|
public void onTransitionFinished(WindowContainerTransaction finishWct,
|
||||||
|
SurfaceControl.Transaction finishT) {
|
||||||
|
if (!evictWct.isEmpty()) {
|
||||||
|
finishWct.merge(evictWct, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
|
if (!evictWct.isEmpty()) {
|
||||||
|
wct.merge(evictWct, true /* transfer */);
|
||||||
|
}
|
||||||
mTaskOrganizer.applyTransaction(wct);
|
mTaskOrganizer.applyTransaction(wct);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -365,6 +401,39 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
return result;
|
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. */
|
/** Starts 2 tasks in one transition. */
|
||||||
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
|
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
|
||||||
@Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
|
@Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
|
||||||
@@ -395,7 +464,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
wct.startTask(sideTaskId, sideOptions);
|
wct.startTask(sideTaskId, sideOptions);
|
||||||
|
|
||||||
mSplitTransitions.startEnterTransition(
|
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. */
|
/** Starts 2 tasks in one legacy transition. */
|
||||||
@@ -617,11 +686,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int getTaskId(@SplitPosition int splitPosition) {
|
int getTaskId(@SplitPosition int splitPosition) {
|
||||||
if (mSideStagePosition == splitPosition) {
|
if (splitPosition == SPLIT_POSITION_UNDEFINED) {
|
||||||
return mSideStage.getTopVisibleChildTaskId();
|
return INVALID_TASK_ID;
|
||||||
} else {
|
|
||||||
return mMainStage.getTopVisibleChildTaskId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return mSideStagePosition == splitPosition
|
||||||
|
? mSideStage.getTopVisibleChildTaskId()
|
||||||
|
: mMainStage.getTopVisibleChildTaskId();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) {
|
void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) {
|
||||||
@@ -861,6 +932,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
mSplitLayout.init();
|
mSplitLayout.init();
|
||||||
setDividerVisibility(true, t);
|
setDividerVisibility(true, t);
|
||||||
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
|
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
|
||||||
|
t.show(mRootTaskLeash);
|
||||||
setSplitsVisible(true);
|
setSplitsVisible(true);
|
||||||
mShouldUpdateRecents = true;
|
mShouldUpdateRecents = true;
|
||||||
updateRecentTasksSplitPair();
|
updateRecentTasksSplitPair();
|
||||||
@@ -1543,14 +1615,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
} else if (activityType == ACTIVITY_TYPE_HOME
|
} else if (activityType == ACTIVITY_TYPE_HOME
|
||||||
|| 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,
|
mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(),
|
||||||
request.getRemoteTransition());
|
mRecentTransitionCallback);
|
||||||
} 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.
|
||||||
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
|
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
|
||||||
mSplitTransitions.setDismissTransition(transition,
|
mSplitTransitions.setDismissTransition(
|
||||||
STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
|
transition, STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1558,7 +1630,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.mPendingEnter = transition;
|
mSplitTransitions.setEnterTransition(
|
||||||
|
transition, request.getRemoteTransition(), null /* callback */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@@ -1614,10 +1687,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
@NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull SurfaceControl.Transaction startTransaction,
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction,
|
@NonNull SurfaceControl.Transaction finishTransaction,
|
||||||
@NonNull Transitions.TransitionFinishCallback finishCallback) {
|
@NonNull Transitions.TransitionFinishCallback finishCallback) {
|
||||||
if (transition != mSplitTransitions.mPendingEnter
|
if (!mSplitTransitions.isPendingTransition(transition)) {
|
||||||
&& transition != mSplitTransitions.mPendingRecent
|
|
||||||
&& (mSplitTransitions.mPendingDismiss == null
|
|
||||||
|| mSplitTransitions.mPendingDismiss.mTransition != transition)) {
|
|
||||||
// Not entering or exiting, so just do some house-keeping and validation.
|
// 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.
|
// 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;
|
boolean shouldAnimate = true;
|
||||||
if (mSplitTransitions.mPendingEnter == transition) {
|
if (mSplitTransitions.isPendingEnter(transition)) {
|
||||||
shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
|
shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
|
||||||
} else if (mSplitTransitions.mPendingRecent == transition) {
|
} else if (mSplitTransitions.isPendingRecent(transition)) {
|
||||||
shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
|
shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
|
||||||
} else if (mSplitTransitions.mPendingDismiss != null
|
} else if (mSplitTransitions.isPendingDismiss(transition)) {
|
||||||
&& mSplitTransitions.mPendingDismiss.mTransition == transition) {
|
|
||||||
shouldAnimate = startPendingDismissAnimation(
|
shouldAnimate = startPendingDismissAnimation(
|
||||||
mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
|
mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
|
||||||
}
|
}
|
||||||
@@ -1837,28 +1906,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
return true;
|
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,
|
private void addDividerBarToTransition(@NonNull TransitionInfo info,
|
||||||
@NonNull SurfaceControl.Transaction t, boolean show) {
|
@NonNull SurfaceControl.Transaction t, boolean show) {
|
||||||
final SurfaceControl leash = mSplitLayout.getDividerLeash();
|
final SurfaceControl leash = mSplitLayout.getDividerLeash();
|
||||||
|
|||||||
@@ -182,7 +182,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);
|
new RemoteTransition(testRemote), mStageCoordinator, 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,
|
||||||
@@ -422,7 +422,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);
|
new RemoteTransition(new TestRemoteTransition()), mStageCoordinator, 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,
|
||||||
|
|||||||
Reference in New Issue
Block a user