Merge "Exit split when fold only if user interacted" into udc-qpr-dev

This commit is contained in:
Tony Huang
2023-07-07 08:08:51 +00:00
committed by Android (Google) Code Review
5 changed files with 64 additions and 27 deletions

View File

@@ -219,6 +219,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private boolean mIsDropEntering;
private boolean mIsExiting;
private boolean mIsRootTranslucent;
@VisibleForTesting
int mTopStageAfterFoldDismiss;
private DefaultMixedHandler mMixedHandler;
private final Toast mSplitUnsupportedToast;
@@ -1310,6 +1312,24 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
// Dismiss split if the flag record any side of stages.
if (mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
if (ENABLE_SHELL_TRANSITIONS) {
// Need manually clear here due to this transition might be aborted due to keyguard
// on top and lead to no visible change.
clearSplitPairedInRecents(EXIT_REASON_DEVICE_FOLDED);
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
mSplitTransitions.startDismissTransition(wct, this,
mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
} else {
exitSplitScreen(
mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
EXIT_REASON_DEVICE_FOLDED);
}
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
}
void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
@@ -1346,15 +1366,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!mMainStage.isActive() || mIsExiting) return;
onSplitScreenExit();
clearSplitPairedInRecents(exitReason);
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(exitReason) && mShouldUpdateRecents) {
recentTasks.removeSplitPair(mMainStage.getTopVisibleChildTaskId());
recentTasks.removeSplitPair(mSideStage.getTopVisibleChildTaskId());
}
});
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = false;
mSplitRequest = null;
@@ -1481,6 +1494,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
private void clearSplitPairedInRecents(@ExitReason int exitReason) {
if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
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
mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
});
}
/**
* Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
@@ -2208,7 +2232,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
void updateSurfaces(SurfaceControl.Transaction transaction) {
/**
* Update surfaces of the split screen layout based on the current state
* @param transaction to write the updates to
*/
public void updateSurfaces(SurfaceControl.Transaction transaction) {
updateSurfaceBounds(mSplitLayout, transaction, /* applyResizingOffset */ false);
mSplitLayout.update(transaction);
}
@@ -2227,26 +2255,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@VisibleForTesting
void onFoldedStateChanged(boolean folded) {
int topStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
if (!folded) return;
if (!mMainStage.isActive()) return;
if (!isSplitActive() || !isSplitScreenVisible()) return;
// To avoid split dismiss when user fold the device and unfold to use later, we only
// record the flag here and try to dismiss on wakeUp callback to ensure split dismiss
// when user interact on phone folded.
if (mMainStage.isFocused()) {
topStageAfterFoldDismiss = STAGE_TYPE_MAIN;
mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
} else if (mSideStage.isFocused()) {
topStageAfterFoldDismiss = STAGE_TYPE_SIDE;
}
if (ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(topStageAfterFoldDismiss, wct);
mSplitTransitions.startDismissTransition(wct, this,
topStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
} else {
exitSplitScreen(
topStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
EXIT_REASON_DEVICE_FOLDED);
mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
}
}

View File

@@ -55,6 +55,7 @@ import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -347,6 +348,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */);
}
void doForAllChildTasks(Consumer<Integer> consumer) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
consumer.accept(taskInfo.taskId);
}
}
/** Collects all the current child tasks and prepares transaction to evict them to display. */
void evictAllChildren(WindowContainerTransaction wct) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {

View File

@@ -704,6 +704,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
if (mPipHandler != null) {
mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
}
if (mSplitHandler != null && mSplitHandler.isSplitActive()) {
mSplitHandler.updateSurfaces(startTransaction);
}
return mUnfoldHandler.startAnimation(
mixed.mTransition, info, startTransaction, finishTransaction, finishCB);
}

View File

@@ -270,7 +270,6 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator,
@Override
public void prepareStartTransaction(Transaction transaction) {
mUnfoldBackgroundController.ensureBackground(transaction);
mSplitScreenController.get().get().updateSplitScreenSurfaces(transaction);
}
@Override

View File

@@ -347,13 +347,20 @@ public class StageCoordinatorTests extends ShellTestCase {
}
@Test
public void testExitSplitScreenAfterFolded() {
when(mMainStage.isActive()).thenReturn(true);
public void testExitSplitScreenAfterFoldedAndWakeUp() {
when(mMainStage.isFocused()).thenReturn(true);
when(mMainStage.getTopVisibleChildTaskId()).thenReturn(INVALID_TASK_ID);
mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build();
mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build();
when(mStageCoordinator.isSplitActive()).thenReturn(true);
when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
mStageCoordinator.onFoldedStateChanged(true);
assertEquals(mStageCoordinator.mTopStageAfterFoldDismiss, STAGE_TYPE_MAIN);
mStageCoordinator.onFinishedWakingUp();
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
verify(mTaskOrganizer).startNewTransition(eq(TRANSIT_SPLIT_DISMISS), notNull());
} else {