Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +6 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +97 −67 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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()); Loading @@ -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); Loading @@ -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(); Loading @@ -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()); } Loading @@ -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()); } Loading @@ -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 Loading Loading @@ -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( Loading @@ -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 Loading @@ -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( Loading @@ -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 Loading @@ -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( Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +6 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +97 −67 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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()); Loading @@ -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); Loading @@ -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(); Loading @@ -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()); } Loading @@ -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()); } Loading @@ -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 Loading Loading @@ -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( Loading @@ -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 Loading @@ -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( Loading @@ -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 Loading @@ -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( Loading