Aggregate stage-split operations into WCT

Previously different operations were just applying transactions
as they were called. We need better control over this for
synchronization purposes, so we basically pass wct into these
operations so that everything can be aggregated into one WCT
if desired.

Bug: 192291727
Test: existing tests pass (this is a refactor)
Change-Id: Ie26d634bcd3ab6baf4d2a4788986689914a58c13
This commit is contained in:
Evan Rosky
2021-07-14 17:15:39 -07:00
parent 2e5a48be0e
commit e9f13e1341
2 changed files with 64 additions and 36 deletions

View File

@@ -147,7 +147,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
public void setSideStagePosition(@SplitPosition int sideStagePosition) {
mStageCoordinator.setSideStagePosition(sideStagePosition);
mStageCoordinator.setSideStagePosition(sideStagePosition, null /* wct */);
}
public void setSideStageVisibility(boolean visible) {
@@ -185,7 +185,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
public void startTask(int taskId, @SplitScreen.StageType int stage,
@SplitPosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
options = resolveStartStage(stage, position, options, null /* wct */);
try {
ActivityTaskManager.getService().startActivityFromRecents(taskId, options);
@@ -197,7 +197,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
public void startShortcut(String packageName, String shortcutId,
@SplitScreen.StageType int stage, @SplitPosition int position,
@Nullable Bundle options, UserHandle user) {
options = resolveStartStage(stage, position, options);
options = resolveStartStage(stage, position, options, null /* wct */);
try {
LauncherApps launcherApps =
@@ -222,32 +222,33 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
private Bundle resolveStartStage(@SplitScreen.StageType int stage,
@SplitPosition int position, @Nullable Bundle options) {
@SplitPosition int position, @Nullable Bundle options,
@Nullable WindowContainerTransaction wct) {
switch (stage) {
case STAGE_TYPE_UNDEFINED: {
// Use the stage of the specified position is valid.
if (position != SPLIT_POSITION_UNDEFINED) {
if (position == mStageCoordinator.getSideStagePosition()) {
options = resolveStartStage(STAGE_TYPE_SIDE, position, options);
options = resolveStartStage(STAGE_TYPE_SIDE, position, options, wct);
} else {
options = resolveStartStage(STAGE_TYPE_MAIN, position, options);
options = resolveStartStage(STAGE_TYPE_MAIN, position, options, wct);
}
} else {
// Exit split-screen and launch fullscreen since stage wasn't specified.
mStageCoordinator.exitSplitScreen();
mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
}
break;
}
case STAGE_TYPE_SIDE: {
if (position != SPLIT_POSITION_UNDEFINED) {
mStageCoordinator.setSideStagePosition(position);
mStageCoordinator.setSideStagePosition(position, wct);
} else {
position = mStageCoordinator.getSideStagePosition();
}
if (options == null) {
options = new Bundle();
}
mStageCoordinator.updateActivityOptions(options, position);
mStageCoordinator.updateActivityOptions(options, position, wct);
break;
}
case STAGE_TYPE_MAIN: {
@@ -255,14 +256,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
// Set the side stage opposite of what we want to the main stage.
final int sideStagePosition = position == SPLIT_POSITION_TOP_OR_LEFT
? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
mStageCoordinator.setSideStagePosition(sideStagePosition);
mStageCoordinator.setSideStagePosition(sideStagePosition, wct);
} else {
position = mStageCoordinator.getMainStagePosition();
}
if (options == null) {
options = new Bundle();
}
mStageCoordinator.updateActivityOptions(options, position);
mStageCoordinator.updateActivityOptions(options, position, wct);
break;
}
default:

View File

@@ -211,7 +211,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
setSideStagePosition(sideStagePosition);
setSideStagePosition(sideStagePosition, wct);
mMainStage.activate(getMainStageBounds(), wct);
mSideStage.addTask(task, getSideStageBounds(), wct);
mTaskOrganizer.applyTransaction(wct);
@@ -243,7 +243,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final WindowContainerTransaction wct = new WindowContainerTransaction();
mainOptions = mainOptions != null ? mainOptions : new Bundle();
sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition);
setSideStagePosition(sidePosition, wct);
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
@@ -312,7 +312,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition);
setSideStagePosition(sidePosition, wct);
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
@@ -342,18 +342,24 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
}
void setSideStagePosition(@SplitPosition int sideStagePosition) {
setSideStagePosition(sideStagePosition, true /* updateBounds */);
void setSideStagePosition(@SplitPosition int sideStagePosition,
@Nullable WindowContainerTransaction wct) {
setSideStagePosition(sideStagePosition, true /* updateBounds */, wct);
}
private void setSideStagePosition(@SplitPosition int sideStagePosition,
boolean updateBounds) {
boolean updateBounds, @Nullable WindowContainerTransaction wct) {
if (mSideStagePosition == sideStagePosition) return;
mSideStagePosition = sideStagePosition;
sendOnStagePositionChanged();
if (mSideStageListener.mVisible && updateBounds) {
onBoundsChanged(mSplitLayout);
if (wct == null) {
// onBoundsChanged builds/applies a wct with the contents of updateWindowBounds.
onBoundsChanged(mSplitLayout);
} else {
updateWindowBounds(mSplitLayout, wct);
}
}
}
@@ -388,7 +394,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.resetDividerPosition();
}
private void prepareExitSplitScreen(@SplitScreen.StageType int stageToTop,
/**
* Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
* to be used when exiting split might be bundled with other window operations.
*/
void prepareExitSplitScreen(@SplitScreen.StageType int stageToTop,
@NonNull WindowContainerTransaction wct) {
mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
@@ -403,15 +414,21 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
}
void updateActivityOptions(Bundle opts, @SplitPosition int position) {
void updateActivityOptions(Bundle opts, @SplitPosition int position,
@Nullable WindowContainerTransaction wct) {
addActivityOptions(opts, position == mSideStagePosition ? mSideStage : mMainStage);
if (!mMainStage.isActive()) {
// Activate the main stage in anticipation of an app launch.
final WindowContainerTransaction wct = new WindowContainerTransaction();
boolean needsApply = wct == null;
if (needsApply) {
wct = new WindowContainerTransaction();
}
mMainStage.activate(getMainStageBounds(), wct);
mSideStage.setBounds(getSideStageBounds(), wct);
mTaskOrganizer.applyTransaction(wct);
if (needsApply) {
mTaskOrganizer.applyTransaction(wct);
}
}
}
@@ -624,32 +641,41 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onDoubleTappedDivider() {
setSideStagePosition(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT);
? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT, null /* wct */);
}
@Override
public void onBoundsChanging(SplitLayout layout) {
final StageTaskListener topLeftStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
final StageTaskListener bottomRightStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, topLeftStage.mRootLeash,
bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer));
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
}
@Override
public void onBoundsChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateWindowBounds(layout, wct);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
}
/**
* Populates `wct` with operations that match the split windows to the current layout.
* To match relevant surfaces, make sure to call updateSurfaceBounds after `wct` is applied
*/
private void updateWindowBounds(SplitLayout layout, WindowContainerTransaction wct) {
final StageTaskListener topLeftStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
final StageTaskListener bottomRightStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
final WindowContainerTransaction wct = new WindowContainerTransaction();
layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo, bottomRightStage.mRootTaskInfo);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, topLeftStage.mRootLeash,
bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer));
}
void updateSurfaceBounds(@Nullable SplitLayout layout, @NonNull SurfaceControl.Transaction t) {
final StageTaskListener topLeftStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
final StageTaskListener bottomRightStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
(layout != null ? layout : mSplitLayout).applySurfaceChanges(t, topLeftStage.mRootLeash,
bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer);
}
@Override
@@ -869,7 +895,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Update local states (before animating).
setDividerVisibility(true);
setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateBounds */);
setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateBounds */,
null /* wct */);
setSplitsVisible(true);
addDividerBarToTransition(info, t, true /* show */);