Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +4 −0 Original line number Diff line number Diff line Loading @@ -2878,6 +2878,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mWindowManager.deferSurfaceLayout(); // This will clear the pinned stack by moving an existing task to the full screen stack, // ensuring only one task is present. moveTasksToFullscreenStackLocked(PINNED_STACK_ID, !ON_TOP); // Need to make sure the pinned stack exist so we can resize it below... final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); Loading services/core/java/com/android/server/am/TaskRecord.java +16 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.util.XmlUtils; Loading Loading @@ -445,10 +446,23 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); final Configuration overrideConfig = getOverrideConfiguration(); mWindowContainerController = new TaskWindowContainerController(taskId, this, setWindowContainerController(new TaskWindowContainerController(taskId, this, getStack().getWindowContainerController(), userId, bounds, overrideConfig, mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers, lastTaskDescription); lastTaskDescription)); } /** * Should only be invoked from {@link #createWindowContainer(boolean, boolean)}. */ @VisibleForTesting protected void setWindowContainerController(TaskWindowContainerController controller) { if (mWindowContainerController != null) { throw new IllegalArgumentException("Window container=" + mWindowContainerController + " already created for task=" + this); } mWindowContainerController = controller; } void removeWindowContainer() { Loading services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +27 −15 Original line number Diff line number Diff line Loading @@ -16,7 +16,8 @@ package com.android.server.am; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import android.content.ComponentName; import android.platform.test.annotations.Presubmit; Loading @@ -36,50 +37,61 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityRecordTests extends ActivityTestsBase { private static final int TEST_STACK_ID = 100; private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); @Test public void testStackCleanupOnClearingTask() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); record.setTask(null); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); } @Test public void testStackCleanupOnActivityRemoval() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); task.removeActivity(record); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); } @Test public void testStackCleanupOnTaskRemoval() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); testStack.removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); service.mStackSupervisor.getStack(TEST_STACK_ID) .removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); // Stack should be gone on task removal. assertNull(service.mStackSupervisor.getStack(TEST_STACK_ID)); } @Test public void testNoCleanupMovingActivityInSameStack() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord oldTask = createTask(service, testActivityComponent, testStack); final TaskRecord oldTask = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, oldTask); final TaskRecord newTask = createTask(service, testActivityComponent, testStack); final TaskRecord newTask = createTask(service, testActivityComponent, TEST_STACK_ID); record.reparent(newTask, 0, null /*reason*/); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 0); assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 0); } private static int getActivityRemovedFromStackCount(ActivityManagerService service, int stackId) { final ActivityStack stack = service.mStackSupervisor.getStack(stackId); if (stack instanceof ActivityStackReporter) { return ((ActivityStackReporter) stack).onActivityRemovedFromStackInvocationCount(); } return -1; } } services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +68 −0 Original line number Diff line number Diff line Loading @@ -16,8 +16,14 @@ package com.android.server.am; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.content.ComponentName; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; Loading @@ -25,6 +31,10 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.runner.RunWith; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; /** Loading @@ -37,6 +47,9 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityStackSupervisorTests extends ActivityTestsBase { private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); /** * This test ensures that we do not try to restore a task based off an invalid task id. The * stack supervisor is a test version so there will be no tasks present. We should expect Loading @@ -49,4 +62,59 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/); assertNull(task); } /** * This test ensures that an existing task in the pinned stack is moved to the fullscreen * activity stack when a new task is added. */ @Test public void testReplacingTaskInPinnedStack() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TaskRecord firstTask = createTask(service, testActivityComponent, FULLSCREEN_WORKSPACE_STACK_ID); final ActivityRecord firstActivity = createActivity(service, testActivityComponent, firstTask); // Create a new task on the full screen stack final TaskRecord secondTask = createTask(service, testActivityComponent, FULLSCREEN_WORKSPACE_STACK_ID); final ActivityRecord secondActivity = createActivity(service, testActivityComponent, secondTask); service.mStackSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", service.mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID)); // Ensure full screen stack has both tasks. ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask, secondTask); // Move first activity to pinned stack. service.mStackSupervisor.moveActivityToPinnedStackLocked(firstActivity, new Rect() /*sourceBounds*/, 0f /*aspectRatio*/, false, "initialMove"); // Ensure a task has moved over. ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, firstTask); ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, secondTask); // Move second activity to pinned stack. service.mStackSupervisor.moveActivityToPinnedStackLocked(secondActivity, new Rect() /*sourceBounds*/, 0f /*aspectRatio*/ /*destBounds*/, false, "secondMove"); // Ensure stacks have swapped tasks. ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, secondTask); ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask); } private static void ensureStackPlacement(ActivityStackSupervisor supervisor, int stackId, TaskRecord... tasks) { final ActivityStack stack = supervisor.getStack(stackId); final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); if (tasks == null) { return; } for (TaskRecord task : tasks) { assertTrue(stackTasks.contains(task)); } } } services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +8 −9 Original line number Diff line number Diff line Loading @@ -37,28 +37,27 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityStackTests extends ActivityTestsBase { private final ComponentName testActivityComponent = private static final int TEST_STACK_ID = 100; private static final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); @Test public void testEmptyTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); assertNotNull(task.getWindowContainerController()); testStack.removeTask(task, "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNull(task.getWindowContainerController()); } @Test public void testOccupiedTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); assertNotNull(task.getWindowContainerController()); testStack.removeTask(task, "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNotNull(task.getWindowContainerController()); } } Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +4 −0 Original line number Diff line number Diff line Loading @@ -2878,6 +2878,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mWindowManager.deferSurfaceLayout(); // This will clear the pinned stack by moving an existing task to the full screen stack, // ensuring only one task is present. moveTasksToFullscreenStackLocked(PINNED_STACK_ID, !ON_TOP); // Need to make sure the pinned stack exist so we can resize it below... final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); Loading
services/core/java/com/android/server/am/TaskRecord.java +16 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.util.XmlUtils; Loading Loading @@ -445,10 +446,23 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); final Configuration overrideConfig = getOverrideConfiguration(); mWindowContainerController = new TaskWindowContainerController(taskId, this, setWindowContainerController(new TaskWindowContainerController(taskId, this, getStack().getWindowContainerController(), userId, bounds, overrideConfig, mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers, lastTaskDescription); lastTaskDescription)); } /** * Should only be invoked from {@link #createWindowContainer(boolean, boolean)}. */ @VisibleForTesting protected void setWindowContainerController(TaskWindowContainerController controller) { if (mWindowContainerController != null) { throw new IllegalArgumentException("Window container=" + mWindowContainerController + " already created for task=" + this); } mWindowContainerController = controller; } void removeWindowContainer() { Loading
services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +27 −15 Original line number Diff line number Diff line Loading @@ -16,7 +16,8 @@ package com.android.server.am; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import android.content.ComponentName; import android.platform.test.annotations.Presubmit; Loading @@ -36,50 +37,61 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityRecordTests extends ActivityTestsBase { private static final int TEST_STACK_ID = 100; private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); @Test public void testStackCleanupOnClearingTask() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); record.setTask(null); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); } @Test public void testStackCleanupOnActivityRemoval() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); task.removeActivity(record); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); } @Test public void testStackCleanupOnTaskRemoval() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); testStack.removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); service.mStackSupervisor.getStack(TEST_STACK_ID) .removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); // Stack should be gone on task removal. assertNull(service.mStackSupervisor.getStack(TEST_STACK_ID)); } @Test public void testNoCleanupMovingActivityInSameStack() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord oldTask = createTask(service, testActivityComponent, testStack); final TaskRecord oldTask = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, oldTask); final TaskRecord newTask = createTask(service, testActivityComponent, testStack); final TaskRecord newTask = createTask(service, testActivityComponent, TEST_STACK_ID); record.reparent(newTask, 0, null /*reason*/); assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 0); assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 0); } private static int getActivityRemovedFromStackCount(ActivityManagerService service, int stackId) { final ActivityStack stack = service.mStackSupervisor.getStack(stackId); if (stack instanceof ActivityStackReporter) { return ((ActivityStackReporter) stack).onActivityRemovedFromStackInvocationCount(); } return -1; } }
services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +68 −0 Original line number Diff line number Diff line Loading @@ -16,8 +16,14 @@ package com.android.server.am; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.content.ComponentName; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; Loading @@ -25,6 +31,10 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.runner.RunWith; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; /** Loading @@ -37,6 +47,9 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityStackSupervisorTests extends ActivityTestsBase { private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); /** * This test ensures that we do not try to restore a task based off an invalid task id. The * stack supervisor is a test version so there will be no tasks present. We should expect Loading @@ -49,4 +62,59 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/); assertNull(task); } /** * This test ensures that an existing task in the pinned stack is moved to the fullscreen * activity stack when a new task is added. */ @Test public void testReplacingTaskInPinnedStack() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TaskRecord firstTask = createTask(service, testActivityComponent, FULLSCREEN_WORKSPACE_STACK_ID); final ActivityRecord firstActivity = createActivity(service, testActivityComponent, firstTask); // Create a new task on the full screen stack final TaskRecord secondTask = createTask(service, testActivityComponent, FULLSCREEN_WORKSPACE_STACK_ID); final ActivityRecord secondActivity = createActivity(service, testActivityComponent, secondTask); service.mStackSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", service.mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID)); // Ensure full screen stack has both tasks. ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask, secondTask); // Move first activity to pinned stack. service.mStackSupervisor.moveActivityToPinnedStackLocked(firstActivity, new Rect() /*sourceBounds*/, 0f /*aspectRatio*/, false, "initialMove"); // Ensure a task has moved over. ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, firstTask); ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, secondTask); // Move second activity to pinned stack. service.mStackSupervisor.moveActivityToPinnedStackLocked(secondActivity, new Rect() /*sourceBounds*/, 0f /*aspectRatio*/ /*destBounds*/, false, "secondMove"); // Ensure stacks have swapped tasks. ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, secondTask); ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask); } private static void ensureStackPlacement(ActivityStackSupervisor supervisor, int stackId, TaskRecord... tasks) { final ActivityStack stack = supervisor.getStack(stackId); final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); if (tasks == null) { return; } for (TaskRecord task : tasks) { assertTrue(stackTasks.contains(task)); } } }
services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +8 −9 Original line number Diff line number Diff line Loading @@ -37,28 +37,27 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityStackTests extends ActivityTestsBase { private final ComponentName testActivityComponent = private static final int TEST_STACK_ID = 100; private static final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); @Test public void testEmptyTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); assertNotNull(task.getWindowContainerController()); testStack.removeTask(task, "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNull(task.getWindowContainerController()); } @Test public void testOccupiedTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); final TestActivityStack testStack = new ActivityStackBuilder(service).build(); final TaskRecord task = createTask(service, testActivityComponent, testStack); final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); assertNotNull(task.getWindowContainerController()); testStack.removeTask(task, "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNotNull(task.getWindowContainerController()); } }