Loading services/core/java/com/android/server/wm/ActivityStack.java +37 −11 Original line number Original line Diff line number Diff line Loading @@ -1049,6 +1049,9 @@ class ActivityStack extends Task { } } /** /** * This moves 'task' to the back of this task and also recursively moves this task to the back * of its parents (if applicable). * * @param reason The reason for moving the stack to the back. * @param reason The reason for moving the stack to the back. * @param task If non-null, the task will be moved to the bottom of the stack. * @param task If non-null, the task will be moved to the bottom of the stack. **/ **/ Loading @@ -1056,18 +1059,41 @@ class ActivityStack extends Task { if (!isAttached()) { if (!isAttached()) { return; return; } } final TaskDisplayArea displayArea = getDisplayArea(); getDisplayArea().positionStackAtBottom(this, reason); if (!mCreatedByOrganizer) { // If this is just a normal task, so move to back of parent and then move 'task' to // back of this. final WindowContainer parent = getParent(); final Task parentTask = parent != null ? parent.asTask() : null; if (parentTask != null) { ((ActivityStack) parentTask).moveToBack(reason, this); } else { displayArea.positionStackAtBottom(this, reason); } if (task != null && task != this) { if (task != null && task != this) { positionChildAtBottom(task); positionChildAtBottom(task); } } return; /** } * The intent behind moving a primary split screen stack to the back is usually to hide if (task == null || task == this) { * behind the home stack. Exit split screen in this case. return; */ } if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // This is a created-by-organizer task. In this case, let the organizer deal with this setWindowingMode(WINDOWING_MODE_UNDEFINED); // task's ordering. However, we still need to move 'task' to back. The intention is that // this ends up behind the home-task so that it is made invisible; so, if the home task // is not a child of this, reparent 'task' to the back of the home task's actual parent. final ActivityStack home = displayArea.getOrCreateRootHomeTask(); final WindowContainer homeParent = home.getParent(); final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; if (homeParentTask == null) { ((ActivityStack) task).reparent(displayArea, false /* onTop */); } else if (homeParentTask == this) { // Apparently reparent early-outs if same stack, so we have to explicitly reorder. positionChildAtBottom(task); } else { task.reparent((ActivityStack) homeParentTask, false /* toTop */, REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, false /* deferResume */, "moveToBack"); } } } } Loading services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +52 −8 Original line number Original line Diff line number Diff line Loading @@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_F import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.TaskDisplayArea.getStackAbove; import static com.android.server.wm.TaskDisplayArea.getStackAbove; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -140,9 +141,12 @@ public class ActivityStackTests extends ActivityTestsBase { } } @Test @Test public void testPrimarySplitScreenRestoresWhenMovedToBack() { public void testPrimarySplitScreenMoveToBack() { // Create primary splitscreen stack. This will create secondary stacks and places the TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // existing fullscreen stack on the bottom. // We're testing an edge case here where we have primary + fullscreen rather than secondary. organizer.setMoveToSecondaryOnEnter(false); // Create primary splitscreen stack. final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); Loading @@ -165,12 +169,14 @@ public class ActivityStackTests extends ActivityTestsBase { } } @Test @Test public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() { public void testMoveToPrimarySplitScreenThenMoveToBack() { TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // This time, start with a fullscreen activitystack // This time, start with a fullscreen activitystack final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); primarySplitScreen.reparent((ActivityStack) organizer.mPrimary, POSITION_TOP, false /*moveParents*/, "test"); // Assert windowing mode. // Assert windowing mode. assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); Loading @@ -180,13 +186,51 @@ public class ActivityStackTests extends ActivityTestsBase { null /* task */); null /* task */); // Assert that stack is at the bottom. // Assert that stack is at the bottom. assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen)); assertEquals(primarySplitScreen, organizer.mSecondary.getChildAt(0)); // Ensure that the override mode is restored to what it was (fullscreen) // Ensure that the override mode is restored to what it was (fullscreen) assertEquals(WINDOWING_MODE_FULLSCREEN, assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getRequestedOverrideWindowingMode()); primarySplitScreen.getRequestedOverrideWindowingMode()); } } @Test public void testSplitScreenMoveToBack() { TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // Set up split-screen with primary on top and secondary containing the home task below // another stack. final ActivityStack primaryTask = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityStack homeRoot = mDefaultTaskDisplayArea.getStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); final ActivityStack secondaryTask = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); mDefaultTaskDisplayArea.positionStackAtTop((ActivityStack) organizer.mPrimary, false /* includingParents */); // Move primary to back. primaryTask.moveToBack("test", null /* task */); // Assert that the primaryTask is now below home in its parent but primary is left alone. assertEquals(0, organizer.mPrimary.getChildCount()); assertEquals(primaryTask, organizer.mSecondary.getChildAt(0)); assertEquals(1, organizer.mPrimary.compareTo(organizer.mSecondary)); assertEquals(1, homeRoot.compareTo(primaryTask)); assertEquals(homeRoot.getParent(), primaryTask.getParent()); // Make sure windowing modes are correct assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, organizer.mPrimary.getWindowingMode()); assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, primaryTask.getWindowingMode()); // Move secondary to back via parent (should be equivalent) ((ActivityStack) organizer.mSecondary).moveToBack("test", secondaryTask); // Assert that it is now in back but still in secondary split assertEquals(1, homeRoot.compareTo(primaryTask)); assertEquals(secondaryTask, organizer.mSecondary.getChildAt(0)); assertEquals(1, primaryTask.compareTo(secondaryTask)); assertEquals(homeRoot.getParent(), secondaryTask.getParent()); } @Test @Test public void testStackInheritsDisplayWindowingMode() { public void testStackInheritsDisplayWindowingMode() { final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( Loading services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +0 −63 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,6 @@ import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SWITCHES_CANCELED; import static android.app.ActivityManager.START_SWITCHES_CANCELED; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; Loading Loading @@ -64,10 +63,8 @@ import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.app.IApplicationThread; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.ComponentName; import android.content.Intent; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo; Loading @@ -82,8 +79,6 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession; import android.view.Gravity; import android.view.Gravity; import android.window.ITaskOrganizer; import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest; Loading Loading @@ -1004,62 +999,4 @@ public class ActivityStarterTests extends ActivityTestsBase { verify(recentTasks, times(1)).add(any()); verify(recentTasks, times(1)).add(any()); } } static class TestSplitOrganizer extends ITaskOrganizer.Stub { final ActivityTaskManagerService mService; Task mPrimary; Task mSecondary; boolean mInSplit = false; int mDisplayId; TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { mService = service; mDisplayId = displayId; mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); } @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { if (mInSplit) { return; } if (info.topActivityType != ACTIVITY_TYPE_UNDEFINED) { if (info.configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { mInSplit = true; mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, mSecondary.mRemoteToken.toWindowContainerToken()); // move everything to secondary because test expects this but usually sysui // does it. DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); if (!WindowConfiguration.isSplitScreenWindowingMode( stack.getWindowingMode())) { stack.reparent(mSecondary, POSITION_BOTTOM); } } } } } } @Override public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { } }; } } services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +78 −0 Original line number Original line Diff line number Diff line Loading @@ -17,7 +17,10 @@ package com.android.server.wm; package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; Loading @@ -30,9 +33,12 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.app.IApplicationThread; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; Loading @@ -43,6 +49,8 @@ import android.os.Build; import android.os.Bundle; import android.os.Bundle; import android.os.UserHandle; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession; import android.window.ITaskOrganizer; import android.window.WindowContainerToken; import com.android.server.AttributeCache; import com.android.server.AttributeCache; Loading Loading @@ -505,4 +513,74 @@ class ActivityTestsBase extends SystemServiceTestsBase { } } } } static class TestSplitOrganizer extends ITaskOrganizer.Stub { final ActivityTaskManagerService mService; Task mPrimary; Task mSecondary; boolean mInSplit = false; // moves everything to secondary. Most tests expect this since sysui usually does it. boolean mMoveToSecondaryOnEnter = true; int mDisplayId; TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { mService = service; mDisplayId = displayId; mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); } TestSplitOrganizer(ActivityTaskManagerService service) { this(service, service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId); } public void setMoveToSecondaryOnEnter(boolean move) { mMoveToSecondaryOnEnter = move; } @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { if (mInSplit) { return; } if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) { // Not populated return; } if (info.configuration.windowConfiguration.getWindowingMode() != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { return; } mInSplit = true; if (!mMoveToSecondaryOnEnter) { return; } mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, mSecondary.mRemoteToken.toWindowContainerToken()); DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) { stack.reparent(mSecondary, POSITION_BOTTOM); } } } } @Override public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { } }; } } Loading
services/core/java/com/android/server/wm/ActivityStack.java +37 −11 Original line number Original line Diff line number Diff line Loading @@ -1049,6 +1049,9 @@ class ActivityStack extends Task { } } /** /** * This moves 'task' to the back of this task and also recursively moves this task to the back * of its parents (if applicable). * * @param reason The reason for moving the stack to the back. * @param reason The reason for moving the stack to the back. * @param task If non-null, the task will be moved to the bottom of the stack. * @param task If non-null, the task will be moved to the bottom of the stack. **/ **/ Loading @@ -1056,18 +1059,41 @@ class ActivityStack extends Task { if (!isAttached()) { if (!isAttached()) { return; return; } } final TaskDisplayArea displayArea = getDisplayArea(); getDisplayArea().positionStackAtBottom(this, reason); if (!mCreatedByOrganizer) { // If this is just a normal task, so move to back of parent and then move 'task' to // back of this. final WindowContainer parent = getParent(); final Task parentTask = parent != null ? parent.asTask() : null; if (parentTask != null) { ((ActivityStack) parentTask).moveToBack(reason, this); } else { displayArea.positionStackAtBottom(this, reason); } if (task != null && task != this) { if (task != null && task != this) { positionChildAtBottom(task); positionChildAtBottom(task); } } return; /** } * The intent behind moving a primary split screen stack to the back is usually to hide if (task == null || task == this) { * behind the home stack. Exit split screen in this case. return; */ } if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // This is a created-by-organizer task. In this case, let the organizer deal with this setWindowingMode(WINDOWING_MODE_UNDEFINED); // task's ordering. However, we still need to move 'task' to back. The intention is that // this ends up behind the home-task so that it is made invisible; so, if the home task // is not a child of this, reparent 'task' to the back of the home task's actual parent. final ActivityStack home = displayArea.getOrCreateRootHomeTask(); final WindowContainer homeParent = home.getParent(); final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; if (homeParentTask == null) { ((ActivityStack) task).reparent(displayArea, false /* onTop */); } else if (homeParentTask == this) { // Apparently reparent early-outs if same stack, so we have to explicitly reorder. positionChildAtBottom(task); } else { task.reparent((ActivityStack) homeParentTask, false /* toTop */, REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, false /* deferResume */, "moveToBack"); } } } } Loading
services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +52 −8 Original line number Original line Diff line number Diff line Loading @@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_F import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.TaskDisplayArea.getStackAbove; import static com.android.server.wm.TaskDisplayArea.getStackAbove; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -140,9 +141,12 @@ public class ActivityStackTests extends ActivityTestsBase { } } @Test @Test public void testPrimarySplitScreenRestoresWhenMovedToBack() { public void testPrimarySplitScreenMoveToBack() { // Create primary splitscreen stack. This will create secondary stacks and places the TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // existing fullscreen stack on the bottom. // We're testing an edge case here where we have primary + fullscreen rather than secondary. organizer.setMoveToSecondaryOnEnter(false); // Create primary splitscreen stack. final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); Loading @@ -165,12 +169,14 @@ public class ActivityStackTests extends ActivityTestsBase { } } @Test @Test public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() { public void testMoveToPrimarySplitScreenThenMoveToBack() { TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // This time, start with a fullscreen activitystack // This time, start with a fullscreen activitystack final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); primarySplitScreen.reparent((ActivityStack) organizer.mPrimary, POSITION_TOP, false /*moveParents*/, "test"); // Assert windowing mode. // Assert windowing mode. assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); Loading @@ -180,13 +186,51 @@ public class ActivityStackTests extends ActivityTestsBase { null /* task */); null /* task */); // Assert that stack is at the bottom. // Assert that stack is at the bottom. assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen)); assertEquals(primarySplitScreen, organizer.mSecondary.getChildAt(0)); // Ensure that the override mode is restored to what it was (fullscreen) // Ensure that the override mode is restored to what it was (fullscreen) assertEquals(WINDOWING_MODE_FULLSCREEN, assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getRequestedOverrideWindowingMode()); primarySplitScreen.getRequestedOverrideWindowingMode()); } } @Test public void testSplitScreenMoveToBack() { TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // Set up split-screen with primary on top and secondary containing the home task below // another stack. final ActivityStack primaryTask = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityStack homeRoot = mDefaultTaskDisplayArea.getStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); final ActivityStack secondaryTask = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); mDefaultTaskDisplayArea.positionStackAtTop((ActivityStack) organizer.mPrimary, false /* includingParents */); // Move primary to back. primaryTask.moveToBack("test", null /* task */); // Assert that the primaryTask is now below home in its parent but primary is left alone. assertEquals(0, organizer.mPrimary.getChildCount()); assertEquals(primaryTask, organizer.mSecondary.getChildAt(0)); assertEquals(1, organizer.mPrimary.compareTo(organizer.mSecondary)); assertEquals(1, homeRoot.compareTo(primaryTask)); assertEquals(homeRoot.getParent(), primaryTask.getParent()); // Make sure windowing modes are correct assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, organizer.mPrimary.getWindowingMode()); assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, primaryTask.getWindowingMode()); // Move secondary to back via parent (should be equivalent) ((ActivityStack) organizer.mSecondary).moveToBack("test", secondaryTask); // Assert that it is now in back but still in secondary split assertEquals(1, homeRoot.compareTo(primaryTask)); assertEquals(secondaryTask, organizer.mSecondary.getChildAt(0)); assertEquals(1, primaryTask.compareTo(secondaryTask)); assertEquals(homeRoot.getParent(), secondaryTask.getParent()); } @Test @Test public void testStackInheritsDisplayWindowingMode() { public void testStackInheritsDisplayWindowingMode() { final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( Loading
services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +0 −63 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,6 @@ import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SWITCHES_CANCELED; import static android.app.ActivityManager.START_SWITCHES_CANCELED; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; Loading Loading @@ -64,10 +63,8 @@ import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.app.IApplicationThread; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.ComponentName; import android.content.Intent; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo; Loading @@ -82,8 +79,6 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession; import android.view.Gravity; import android.view.Gravity; import android.window.ITaskOrganizer; import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest; Loading Loading @@ -1004,62 +999,4 @@ public class ActivityStarterTests extends ActivityTestsBase { verify(recentTasks, times(1)).add(any()); verify(recentTasks, times(1)).add(any()); } } static class TestSplitOrganizer extends ITaskOrganizer.Stub { final ActivityTaskManagerService mService; Task mPrimary; Task mSecondary; boolean mInSplit = false; int mDisplayId; TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { mService = service; mDisplayId = displayId; mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); } @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { if (mInSplit) { return; } if (info.topActivityType != ACTIVITY_TYPE_UNDEFINED) { if (info.configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { mInSplit = true; mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, mSecondary.mRemoteToken.toWindowContainerToken()); // move everything to secondary because test expects this but usually sysui // does it. DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); if (!WindowConfiguration.isSplitScreenWindowingMode( stack.getWindowingMode())) { stack.reparent(mSecondary, POSITION_BOTTOM); } } } } } } @Override public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { } }; } }
services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +78 −0 Original line number Original line Diff line number Diff line Loading @@ -17,7 +17,10 @@ package com.android.server.wm; package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; Loading @@ -30,9 +33,12 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.app.IApplicationThread; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; Loading @@ -43,6 +49,8 @@ import android.os.Build; import android.os.Bundle; import android.os.Bundle; import android.os.UserHandle; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession; import android.window.ITaskOrganizer; import android.window.WindowContainerToken; import com.android.server.AttributeCache; import com.android.server.AttributeCache; Loading Loading @@ -505,4 +513,74 @@ class ActivityTestsBase extends SystemServiceTestsBase { } } } } static class TestSplitOrganizer extends ITaskOrganizer.Stub { final ActivityTaskManagerService mService; Task mPrimary; Task mSecondary; boolean mInSplit = false; // moves everything to secondary. Most tests expect this since sysui usually does it. boolean mMoveToSecondaryOnEnter = true; int mDisplayId; TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { mService = service; mDisplayId = displayId; mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); mService.mTaskOrganizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); } TestSplitOrganizer(ActivityTaskManagerService service) { this(service, service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId); } public void setMoveToSecondaryOnEnter(boolean move) { mMoveToSecondaryOnEnter = move; } @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { if (mInSplit) { return; } if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) { // Not populated return; } if (info.configuration.windowConfiguration.getWindowingMode() != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { return; } mInSplit = true; if (!mMoveToSecondaryOnEnter) { return; } mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, mSecondary.mRemoteToken.toWindowContainerToken()); DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) { stack.reparent(mSecondary, POSITION_BOTTOM); } } } } @Override public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { } }; } }