Improve pip to split transition
When pip to split, flicker usually occured due to the surface reset transaction applied too late and cuase double offset lead to surface outside of display then cause flicker. Fix it by using sync transaction, and also try to do this transition in a WCT rather than two. (Before this CL, we will add pip task to split root as one WCT, and active split as another WCT). Fix: 272446831 Test: manual Test: pass existing tests Change-Id: I6d59bd4084862e15a337c755cbad73d26a71e5aa
This commit is contained in:
@@ -1481,9 +1481,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
applyFinishBoundsResize(wct, direction, false);
|
||||
}
|
||||
} else {
|
||||
final boolean isPipTopLeft =
|
||||
direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft();
|
||||
applyFinishBoundsResize(wct, direction, isPipTopLeft);
|
||||
applyFinishBoundsResize(wct, direction, isPipToTopLeft());
|
||||
// Use sync transaction to apply finish transaction for enter split case.
|
||||
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
|
||||
mSyncTransactionQueue.runInSync(t -> {
|
||||
t.merge(tx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
finishResizeForMenu(destinationBounds);
|
||||
@@ -1520,7 +1524,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
mSurfaceTransactionHelper.round(tx, mLeash, isInPip());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.reverseSplitPosition;
|
||||
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.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
|
||||
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.protolog.ShellProtoLogGroup;
|
||||
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.ShellCommandHandler;
|
||||
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) {
|
||||
return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
|
||||
new WindowContainerTransaction());
|
||||
return moveToStage(taskId, sideStagePosition, new WindowContainerTransaction());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,13 +348,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
||||
mStageCoordinator.updateSurfaces(transaction);
|
||||
}
|
||||
|
||||
private boolean moveToStage(int taskId, @StageType int stageType,
|
||||
@SplitPosition int stagePosition, WindowContainerTransaction wct) {
|
||||
private boolean moveToStage(int taskId, @SplitPosition int stagePosition,
|
||||
WindowContainerTransaction wct) {
|
||||
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException("Unknown taskId" + taskId);
|
||||
}
|
||||
return mStageCoordinator.moveToStage(task, stageType, stagePosition, wct);
|
||||
return mStageCoordinator.moveToStage(task, stagePosition, wct);
|
||||
}
|
||||
|
||||
public boolean removeFromSideStage(int taskId) {
|
||||
@@ -382,10 +379,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
||||
}
|
||||
|
||||
public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
|
||||
final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
|
||||
final int stagePosition =
|
||||
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) {
|
||||
|
||||
@@ -399,56 +399,43 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
return STAGE_TYPE_UNDEFINED;
|
||||
}
|
||||
|
||||
boolean moveToStage(ActivityManager.RunningTaskInfo task, @StageType int stageType,
|
||||
@SplitPosition int stagePosition, WindowContainerTransaction wct) {
|
||||
boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
|
||||
WindowContainerTransaction wct) {
|
||||
StageTaskListener targetStage;
|
||||
int sideStagePosition;
|
||||
if (stageType == STAGE_TYPE_MAIN) {
|
||||
targetStage = mMainStage;
|
||||
sideStagePosition = reverseSplitPosition(stagePosition);
|
||||
} else if (stageType == STAGE_TYPE_SIDE) {
|
||||
if (isSplitScreenVisible()) {
|
||||
// If the split screen is foreground, retrieves target stage based on position.
|
||||
targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
|
||||
sideStagePosition = mSideStagePosition;
|
||||
} else {
|
||||
targetStage = mSideStage;
|
||||
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()) {
|
||||
// prevent the fling divider to center transitioni if split screen didn't active.
|
||||
mIsDropEntering = true;
|
||||
mSplitLayout.init();
|
||||
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);
|
||||
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
|
||||
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);
|
||||
// Due to drag already pip task entering split by this method so need to reset flag here.
|
||||
mIsDropEntering = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -144,39 +144,48 @@ public class StageCoordinatorTests extends ShellTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToStage() {
|
||||
public void testMoveToStage_splitActiveBackground() {
|
||||
when(mStageCoordinator.isSplitActive()).thenReturn(true);
|
||||
|
||||
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
|
||||
mStageCoordinator.moveToStage(task, STAGE_TYPE_MAIN, SPLIT_POSITION_BOTTOM_OR_RIGHT,
|
||||
new WindowContainerTransaction());
|
||||
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));
|
||||
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
|
||||
verify(mSideStage).addTask(eq(task), eq(wct));
|
||||
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
|
||||
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToUndefinedStage() {
|
||||
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
|
||||
|
||||
// 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.
|
||||
public void testMoveToStage_splitActiveForeground() {
|
||||
when(mStageCoordinator.isSplitActive()).thenReturn(true);
|
||||
when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
|
||||
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
|
||||
mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_TOP_OR_LEFT,
|
||||
new WindowContainerTransaction());
|
||||
verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
|
||||
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
|
||||
// Assume current side stage is top or left.
|
||||
mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
|
||||
|
||||
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user