Merge "Integrate RecetsTaskController with shell-transition"

This commit is contained in:
Jerry Chang
2021-12-16 09:01:25 +00:00
committed by Android (Google) Code Review
6 changed files with 217 additions and 78 deletions

View File

@@ -23,6 +23,10 @@ import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -40,7 +44,9 @@ import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.Transitions;
@@ -57,7 +63,7 @@ class SplitScreenTransitions {
private final Transitions mTransitions;
private final Runnable mOnFinish;
IBinder mPendingDismiss = null;
DismissTransition mPendingDismiss = null;
IBinder mPendingEnter = null;
private IBinder mAnimatingTransition = null;
@@ -127,12 +133,6 @@ class SplitScreenTransitions {
}
// TODO(shell-transitions): screenshot here
final Rect startBounds = new Rect(change.getStartAbsBounds());
if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
// Dismissing split via snap which means the still-visible task has been
// dragged to its end position at animation start so reflect that here.
startBounds.offsetTo(change.getEndAbsBounds().left,
change.getEndAbsBounds().top);
}
final Rect endBounds = new Rect(change.getEndAbsBounds());
startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
@@ -184,12 +184,20 @@ class SplitScreenTransitions {
return transition;
}
/** Starts a transition for dismissing split after dragging the divider to a screen edge */
IBinder startSnapToDismiss(@NonNull WindowContainerTransaction wct,
@NonNull Transitions.TransitionHandler handler) {
final IBinder transition = mTransitions.startTransition(
TRANSIT_SPLIT_DISMISS_SNAP, wct, handler);
mPendingDismiss = transition;
/** Starts a transition to dismiss split. */
IBinder startDismissTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
Transitions.TransitionHandler handler, @SplitScreen.StageType int dismissTop,
@SplitScreenController.ExitReason int reason) {
final int type = reason == EXIT_REASON_DRAG_DIVIDER
? TRANSIT_SPLIT_DISMISS_SNAP : TRANSIT_SPLIT_DISMISS;
if (transition == null) {
transition = mTransitions.startTransition(type, wct, handler);
}
mPendingDismiss = new DismissTransition(transition, reason, dismissTop);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Dismiss due to %s. toTop=%s",
exitReasonToString(reason), stageTypeToString(dismissTop));
return transition;
}
@@ -206,7 +214,7 @@ class SplitScreenTransitions {
if (mAnimatingTransition == mPendingEnter) {
mPendingEnter = null;
}
if (mAnimatingTransition == mPendingDismiss) {
if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
mPendingDismiss = null;
}
mAnimatingTransition = null;
@@ -295,4 +303,20 @@ class SplitScreenTransitions {
mAnimations.add(va);
mTransitions.getAnimExecutor().execute(va::start);
}
/** Bundled information of dismiss transition. */
static class DismissTransition {
IBinder mTransition;
int mReason;
@SplitScreen.StageType
int mDismissTop;
DismissTransition(IBinder transition, int reason, int dismissTop) {
this.mTransition = transition;
this.mReason = reason;
this.mDismissTop = dismissTop;
}
}
}

View File

@@ -18,9 +18,10 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
@@ -32,7 +33,6 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
@@ -40,6 +40,7 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -121,9 +122,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private static final String TAG = StageCoordinator.class.getSimpleName();
/** internal value for mDismissTop that represents no dismiss */
private static final int NO_DISMISS = -2;
private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final MainStage mMainStage;
@@ -156,9 +154,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private boolean mKeyguardOccluded;
private boolean mDeviceSleep;
@StageType
private int mDismissTop = NO_DISMISS;
/** The target stage to dismiss to when unlock after folded. */
@StageType
private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
@@ -171,7 +166,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setDividerVisibility(false);
mSplitLayout.resetDividerPosition();
}
mDismissTop = NO_DISMISS;
};
private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
@@ -461,8 +455,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
options = resolveStartStage(STAGE_TYPE_SIDE, position, options, wct);
}
} else {
// Exit split-screen and launch fullscreen since stage wasn't specified.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
Slog.w(TAG,
"No stage type nor split position specified to resolve start stage");
}
break;
}
@@ -914,23 +908,22 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
@VisibleForTesting
IBinder onSnappedToDismissTransition(boolean mainStageToTop) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE, wct);
return mSplitTransitions.startSnapToDismiss(wct, this);
}
@Override
public void onSnappedToDismiss(boolean bottomOrRight) {
final boolean mainStageToTop =
bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
: mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
if (ENABLE_SHELL_TRANSITIONS) {
onSnappedToDismissTransition(mainStageToTop);
if (!ENABLE_SHELL_TRANSITIONS) {
exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, EXIT_REASON_DRAG_DIVIDER);
return;
}
exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, EXIT_REASON_DRAG_DIVIDER);
final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
mSplitTransitions.startDismissTransition(
null /* transition */, wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
}
@Override
@@ -1109,14 +1102,25 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Nullable TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
if (triggerTask == null) {
// still want to monitor everything while in split-screen, so return non-null.
// Still want to monitor everything while in split-screen, so return non-null.
return isSplitScreenVisible() ? new WindowContainerTransaction() : null;
} else if (triggerTask.displayId != mDisplayId) {
// Skip handling task on the other display.
return null;
}
WindowContainerTransaction out = null;
final @WindowManager.TransitionType int type = request.getType();
final boolean isOpening = isOpeningType(type);
final boolean inFullscreen = triggerTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
if (isOpening && inFullscreen) {
// One task is opening into fullscreen mode, remove the corresponding split record.
mRecentTasks.ifPresent(recentTasks -> recentTasks.removeSplitPair(triggerTask.taskId));
}
if (isSplitScreenVisible()) {
// try to handle everything while in split-screen, so return a WCT even if it's empty.
// Try to handle everything while in split-screen, so return a WCT even if it's empty.
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " split is active so using split"
+ "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
+ " sideChildren=%d", triggerTask.taskId, transitTypeToString(type),
@@ -1124,35 +1128,35 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
out = new WindowContainerTransaction();
final StageTaskListener stage = getStageOfTask(triggerTask);
if (stage != null) {
// dismiss split if the last task in one of the stages is going away
// Dismiss split if the last task in one of the stages is going away
if (isClosingType(type) && stage.getChildCount() == 1) {
// The top should be the opposite side that is closing:
mDismissTop = getStageType(stage) == STAGE_TYPE_MAIN
? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN ? STAGE_TYPE_SIDE
: STAGE_TYPE_MAIN;
prepareExitSplitScreen(dismissTop, out);
mSplitTransitions.startDismissTransition(transition, out, this, dismissTop,
EXIT_REASON_APP_FINISHED);
}
} else {
if (triggerTask.getActivityType() == ACTIVITY_TYPE_HOME && isOpeningType(type)) {
// Going home so dismiss both.
mDismissTop = STAGE_TYPE_UNDEFINED;
} else if (isOpening && inFullscreen) {
final int activityType = triggerTask.getActivityType();
if (activityType == ACTIVITY_TYPE_ASSISTANT) {
// We don't want assistant panel to dismiss split screen, so do nothing.
} else {
// Going home or occluded by the other fullscreen task, so dismiss both.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
final int exitReason = activityType == ACTIVITY_TYPE_HOME
? EXIT_REASON_RETURN_HOME : EXIT_REASON_UNKNOWN;
mSplitTransitions.startDismissTransition(transition, out, this,
STAGE_TYPE_UNDEFINED, exitReason);
}
}
if (mDismissTop != NO_DISMISS) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Dismiss from request. toTop=%s",
stageTypeToString(mDismissTop));
prepareExitSplitScreen(mDismissTop, out);
mSplitTransitions.mPendingDismiss = transition;
}
} else {
// Not in split mode, so look for an open into a split stage to active split screen.
if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)) {
if (getStageOfTask(triggerTask) != null) {
// One task is appearing in split, prepare to enter split screen.
out = new WindowContainerTransaction();
mSplitTransitions.mPendingEnter = transition;
mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
mSideStage.moveToTop(getSideStageBounds(), out);
}
if (isOpening && getStageOfTask(triggerTask) != null) {
// One task is appearing into split, prepare to enter split screen.
out = new WindowContainerTransaction();
mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
mSideStage.moveToTop(getSideStageBounds(), out);
mSplitTransitions.mPendingEnter = transition;
}
}
return out;
@@ -1164,8 +1168,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (transition != mSplitTransitions.mPendingDismiss
&& transition != mSplitTransitions.mPendingEnter) {
if (transition != mSplitTransitions.mPendingEnter && (
mSplitTransitions.mPendingDismiss == null
|| mSplitTransitions.mPendingDismiss.mTransition != 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.
@@ -1208,8 +1213,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
boolean shouldAnimate = true;
if (mSplitTransitions.mPendingEnter == transition) {
shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
} else if (mSplitTransitions.mPendingDismiss == transition) {
shouldAnimate = startPendingDismissAnimation(transition, info, startTransaction);
} else if (mSplitTransitions.mPendingDismiss != null
&& mSplitTransitions.mPendingDismiss.mTransition == transition) {
shouldAnimate = startPendingDismissAnimation(
mSplitTransitions.mPendingDismiss, info, startTransaction);
}
if (!shouldAnimate) return false;
@@ -1263,10 +1270,22 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
+ " to have been called with " + sideChild.getTaskInfo().taskId
+ " before startAnimation().");
}
mShouldUpdateRecents = true;
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
getMainStagePosition(), mMainStage.getTopChildTaskUid(),
getSideStagePosition(), mSideStage.getTopChildTaskUid(),
mSplitLayout.isLandscape());
}
return true;
}
private boolean startPendingDismissAnimation(@NonNull IBinder transition,
private boolean startPendingDismissAnimation(
@NonNull SplitScreenTransitions.DismissTransition dismissTransition,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
// Make some noise if things aren't totally expected. These states shouldn't effect
// transitions locally, but remotes (like Launcher) may get confused if they were
@@ -1295,6 +1314,21 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
+ "] before startAnimation().");
}
mRecentTasks.ifPresent(recentTasks -> {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
if (shouldBreakPairedTaskInRecents(dismissTransition.mReason) && mShouldUpdateRecents) {
for (TransitionInfo.Change change : info.getChanges()) {
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo != null
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
recentTasks.removeSplitPair(taskInfo.taskId);
}
}
}
});
mShouldUpdateRecents = false;
// Update local states.
setSplitsVisible(false);
// Wait until after animation to update divider
@@ -1305,15 +1339,17 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.setWindowCrop(mSideStage.mRootLeash, null);
}
if (mDismissTop == STAGE_TYPE_UNDEFINED) {
// Going home (dismissing both splits)
if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
logExit(dismissTransition.mReason);
// TODO: Have a proper remote for this. Until then, though, reset state and use the
// normal animation stuff (which falls back to the normal launcher remote).
t.hide(mSplitLayout.getDividerLeash());
setDividerVisibility(false);
mSplitTransitions.mPendingDismiss = null;
return false;
} else {
logExitToStage(dismissTransition.mReason,
dismissTransition.mDismissTop == STAGE_TYPE_MAIN);
}
addDividerBarToTransition(info, t, false /* show */);
@@ -1457,7 +1493,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onNoLongerSupportMultiWindow() {
if (mMainStage.isActive()) {
StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
if (!ENABLE_SHELL_TRANSITIONS) {
StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
}
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
mSplitTransitions.startDismissTransition(null /* transition */, wct,
StageCoordinator.this, STAGE_TYPE_UNDEFINED,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
}
}

View File

@@ -127,12 +127,6 @@ class SplitScreenTransitions {
}
// TODO(shell-transitions): screenshot here
final Rect startBounds = new Rect(change.getStartAbsBounds());
if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
// Dismissing split via snap which means the still-visible task has been
// dragged to its end position at animation start so reflect that here.
startBounds.offsetTo(change.getEndAbsBounds().left,
change.getEndAbsBounds().top);
}
final Rect endBounds = new Rect(change.getEndAbsBounds());
startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);

View File

@@ -89,6 +89,9 @@ public class Transitions implements RemoteCallable<Transitions> {
/** Transition type for entering split by opening an app into side-stage. */
public static final int TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE = TRANSIT_FIRST_CUSTOM + 5;
/** Transition type for dismissing split-screen. */
public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 6;
private final WindowOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;

View File

@@ -18,6 +18,7 @@ package com.android.wm.shell;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -36,6 +37,7 @@ public final class TestRunningTaskInfoBuilder {
private WindowContainerToken mToken = createMockWCToken();
private int mParentTaskId = INVALID_TASK_ID;
private @WindowConfiguration.ActivityType int mActivityType = ACTIVITY_TYPE_STANDARD;
private @WindowConfiguration.WindowingMode int mWindowingMode = WINDOWING_MODE_UNDEFINED;
public static WindowContainerToken createMockWCToken() {
final IWindowContainerToken itoken = mock(IWindowContainerToken.class);
@@ -60,6 +62,12 @@ public final class TestRunningTaskInfoBuilder {
return this;
}
public TestRunningTaskInfoBuilder setWindowingMode(
@WindowConfiguration.WindowingMode int windowingMode) {
mWindowingMode = windowingMode;
return this;
}
public ActivityManager.RunningTaskInfo build() {
final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
info.parentTaskId = INVALID_TASK_ID;
@@ -67,6 +75,7 @@ public final class TestRunningTaskInfoBuilder {
info.parentTaskId = mParentTaskId;
info.configuration.windowConfiguration.setBounds(mBounds);
info.configuration.windowConfiguration.setActivityType(mActivityType);
info.configuration.windowConfiguration.setWindowingMode(mWindowingMode);
info.token = mToken;
info.isResizeable = true;
info.supportsMultiWindow = true;

View File

@@ -17,6 +17,7 @@
package com.android.wm.shell.splitscreen;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -26,6 +27,9 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitTestUtils.createMockSurface;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -249,7 +253,9 @@ public class SplitTransitionTests extends ShellTestCase {
enterSplit();
ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder()
.setActivityType(ACTIVITY_TYPE_HOME).build();
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
.setActivityType(ACTIVITY_TYPE_HOME)
.build();
// Create a request to bring home forward
TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, homeTask, null);
@@ -279,6 +285,64 @@ public class SplitTransitionTests extends ShellTestCase {
assertFalse(mStageCoordinator.isSplitScreenVisible());
}
@Test
public void testDismissFromBeingOccluded() {
enterSplit();
ActivityManager.RunningTaskInfo normalTask = new TestRunningTaskInfoBuilder()
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
.build();
// Create a request to bring a normal task forward
TransitionRequestInfo request =
new TransitionRequestInfo(TRANSIT_TO_FRONT, normalTask, null);
IBinder transition = mock(IBinder.class);
WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request);
assertTrue(containsSplitExit(result));
// make sure we haven't made any local changes yet (need to wait until transition is ready)
assertTrue(mStageCoordinator.isSplitScreenVisible());
// simulate the transition
TransitionInfo.Change normalChange = createChange(TRANSIT_TO_FRONT, normalTask);
TransitionInfo.Change mainChange = createChange(TRANSIT_TO_BACK, mMainChild);
TransitionInfo.Change sideChange = createChange(TRANSIT_TO_BACK, mSideChild);
TransitionInfo info = new TransitionInfo(TRANSIT_TO_FRONT, 0);
info.addChange(normalChange);
info.addChange(mainChange);
info.addChange(sideChange);
mMainStage.onTaskVanished(mMainChild);
mSideStage.onTaskVanished(mSideChild);
mStageCoordinator.startAnimation(transition, info,
mock(SurfaceControl.Transaction.class),
mock(SurfaceControl.Transaction.class),
mock(Transitions.TransitionFinishCallback.class));
assertFalse(mStageCoordinator.isSplitScreenVisible());
}
@Test
public void testDismissFromMultiWindowSupport() {
enterSplit();
// simulate the transition
TransitionInfo.Change mainChange = createChange(TRANSIT_TO_BACK, mMainChild);
TransitionInfo.Change sideChange = createChange(TRANSIT_TO_BACK, mSideChild);
TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
info.addChange(mainChange);
info.addChange(sideChange);
IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
new WindowContainerTransaction(), mStageCoordinator,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, STAGE_TYPE_SIDE);
boolean accepted = mStageCoordinator.startAnimation(transition, info,
mock(SurfaceControl.Transaction.class),
mock(SurfaceControl.Transaction.class),
mock(Transitions.TransitionFinishCallback.class));
assertTrue(accepted);
assertFalse(mStageCoordinator.isSplitScreenVisible());
}
@Test
public void testDismissSnap() {
enterSplit();
@@ -290,8 +354,9 @@ public class SplitTransitionTests extends ShellTestCase {
TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
info.addChange(mainChange);
info.addChange(sideChange);
IBinder transition = mStageCoordinator.onSnappedToDismissTransition(
false /* mainStageToTop */);
IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
new WindowContainerTransaction(), mStageCoordinator, EXIT_REASON_DRAG_DIVIDER,
STAGE_TYPE_SIDE);
mMainStage.onTaskVanished(mMainChild);
mSideStage.onTaskVanished(mSideChild);
boolean accepted = mStageCoordinator.startAnimation(transition, info,