diff options
author | 2025-02-24 12:03:24 -0800 | |
---|---|---|
committer | 2025-02-24 12:03:24 -0800 | |
commit | dd407c456f20dd1fbe5286cda0288a2e0513279d (patch) | |
tree | c640e2ce139f52b08f73ea01ad7aea0f9d305f50 | |
parent | 56d5b3753b4fb67d9ae4103d41af861f4a590b0b (diff) | |
parent | 160e43beeb3e6ee9555b31f71c4012865448e8e5 (diff) |
Merge "[23/N] Desks: Deactivate desk when moving to split-screen" into main
5 files changed, 137 insertions, 17 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 2d9aea014fbe..180d069f359d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -2701,10 +2701,12 @@ class DesktopTasksController( /** * Adds split screen changes to a transaction. Note that bounds are not reset here due to * animation; see {@link onDesktopSplitSelectAnimComplete} - * - * TODO: b/394268248 - desk needs to be deactivated. */ - private fun addMoveToSplitChanges(wct: WindowContainerTransaction, taskInfo: RunningTaskInfo) { + private fun addMoveToSplitChanges( + wct: WindowContainerTransaction, + taskInfo: RunningTaskInfo, + deskId: Int?, + ): RunOnTransitStart? { // This windowing mode is to get the transition animation started; once we complete // split select, we will change windowing mode to undefined and inherit from split stage. // Going to undefined here causes task to flicker to the top left. @@ -2714,11 +2716,12 @@ class DesktopTasksController( // want it overridden in multi-window. wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) - performDesktopExitCleanupIfNeeded( + return performDesktopExitCleanupIfNeeded( taskId = taskInfo.taskId, displayId = taskInfo.displayId, + deskId = deskId, wct = wct, - forceToFullscreen = false, + forceToFullscreen = true, shouldEndUpAtHome = false, ) } @@ -2950,14 +2953,21 @@ class DesktopTasksController( } dragToDesktopTransitionHandler.cancelDragToDesktopTransition(cancelState) } else { + val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId) + logV("Split requested for task=%d in desk=%d", taskInfo.taskId, deskId) val wct = WindowContainerTransaction() - addMoveToSplitChanges(wct, taskInfo) - splitScreenController.requestEnterSplitSelect( - taskInfo, - wct, - if (leftOrTop) SPLIT_POSITION_TOP_OR_LEFT else SPLIT_POSITION_BOTTOM_OR_RIGHT, - taskInfo.configuration.windowConfiguration.bounds, - ) + val runOnTransitStart = addMoveToSplitChanges(wct, taskInfo, deskId) + val transition = + splitScreenController.requestEnterSplitSelect( + taskInfo, + wct, + if (leftOrTop) SPLIT_POSITION_TOP_OR_LEFT + else SPLIT_POSITION_BOTTOM_OR_RIGHT, + taskInfo.configuration.windowConfiguration.bounds, + ) + if (transition != null) { + runOnTransitStart?.invoke(transition) + } } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index ba30d924e0b1..10b23fd2f552 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -54,6 +54,7 @@ import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; @@ -580,10 +581,13 @@ public class SplitScreenController implements SplitDragPolicy.Starter, * @param wct transaction to apply if this is a valid request * @param splitPosition the split position this task should move to * @param taskBounds current freeform bounds of the task entering split + * + * @return the token of the transition that started as a result of entering split select. */ - public void requestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo, + @Nullable + public IBinder requestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo, WindowContainerTransaction wct, int splitPosition, Rect taskBounds) { - mStageCoordinator.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds); + return mStageCoordinator.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 77a7c5406a67..0438d16796cf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -122,6 +122,7 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManager; import android.widget.Toast; +import android.window.DesktopExperienceFlags; import android.window.DisplayAreaInfo; import android.window.RemoteTransition; import android.window.TransitionInfo; @@ -219,6 +220,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final Context mContext; private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>(); private final Set<SplitScreen.SplitSelectListener> mSelectListeners = new HashSet<>(); + private final Transitions mTransitions; private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; private final DisplayInsetsController mDisplayInsetsController; @@ -419,6 +421,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, iconProvider, mWindowDecorViewModel, STAGE_TYPE_SIDE); } + mTransitions = transitions; mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; @@ -455,6 +458,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mTaskOrganizer = taskOrganizer; mMainStage = mainStage; mSideStage = sideStage; + mTransitions = transitions; mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; @@ -660,16 +664,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return mLogger; } - void requestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo, + @Nullable + IBinder requestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo, WindowContainerTransaction wct, int splitPosition, Rect taskBounds) { boolean enteredSplitSelect = false; for (SplitScreen.SplitSelectListener listener : mSelectListeners) { enteredSplitSelect |= listener.onRequestEnterSplitSelect(taskInfo, splitPosition, taskBounds); } - if (enteredSplitSelect) { + if (!enteredSplitSelect) { + return null; + } + if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) { mTaskOrganizer.applyTransaction(wct); + return null; } + return mTransitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null); } void startShortcut(String packageName, String shortcutId, @SplitPosition int position, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 93eb396742ab..ac1deec53bf6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -5249,6 +5249,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun enterSplit_wasInDesk_deactivatesDesk() { + val deskId = 5 + taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId) + taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId) + val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId) + val transition = Binder() + whenever(splitScreenController.requestEnterSplitSelect(eq(task), any(), any(), any())) + .thenReturn(transition) + + controller.requestSplit(task, leftOrTop = false) + + verify(desksOrganizer).deactivateDesk(any(), eq(deskId)) + verify(desksTransitionsObserver) + .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId)) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES) fun newWindow_fromFullscreenOpensInSplit() { setUpLandscapeDisplay() @@ -6601,6 +6619,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() bounds: Rect? = null, active: Boolean = true, background: Boolean = false, + deskId: Int? = null, ): RunningTaskInfo { val task = createFreeformTask(displayId, bounds) val activityInfo = ActivityInfo() @@ -6613,7 +6632,11 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } else { whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) } - taskRepository.addTask(displayId, task.taskId, isVisible = active) + if (deskId != null) { + taskRepository.addTaskToDesk(displayId, deskId, task.taskId, isVisible = active) + } else { + taskRepository.addTask(displayId, task.taskId, isVisible = active) + } if (!background) { runningTasks.add(task) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index 10c28626dc9f..e9c4c31729e9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -38,6 +38,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -48,6 +50,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -58,6 +61,7 @@ import android.app.ActivityOptions; import android.app.PendingIntent; import android.content.res.Configuration; import android.graphics.Rect; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -196,6 +200,7 @@ public class StageCoordinatorTests extends ShellTestCase { when(token.asBinder()).thenReturn(mBinder); when(mRunningTaskInfo.getToken()).thenReturn(token); when(mTaskOrganizer.getRunningTaskInfo(mTaskId)).thenReturn(mRunningTaskInfo); + when(mTaskOrganizer.startNewTransition(anyInt(), any())).thenReturn(new Binder()); when(mRootTDAOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(mDisplayAreaInfo); when(mSplitLayout.getTopLeftBounds()).thenReturn(mBounds1); @@ -557,6 +562,60 @@ public class StageCoordinatorTests extends ShellTestCase { assertFalse(c != null && c.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); } + @Test + @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + public void testRequestEnterSplit_didNotEnterSplitSelect_doesNotApplyTransaction() { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.registerSplitSelectListener( + new TestSplitSelectListener(/* alwaysEnter = */ false)); + + final IBinder transition = mStageCoordinator.requestEnterSplitSelect(mRunningTaskInfo, wct, + SPLIT_POSITION_TOP_OR_LEFT, new Rect(0, 0, 100, 100)); + + assertNull(transition); + verify(mTaskOrganizer, never()).applyTransaction(wct); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + public void testRequestEnterSplit_enteredSplitSelect_appliesTransaction() { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.registerSplitSelectListener( + new TestSplitSelectListener(/* alwaysEnter = */ true)); + + final IBinder transition = mStageCoordinator.requestEnterSplitSelect(mRunningTaskInfo, wct, + SPLIT_POSITION_TOP_OR_LEFT, new Rect(0, 0, 100, 100)); + + assertNull(transition); + verify(mTaskOrganizer).applyTransaction(wct); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + public void testRequestEnterSplit_didNotEnterSplitSelect_doesNotStartTransition() { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.registerSplitSelectListener( + new TestSplitSelectListener(/* alwaysEnter = */ false)); + + final IBinder transition = mStageCoordinator.requestEnterSplitSelect(mRunningTaskInfo, wct, + SPLIT_POSITION_TOP_OR_LEFT, new Rect(0, 0, 100, 100)); + + assertNull(transition); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + public void testRequestEnterSplit_enteredSplitSelect_startsTransition() { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.registerSplitSelectListener( + new TestSplitSelectListener(/* alwaysEnter = */ true)); + + final IBinder transition = mStageCoordinator.requestEnterSplitSelect(mRunningTaskInfo, wct, + SPLIT_POSITION_TOP_OR_LEFT, new Rect(0, 0, 100, 100)); + + assertNotNull(transition); + } + private Transitions createTestTransitions() { ShellInit shellInit = new ShellInit(mMainExecutor); final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class), @@ -566,4 +625,18 @@ public class StageCoordinatorTests extends ShellTestCase { shellInit.init(); return t; } + + private static class TestSplitSelectListener implements SplitScreen.SplitSelectListener { + private final boolean mAlwaysEnter; + + TestSplitSelectListener(boolean alwaysEnter) { + mAlwaysEnter = alwaysEnter; + } + + @Override + public boolean onRequestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo, + int splitPosition, Rect taskBounds) { + return mAlwaysEnter; + } + } } |