Merge "Improve pip to split transition" into tm-qpr-dev am: 95eb72f9fb

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21923605

Change-Id: I7472d56e9be0ed5890216869fc47376d66be7310
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Tony Huang
2023-03-21 03:37:22 +00:00
committed by Automerger Merge Worker
4 changed files with 79 additions and 80 deletions

View File

@@ -1481,9 +1481,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
applyFinishBoundsResize(wct, direction, false); applyFinishBoundsResize(wct, direction, false);
} }
} else { } else {
final boolean isPipTopLeft = applyFinishBoundsResize(wct, direction, isPipToTopLeft());
direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft(); // Use sync transaction to apply finish transaction for enter split case.
applyFinishBoundsResize(wct, direction, isPipTopLeft); if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
mSyncTransactionQueue.runInSync(t -> {
t.merge(tx);
});
}
} }
finishResizeForMenu(destinationBounds); finishResizeForMenu(destinationBounds);
@@ -1520,7 +1524,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceTransactionHelper.round(tx, mLeash, isInPip()); mSurfaceTransactionHelper.round(tx, mLeash, isInPip());
wct.setBounds(mToken, taskBounds); wct.setBounds(mToken, taskBounds);
wct.setBoundsChangeTransaction(mToken, tx); // Pip to split should use sync transaction to sync split bounds change.
if (direction != TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.setBoundsChangeTransaction(mToken, tx);
}
} }
/** /**

View File

@@ -31,7 +31,6 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit; import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition; import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage; import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage;
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.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -89,7 +88,6 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.draganddrop.DragAndDropPolicy; import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellController;
@@ -339,8 +337,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
} }
public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) { public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition, return moveToStage(taskId, sideStagePosition, new WindowContainerTransaction());
new WindowContainerTransaction());
} }
/** /**
@@ -351,13 +348,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.updateSurfaces(transaction); mStageCoordinator.updateSurfaces(transaction);
} }
private boolean moveToStage(int taskId, @StageType int stageType, private boolean moveToStage(int taskId, @SplitPosition int stagePosition,
@SplitPosition int stagePosition, WindowContainerTransaction wct) { WindowContainerTransaction wct) {
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId); final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
if (task == null) { if (task == null) {
throw new IllegalArgumentException("Unknown taskId" + taskId); throw new IllegalArgumentException("Unknown taskId" + taskId);
} }
return mStageCoordinator.moveToStage(task, stageType, stagePosition, wct); return mStageCoordinator.moveToStage(task, stagePosition, wct);
} }
public boolean removeFromSideStage(int taskId) { public boolean removeFromSideStage(int taskId) {
@@ -382,10 +379,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
} }
public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) { public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
final int stagePosition = final int stagePosition =
leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT; leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
moveToStage(taskId, stageType, stagePosition, wct); moveToStage(taskId, stagePosition, wct);
} }
public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) { public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {

View File

@@ -399,56 +399,43 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return STAGE_TYPE_UNDEFINED; return STAGE_TYPE_UNDEFINED;
} }
boolean moveToStage(ActivityManager.RunningTaskInfo task, @StageType int stageType, boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
@SplitPosition int stagePosition, WindowContainerTransaction wct) { WindowContainerTransaction wct) {
StageTaskListener targetStage; StageTaskListener targetStage;
int sideStagePosition; int sideStagePosition;
if (stageType == STAGE_TYPE_MAIN) { if (isSplitScreenVisible()) {
targetStage = mMainStage; // If the split screen is foreground, retrieves target stage based on position.
sideStagePosition = reverseSplitPosition(stagePosition); targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
} else if (stageType == STAGE_TYPE_SIDE) { sideStagePosition = mSideStagePosition;
} else {
targetStage = mSideStage; targetStage = mSideStage;
sideStagePosition = stagePosition; sideStagePosition = stagePosition;
} else {
if (isSplitScreenVisible()) {
// If the split screen is activated, retrieves target stage based on position.
targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
sideStagePosition = mSideStagePosition;
} else {
// Exit split if it running background.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
targetStage = mSideStage;
sideStagePosition = stagePosition;
}
} }
if (!isSplitActive()) { if (!isSplitActive()) {
// prevent the fling divider to center transitioni if split screen didn't active. mSplitLayout.init();
mIsDropEntering = true; prepareEnterSplitScreen(wct, task, stagePosition);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
});
} else {
setSideStagePosition(sideStagePosition, wct);
targetStage.addTask(task, wct);
targetStage.evictAllChildren(wct);
if (!isSplitScreenVisible()) {
final StageTaskListener anotherStage = targetStage == mMainStage
? mSideStage : mMainStage;
anotherStage.reparentTopTask(wct);
anotherStage.evictAllChildren(wct);
wct.reorder(mRootTaskInfo.token, true);
}
setRootForceTranslucent(false, wct);
mSyncQueue.queue(wct);
} }
setSideStagePosition(sideStagePosition, wct); // Due to drag already pip task entering split by this method so need to reset flag here.
final WindowContainerTransaction evictWct = new WindowContainerTransaction(); mIsDropEntering = false;
targetStage.evictAllChildren(evictWct);
// Apply surface bounds before animation start.
SurfaceControl.Transaction startT = mTransactionPool.acquire();
if (startT != null) {
updateSurfaceBounds(mSplitLayout, startT, false /* applyResizingOffset */);
startT.apply();
mTransactionPool.release(startT);
}
// reparent the task to an invisible split root will make the activity invisible. Reorder
// the root task to front to make the entering transition from pip to split smooth.
wct.reorder(mRootTaskInfo.token, true);
wct.reorder(targetStage.mRootTaskInfo.token, true);
targetStage.addTask(task, wct);
if (!evictWct.isEmpty()) {
wct.merge(evictWct, true /* transfer */);
}
mTaskOrganizer.applyTransaction(wct);
return true; return true;
} }

View File

@@ -144,39 +144,48 @@ public class StageCoordinatorTests extends ShellTestCase {
} }
@Test @Test
public void testMoveToStage() { public void testMoveToStage_splitActiveBackground() {
when(mStageCoordinator.isSplitActive()).thenReturn(true);
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.moveToStage(task, STAGE_TYPE_MAIN, SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
new WindowContainerTransaction()); verify(mSideStage).addTask(eq(task), eq(wct));
verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
mStageCoordinator.moveToStage(task, STAGE_TYPE_SIDE, SPLIT_POSITION_BOTTOM_OR_RIGHT,
new WindowContainerTransaction());
verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition()); assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
} }
@Test @Test
public void testMoveToUndefinedStage() { public void testMoveToStage_splitActiveForeground() {
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); when(mStageCoordinator.isSplitActive()).thenReturn(true);
// Verify move to undefined stage while split screen not activated moves task to side stage.
when(mStageCoordinator.isSplitScreenVisible()).thenReturn(false);
mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_BOTTOM_OR_RIGHT,
new WindowContainerTransaction());
verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
// Verify move to undefined stage after split screen activated moves task based on position.
when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true); when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition()); // Assume current side stage is top or left.
mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
new WindowContainerTransaction());
verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class)); final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition()); final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
verify(mMainStage).addTask(eq(task), eq(wct));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
mStageCoordinator.moveToStage(task, SPLIT_POSITION_TOP_OR_LEFT, wct);
verify(mSideStage).addTask(eq(task), eq(wct));
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
}
@Test
public void testMoveToStage_splitInctive() {
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
} }
@Test @Test