diff options
2 files changed, 103 insertions, 67 deletions
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 6f7d992683cf..aff21cbe0ae6 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 @@ -34,6 +34,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; +import static com.android.window.flags.Flags.enableFullScreenWindowOnRemovingSplitScreenStageBugfix; import static com.android.window.flags.Flags.enableNonDefaultDisplaySplit; import static com.android.wm.shell.Flags.enableFlexibleSplit; import static com.android.wm.shell.Flags.enableFlexibleTwoAppSplit; @@ -908,6 +909,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } options = options != null ? options : new Bundle(); addActivityOptions(options, null); + ActivityManager.RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(taskId); + if (enableFullScreenWindowOnRemovingSplitScreenStageBugfix() && taskInfo != null + && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + prepareTasksForSplitScreen(new int[] {taskId}, wct); + } wct.startTask(taskId, options); mSplitTransitions.startFullscreenTransition(wct, remoteTransition); } 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 5851cbf9b933..10c28626dc9f 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 @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; @@ -61,6 +62,9 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; import android.window.DisplayAreaInfo; import android.window.RemoteTransition; @@ -71,6 +75,8 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.internal.logging.InstanceId; +import com.android.window.flags.Flags; import com.android.wm.shell.MockToken; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -96,6 +102,7 @@ import com.android.wm.shell.transition.HomeTransitionObserver; import com.android.wm.shell.transition.Transitions; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -111,6 +118,9 @@ import java.util.function.Consumer; @SmallTest @RunWith(AndroidJUnit4.class) public class StageCoordinatorTests extends ShellTestCase { + @Rule + public final SetFlagsRule setFlagsRule = new SetFlagsRule(); + @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock @@ -141,12 +151,15 @@ public class StageCoordinatorTests extends ShellTestCase { private final Rect mBounds1 = new Rect(10, 20, 30, 40); private final Rect mBounds2 = new Rect(5, 10, 15, 20); private final Rect mRootBounds = new Rect(0, 0, 45, 60); + private final int mTaskId = 18; - private SurfaceControl mRootLeash; - private SurfaceControl mDividerLeash; private ActivityManager.RunningTaskInfo mRootTask; private StageCoordinator mStageCoordinator; - private Transitions mTransitions; + private SplitScreenTransitions mSplitScreenTransitions; + private SplitScreenListener mSplitScreenListener; + private IBinder mBinder; + private ActivityManager.RunningTaskInfo mRunningTaskInfo; + private RemoteTransition mRemoteTransition; private final TestShellExecutor mMainExecutor = new TestShellExecutor(); private final ShellExecutor mAnimExecutor = new TestShellExecutor(); private final Handler mMainHandler = new Handler(Looper.getMainLooper()); @@ -154,19 +167,35 @@ public class StageCoordinatorTests extends ShellTestCase { DEFAULT_DISPLAY, 0); private final ActivityManager.RunningTaskInfo mMainChildTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build(); + private final ArgumentCaptor<WindowContainerTransaction> mWctCaptor = + ArgumentCaptor.forClass(WindowContainerTransaction.class); + private final WindowContainerTransaction mWct = spy(new WindowContainerTransaction()); @Before @UiThreadTest public void setup() { MockitoAnnotations.initMocks(this); - mTransitions = createTestTransitions(); + Transitions transitions = createTestTransitions(); + WindowContainerToken token = mock(WindowContainerToken.class); + SurfaceControl dividerLeash = new SurfaceControl.Builder().setName("fakeDivider").build(); + mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController, - mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, + mDisplayInsetsController, mSplitLayout, transitions, mTransactionPool, mMainExecutor, mMainHandler, Optional.empty(), mLaunchAdjacentController, Optional.empty(), mSplitState, Optional.empty(), mRootTDAOrganizer)); - - mDividerLeash = new SurfaceControl.Builder().setName("fakeDivider").build(); + mSplitScreenTransitions = spy(mStageCoordinator.getSplitTransitions()); + mSplitScreenListener = mock(SplitScreenListener.class); + mStageCoordinator.setSplitTransitions(mSplitScreenTransitions); + mBinder = mock(IBinder.class); + mRunningTaskInfo = mock(ActivityManager.RunningTaskInfo.class); + mRemoteTransition = mock(RemoteTransition.class); + mRunningTaskInfo.token = token; + + when(mRemoteTransition.getDebugName()).thenReturn(""); + when(token.asBinder()).thenReturn(mBinder); + when(mRunningTaskInfo.getToken()).thenReturn(token); + when(mTaskOrganizer.getRunningTaskInfo(mTaskId)).thenReturn(mRunningTaskInfo); when(mRootTDAOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(mDisplayAreaInfo); when(mSplitLayout.getTopLeftBounds()).thenReturn(mBounds1); @@ -174,11 +203,11 @@ public class StageCoordinatorTests extends ShellTestCase { when(mSplitLayout.getRootBounds()).thenReturn(mRootBounds); when(mSplitLayout.isLeftRightSplit()).thenReturn(false); when(mSplitLayout.applyTaskChanges(any(), any(), any())).thenReturn(true); - when(mSplitLayout.getDividerLeash()).thenReturn(mDividerLeash); + when(mSplitLayout.getDividerLeash()).thenReturn(dividerLeash); mRootTask = new TestRunningTaskInfoBuilder().build(); - mRootLeash = new SurfaceControl.Builder().setName("test").build(); - mStageCoordinator.onTaskAppeared(mRootTask, mRootLeash); + SurfaceControl rootLeash = new SurfaceControl.Builder().setName("test").build(); + mStageCoordinator.onTaskAppeared(mRootTask, rootLeash); mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); @@ -196,14 +225,12 @@ public class StageCoordinatorTests extends ShellTestCase { public void testMoveToStage_splitActiveBackground() { when(mStageCoordinator.isSplitActive()).thenReturn(true); - final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); - final WindowContainerTransaction wct = spy(new WindowContainerTransaction()); + mStageCoordinator.moveToStage(mRootTask, SPLIT_POSITION_BOTTOM_OR_RIGHT, mWct); - mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct); // TODO(b/349828130) Address this once we remove index_undefined called - verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task), + verify(mStageCoordinator).prepareEnterSplitScreen(eq(mWct), eq(mRootTask), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED)); - verify(mMainStage).reparentTopTask(eq(wct)); + verify(mMainStage).reparentTopTask(eq(mWct)); assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition()); assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition()); } @@ -215,25 +242,21 @@ public class StageCoordinatorTests extends ShellTestCase { // 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(mRootTask, SPLIT_POSITION_BOTTOM_OR_RIGHT, mWct); - mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct); // TODO(b/349828130) Address this once we remove index_undefined called - verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task), + verify(mStageCoordinator).prepareEnterSplitScreen(eq(mWct), eq(mRootTask), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED)); assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition()); assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition()); } @Test - public void testMoveToStage_splitInctive() { - final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); - final WindowContainerTransaction wct = new WindowContainerTransaction(); + public void testMoveToStage_splitInactive() { + mStageCoordinator.moveToStage(mRootTask, SPLIT_POSITION_BOTTOM_OR_RIGHT, mWct); - mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct); // TODO(b/349828130) Address this once we remove index_undefined called - verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task), + verify(mStageCoordinator).prepareEnterSplitScreen(eq(mWct), eq(mRootTask), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED)); assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition()); } @@ -248,25 +271,23 @@ public class StageCoordinatorTests extends ShellTestCase { @Test public void testLayoutChanged_topLeftSplitPosition_updatesUnfoldStageBounds() { mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null); - final SplitScreenListener listener = mock(SplitScreenListener.class); - mStageCoordinator.registerSplitScreenListener(listener); - clearInvocations(listener); + mStageCoordinator.registerSplitScreenListener(mSplitScreenListener); + clearInvocations(mSplitScreenListener); mStageCoordinator.onLayoutSizeChanged(mSplitLayout); - verify(listener).onSplitBoundsChanged(mRootBounds, mBounds2, mBounds1); + verify(mSplitScreenListener).onSplitBoundsChanged(mRootBounds, mBounds2, mBounds1); } @Test public void testLayoutChanged_bottomRightSplitPosition_updatesUnfoldStageBounds() { mStageCoordinator.setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null); - final SplitScreenListener listener = mock(SplitScreenListener.class); - mStageCoordinator.registerSplitScreenListener(listener); - clearInvocations(listener); + mStageCoordinator.registerSplitScreenListener(mSplitScreenListener); + clearInvocations(mSplitScreenListener); mStageCoordinator.onLayoutSizeChanged(mSplitLayout); - verify(listener).onSplitBoundsChanged(mRootBounds, mBounds1, mBounds2); + verify(mSplitScreenListener).onSplitBoundsChanged(mRootBounds, mBounds1, mBounds2); } @Test @@ -367,13 +388,8 @@ public class StageCoordinatorTests extends ShellTestCase { @Test public void testSplitIntentAndTaskWithPippedApp_launchFullscreen() { int taskId = 9; - SplitScreenTransitions splitScreenTransitions = - spy(mStageCoordinator.getSplitTransitions()); - mStageCoordinator.setSplitTransitions(splitScreenTransitions); mStageCoordinator.setMixedHandler(mDefaultMixedHandler); PendingIntent pendingIntent = mock(PendingIntent.class); - RemoteTransition remoteTransition = mock(RemoteTransition.class); - when(remoteTransition.getDebugName()).thenReturn(""); // Test launching second task full screen when(mDefaultMixedHandler.isIntentInPip(pendingIntent)).thenReturn(true); mStageCoordinator.startIntentAndTask( @@ -384,9 +400,9 @@ public class StageCoordinatorTests extends ShellTestCase { null /*option2*/, 0 /*splitPosition*/, 1 /*snapPosition*/, - remoteTransition /*remoteTransition*/, + mRemoteTransition /*remoteTransition*/, null /*instanceId*/); - verify(splitScreenTransitions, times(1)) + verify(mSplitScreenTransitions, times(1)) .startFullscreenTransition(any(), any()); // Test launching first intent fullscreen @@ -400,22 +416,17 @@ public class StageCoordinatorTests extends ShellTestCase { null /*option2*/, 0 /*splitPosition*/, 1 /*snapPosition*/, - remoteTransition /*remoteTransition*/, + mRemoteTransition /*remoteTransition*/, null /*instanceId*/); - verify(splitScreenTransitions, times(2)) + verify(mSplitScreenTransitions, times(2)) .startFullscreenTransition(any(), any()); } @Test public void testSplitIntentsWithPippedApp_launchFullscreen() { - SplitScreenTransitions splitScreenTransitions = - spy(mStageCoordinator.getSplitTransitions()); - mStageCoordinator.setSplitTransitions(splitScreenTransitions); mStageCoordinator.setMixedHandler(mDefaultMixedHandler); PendingIntent pendingIntent = mock(PendingIntent.class); PendingIntent pendingIntent2 = mock(PendingIntent.class); - RemoteTransition remoteTransition = mock(RemoteTransition.class); - when(remoteTransition.getDebugName()).thenReturn(""); // Test launching second task full screen when(mDefaultMixedHandler.isIntentInPip(pendingIntent)).thenReturn(true); mStageCoordinator.startIntents( @@ -429,9 +440,9 @@ public class StageCoordinatorTests extends ShellTestCase { new Bundle(), 0 /*splitPosition*/, 1 /*snapPosition*/, - remoteTransition /*remoteTransition*/, + mRemoteTransition /*remoteTransition*/, null /*instanceId*/); - verify(splitScreenTransitions, times(1)) + verify(mSplitScreenTransitions, times(1)) .startFullscreenTransition(any(), any()); // Test launching first intent fullscreen @@ -448,35 +459,54 @@ public class StageCoordinatorTests extends ShellTestCase { new Bundle(), 0 /*splitPosition*/, 1 /*snapPosition*/, - remoteTransition /*remoteTransition*/, + mRemoteTransition /*remoteTransition*/, null /*instanceId*/); - verify(splitScreenTransitions, times(2)) + verify(mSplitScreenTransitions, times(2)) .startFullscreenTransition(any(), any()); } - @Test public void startTask_ensureWindowingModeCleared() { - SplitScreenTransitions splitScreenTransitions = - spy(mStageCoordinator.getSplitTransitions()); - mStageCoordinator.setSplitTransitions(splitScreenTransitions); - ArgumentCaptor<WindowContainerTransaction> wctCaptor = - ArgumentCaptor.forClass(WindowContainerTransaction.class); - int taskId = 18; - IBinder binder = mock(IBinder.class); - ActivityManager.RunningTaskInfo rti = mock(ActivityManager.RunningTaskInfo.class); - WindowContainerToken mockToken = mock(WindowContainerToken.class); - when(mockToken.asBinder()).thenReturn(binder); - when(rti.getToken()).thenReturn(mockToken); - when(mTaskOrganizer.getRunningTaskInfo(taskId)).thenReturn(rti); - mStageCoordinator.startTask(taskId, SPLIT_POSITION_TOP_OR_LEFT, null /*options*/, + mStageCoordinator.startTask(mTaskId, SPLIT_POSITION_TOP_OR_LEFT, null /*options*/, null, SPLIT_INDEX_UNDEFINED); - verify(splitScreenTransitions).startEnterTransition(anyInt(), - wctCaptor.capture(), any(), any(), anyInt(), anyBoolean()); + verify(mSplitScreenTransitions).startEnterTransition(anyInt(), + mWctCaptor.capture(), any(), any(), anyInt(), anyBoolean()); + + int windowingMode = mWctCaptor.getValue().getChanges().get(mBinder).getWindowingMode(); + assertEquals(windowingMode, WINDOWING_MODE_UNDEFINED); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_FULL_SCREEN_WINDOW_ON_REMOVING_SPLIT_SCREEN_STAGE_BUGFIX) + public void startTasksOnSingleFreeformWindow_ensureWindowingModeClearedAndLaunchFullScreen() { + mDisplayAreaInfo.configuration.windowConfiguration.setWindowingMode( + WINDOWING_MODE_FREEFORM); + when(mRunningTaskInfo.getWindowingMode()).thenReturn(WINDOWING_MODE_FREEFORM); + + mStageCoordinator.startTasks(mTaskId, null, INVALID_TASK_ID, null, + SPLIT_POSITION_TOP_OR_LEFT, SNAP_TO_2_50_50, mRemoteTransition, + InstanceId.fakeInstanceId(0)); - int windowingMode = wctCaptor.getValue().getChanges().get(binder).getWindowingMode(); + verify(mSplitScreenTransitions).startFullscreenTransition(mWctCaptor.capture(), any()); + int windowingMode = mWctCaptor.getValue().getChanges().get(mBinder).getWindowingMode(); assertEquals(windowingMode, WINDOWING_MODE_UNDEFINED); } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_FULL_SCREEN_WINDOW_ON_REMOVING_SPLIT_SCREEN_STAGE_BUGFIX) + public void startTasksOnSingleFreeformWindow_flagDisabled_noChangeToWindowingModeInWct() { + mDisplayAreaInfo.configuration.windowConfiguration.setWindowingMode( + WINDOWING_MODE_FREEFORM); + when(mRunningTaskInfo.getWindowingMode()).thenReturn(WINDOWING_MODE_FREEFORM); + + mStageCoordinator.startTasks(mTaskId, null, INVALID_TASK_ID, null, + SPLIT_POSITION_TOP_OR_LEFT, SNAP_TO_2_50_50, mRemoteTransition, + InstanceId.fakeInstanceId(0)); + + verify(mSplitScreenTransitions).startFullscreenTransition(mWctCaptor.capture(), any()); + assertThat(mWctCaptor.getValue().getChanges()).isEmpty(); + } + @Test public void testDismiss_freeformDisplay() { mDisplayAreaInfo.configuration.windowConfiguration.setWindowingMode( |