Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +8 −3 Original line number Diff line number Diff line Loading @@ -240,8 +240,12 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static FullscreenTaskListener provideFullscreenTaskListener( SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> controller) { return new FullscreenTaskListener(syncQueue, controller); SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> optionalFullscreenUnfoldController, Optional<RecentTasksController> recentTasksOptional ) { return new FullscreenTaskListener(syncQueue, optionalFullscreenUnfoldController, recentTasksOptional); } // Loading Loading @@ -490,12 +494,13 @@ public abstract class WMShellBaseModule { DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) { if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context, rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, stageTaskUnfoldControllerProvider)); recentTasks, stageTaskUnfoldControllerProvider)); } else { return Optional.empty(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java +21 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; Loading @@ -47,15 +48,23 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = "FullscreenTaskListener"; private final SyncTransactionQueue mSyncQueue; private final FullscreenUnfoldController mFullscreenUnfoldController; private final Optional<RecentTasksController> mRecentTasksOptional; private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>(); private final AnimatableTasksListener mAnimatableTasksListener = new AnimatableTasksListener(); private final FullscreenUnfoldController mFullscreenUnfoldController; public FullscreenTaskListener(SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> unfoldController) { this(syncQueue, unfoldController, Optional.empty()); } public FullscreenTaskListener(SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> unfoldController, Optional<RecentTasksController> recentTasks) { mSyncQueue = syncQueue; mFullscreenUnfoldController = unfoldController.orElse(null); mRecentTasksOptional = recentTasks; } @Override Loading @@ -79,6 +88,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { }); mAnimatableTasksListener.onTaskAppeared(taskInfo); updateRecentsForVisibleFullscreenTask(taskInfo); } @Override Loading @@ -86,6 +96,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { if (Transitions.ENABLE_SHELL_TRANSITIONS) return; mAnimatableTasksListener.onTaskInfoChanged(taskInfo); updateRecentsForVisibleFullscreenTask(taskInfo); final TaskData data = mDataByTaskId.get(taskInfo.taskId); final Point positionInParent = taskInfo.positionInParent; Loading @@ -111,6 +122,15 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { taskInfo.taskId); } private void updateRecentsForVisibleFullscreenTask(RunningTaskInfo taskInfo) { mRecentTasksOptional.ifPresent(recentTasks -> { if (taskInfo.isVisible) { // Remove any persisted splits if either tasks are now made fullscreen and visible recentTasks.removeSplitPair(taskInfo.taskId); } }); } @Override public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { if (!mDataByTaskId.contains(taskId)) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +18 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.common.split.SplitLayout.SplitPosition; import com.android.wm.shell.draganddrop.DragAndDropPolicy; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.transition.LegacyTransitions; import com.android.wm.shell.transition.Transitions; Loading Loading @@ -124,10 +125,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final TransactionPool mTransactionPool; private final SplitscreenEventLogger mLogger; private final IconProvider mIconProvider; private final Optional<RecentTasksController> mRecentTasksOptional; private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider; private StageCoordinator mStageCoordinator; // TODO(b/205019015): Remove after we clean up downstream modules public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, Loading @@ -135,6 +138,19 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { this(shellTaskOrganizer, syncQueue, context, rootTDAOrganizer, mainExecutor, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, Optional.empty(), unfoldControllerProvider); } public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellExecutor mainExecutor, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; mContext = context; Loading @@ -147,6 +163,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mUnfoldControllerProvider = unfoldControllerProvider; mLogger = new SplitscreenEventLogger(); mIconProvider = iconProvider; mRecentTasksOptional = recentTasks; } public SplitScreen asSplitScreen() { Loading @@ -169,7 +186,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, mIconProvider, mUnfoldControllerProvider); mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +64 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ 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_HOME; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; Loading Loading @@ -92,6 +93,7 @@ import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitLayout.SplitPosition; import com.android.wm.shell.common.split.SplitWindowManager; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason; import com.android.wm.shell.transition.Transitions; Loading Loading @@ -147,6 +149,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final DisplayInsetsController mDisplayInsetsController; private final SplitScreenTransitions mSplitTransitions; private final SplitscreenEventLogger mLogger; private final Optional<RecentTasksController> mRecentTasks; // Tracks whether we should update the recent tasks. Only allow this to happen in between enter // and exit, since exit itself can trigger a number of changes that update the stages. private boolean mShouldUpdateRecents; private boolean mExitSplitScreenOnHide; private boolean mKeyguardOccluded; Loading Loading @@ -191,6 +197,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mContext = context; mDisplayId = displayId; Loading @@ -198,6 +205,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mRootTDAOrganizer = rootTDAOrganizer; mTaskOrganizer = taskOrganizer; mLogger = logger; mRecentTasks = recentTasks; mMainUnfoldController = unfoldControllerProvider.get().orElse(null); mSideUnfoldController = unfoldControllerProvider.get().orElse(null); Loading Loading @@ -238,6 +246,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, DisplayInsetsController displayInsetsController, SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mContext = context; mDisplayId = displayId; Loading @@ -255,6 +264,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainUnfoldController = unfoldControllerProvider.get().orElse(null); mSideUnfoldController = unfoldControllerProvider.get().orElse(null); mLogger = logger; mRecentTasks = recentTasks; transitions.addHandler(this); } Loading Loading @@ -560,12 +570,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void applyExitSplitScreen(StageTaskListener childrenToTop, WindowContainerTransaction wct, @ExitReason int 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; mSideStage.removeAllTasks(wct, childrenToTop == mSideStage); mMainStage.deactivate(wct, childrenToTop == mMainStage); mTaskOrganizer.applyTransaction(wct); mSyncQueue.runInSync(t -> t .setWindowCrop(mMainStage.mRootLeash, null) .setWindowCrop(mSideStage.mRootLeash, null)); // Hide divider and reset its position. setDividerVisibility(false); mSplitLayout.resetDividerPosition(); Loading @@ -579,6 +600,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } /** * Returns whether the split pair in the recent tasks list should be broken. */ private boolean shouldBreakPairedTaskInRecents(@ExitReason int exitReason) { switch (exitReason) { // One of the apps doesn't support MW case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW: // User has explicitly dragged the divider to dismiss split case EXIT_REASON_DRAG_DIVIDER: // Either of the split apps have finished case EXIT_REASON_APP_FINISHED: return true; default: return false; } } /** * Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates * an existing WindowContainerTransaction (rather than applying immediately). This is intended Loading Loading @@ -645,12 +683,28 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(), mSplitLayout.isLandscape()); } updateRecentTasksSplitPair(); for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onTaskStageChanged(taskId, stage, visible); } } private void updateRecentTasksSplitPair() { if (!mShouldUpdateRecents) { return; } mRecentTasks.ifPresent(recentTasks -> { int mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId(); int sideStageTopTaskId = mSideStage.getTopVisibleChildTaskId(); if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) { // Update the pair for the top tasks recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId); } }); } private void sendSplitVisibilityChanged() { for (int i = mListeners.size() - 1; i >= 0; --i) { final SplitScreen.SplitScreenListener l = mListeners.get(i); Loading Loading @@ -784,14 +838,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t)); } if (!mLogger.hasStartedSession() && mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { mShouldUpdateRecents = true; updateRecentTasksSplitPair(); if (!mLogger.hasStartedSession()) { mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(), getMainStagePosition(), mMainStage.getTopChildTaskUid(), getSideStagePosition(), mSideStage.getTopChildTaskUid(), mSplitLayout.isLandscape()); } } } @VisibleForTesting IBinder onSnappedToDismissTransition(boolean mainStageToTop) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +14 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; Loading Loading @@ -112,6 +113,19 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { return mChildrenTaskInfo.contains(taskId); } /** * Returns the top visible child task's id. */ int getTopVisibleChildTaskId() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); if (info.isVisible) { return info.taskId; } } return INVALID_TASK_ID; } /** * Returns the top activity uid for the top child task. */ Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +8 −3 Original line number Diff line number Diff line Loading @@ -240,8 +240,12 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static FullscreenTaskListener provideFullscreenTaskListener( SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> controller) { return new FullscreenTaskListener(syncQueue, controller); SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> optionalFullscreenUnfoldController, Optional<RecentTasksController> recentTasksOptional ) { return new FullscreenTaskListener(syncQueue, optionalFullscreenUnfoldController, recentTasksOptional); } // Loading Loading @@ -490,12 +494,13 @@ public abstract class WMShellBaseModule { DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) { if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context, rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, stageTaskUnfoldControllerProvider)); recentTasks, stageTaskUnfoldControllerProvider)); } else { return Optional.empty(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java +21 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; Loading @@ -47,15 +48,23 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = "FullscreenTaskListener"; private final SyncTransactionQueue mSyncQueue; private final FullscreenUnfoldController mFullscreenUnfoldController; private final Optional<RecentTasksController> mRecentTasksOptional; private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>(); private final AnimatableTasksListener mAnimatableTasksListener = new AnimatableTasksListener(); private final FullscreenUnfoldController mFullscreenUnfoldController; public FullscreenTaskListener(SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> unfoldController) { this(syncQueue, unfoldController, Optional.empty()); } public FullscreenTaskListener(SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> unfoldController, Optional<RecentTasksController> recentTasks) { mSyncQueue = syncQueue; mFullscreenUnfoldController = unfoldController.orElse(null); mRecentTasksOptional = recentTasks; } @Override Loading @@ -79,6 +88,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { }); mAnimatableTasksListener.onTaskAppeared(taskInfo); updateRecentsForVisibleFullscreenTask(taskInfo); } @Override Loading @@ -86,6 +96,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { if (Transitions.ENABLE_SHELL_TRANSITIONS) return; mAnimatableTasksListener.onTaskInfoChanged(taskInfo); updateRecentsForVisibleFullscreenTask(taskInfo); final TaskData data = mDataByTaskId.get(taskInfo.taskId); final Point positionInParent = taskInfo.positionInParent; Loading @@ -111,6 +122,15 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { taskInfo.taskId); } private void updateRecentsForVisibleFullscreenTask(RunningTaskInfo taskInfo) { mRecentTasksOptional.ifPresent(recentTasks -> { if (taskInfo.isVisible) { // Remove any persisted splits if either tasks are now made fullscreen and visible recentTasks.removeSplitPair(taskInfo.taskId); } }); } @Override public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { if (!mDataByTaskId.contains(taskId)) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +18 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.common.split.SplitLayout.SplitPosition; import com.android.wm.shell.draganddrop.DragAndDropPolicy; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.transition.LegacyTransitions; import com.android.wm.shell.transition.Transitions; Loading Loading @@ -124,10 +125,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final TransactionPool mTransactionPool; private final SplitscreenEventLogger mLogger; private final IconProvider mIconProvider; private final Optional<RecentTasksController> mRecentTasksOptional; private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider; private StageCoordinator mStageCoordinator; // TODO(b/205019015): Remove after we clean up downstream modules public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, Loading @@ -135,6 +138,19 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { this(shellTaskOrganizer, syncQueue, context, rootTDAOrganizer, mainExecutor, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, Optional.empty(), unfoldControllerProvider); } public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellExecutor mainExecutor, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; mContext = context; Loading @@ -147,6 +163,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mUnfoldControllerProvider = unfoldControllerProvider; mLogger = new SplitscreenEventLogger(); mIconProvider = iconProvider; mRecentTasksOptional = recentTasks; } public SplitScreen asSplitScreen() { Loading @@ -169,7 +186,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, mIconProvider, mUnfoldControllerProvider); mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +64 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ 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_HOME; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; Loading Loading @@ -92,6 +93,7 @@ import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitLayout.SplitPosition; import com.android.wm.shell.common.split.SplitWindowManager; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason; import com.android.wm.shell.transition.Transitions; Loading Loading @@ -147,6 +149,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final DisplayInsetsController mDisplayInsetsController; private final SplitScreenTransitions mSplitTransitions; private final SplitscreenEventLogger mLogger; private final Optional<RecentTasksController> mRecentTasks; // Tracks whether we should update the recent tasks. Only allow this to happen in between enter // and exit, since exit itself can trigger a number of changes that update the stages. private boolean mShouldUpdateRecents; private boolean mExitSplitScreenOnHide; private boolean mKeyguardOccluded; Loading Loading @@ -191,6 +197,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mContext = context; mDisplayId = displayId; Loading @@ -198,6 +205,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mRootTDAOrganizer = rootTDAOrganizer; mTaskOrganizer = taskOrganizer; mLogger = logger; mRecentTasks = recentTasks; mMainUnfoldController = unfoldControllerProvider.get().orElse(null); mSideUnfoldController = unfoldControllerProvider.get().orElse(null); Loading Loading @@ -238,6 +246,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, DisplayInsetsController displayInsetsController, SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mContext = context; mDisplayId = displayId; Loading @@ -255,6 +264,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainUnfoldController = unfoldControllerProvider.get().orElse(null); mSideUnfoldController = unfoldControllerProvider.get().orElse(null); mLogger = logger; mRecentTasks = recentTasks; transitions.addHandler(this); } Loading Loading @@ -560,12 +570,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void applyExitSplitScreen(StageTaskListener childrenToTop, WindowContainerTransaction wct, @ExitReason int 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; mSideStage.removeAllTasks(wct, childrenToTop == mSideStage); mMainStage.deactivate(wct, childrenToTop == mMainStage); mTaskOrganizer.applyTransaction(wct); mSyncQueue.runInSync(t -> t .setWindowCrop(mMainStage.mRootLeash, null) .setWindowCrop(mSideStage.mRootLeash, null)); // Hide divider and reset its position. setDividerVisibility(false); mSplitLayout.resetDividerPosition(); Loading @@ -579,6 +600,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } /** * Returns whether the split pair in the recent tasks list should be broken. */ private boolean shouldBreakPairedTaskInRecents(@ExitReason int exitReason) { switch (exitReason) { // One of the apps doesn't support MW case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW: // User has explicitly dragged the divider to dismiss split case EXIT_REASON_DRAG_DIVIDER: // Either of the split apps have finished case EXIT_REASON_APP_FINISHED: return true; default: return false; } } /** * Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates * an existing WindowContainerTransaction (rather than applying immediately). This is intended Loading Loading @@ -645,12 +683,28 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(), mSplitLayout.isLandscape()); } updateRecentTasksSplitPair(); for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onTaskStageChanged(taskId, stage, visible); } } private void updateRecentTasksSplitPair() { if (!mShouldUpdateRecents) { return; } mRecentTasks.ifPresent(recentTasks -> { int mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId(); int sideStageTopTaskId = mSideStage.getTopVisibleChildTaskId(); if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) { // Update the pair for the top tasks recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId); } }); } private void sendSplitVisibilityChanged() { for (int i = mListeners.size() - 1; i >= 0; --i) { final SplitScreen.SplitScreenListener l = mListeners.get(i); Loading Loading @@ -784,14 +838,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t)); } if (!mLogger.hasStartedSession() && mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { mShouldUpdateRecents = true; updateRecentTasksSplitPair(); if (!mLogger.hasStartedSession()) { mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(), getMainStagePosition(), mMainStage.getTopChildTaskUid(), getSideStagePosition(), mSideStage.getTopChildTaskUid(), mSplitLayout.isLandscape()); } } } @VisibleForTesting IBinder onSnappedToDismissTransition(boolean mainStageToTop) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +14 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; Loading Loading @@ -112,6 +113,19 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { return mChildrenTaskInfo.contains(taskId); } /** * Returns the top visible child task's id. */ int getTopVisibleChildTaskId() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); if (info.isVisible) { return info.taskId; } } return INVALID_TASK_ID; } /** * Returns the top activity uid for the top child task. */ Loading