Loading services/core/java/com/android/server/am/RecentTasks.java +29 −1 Original line number Diff line number Diff line Loading @@ -22,8 +22,10 @@ import static android.app.ActivityManager.RECENT_WITH_EXCLUDED; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; Loading Loading @@ -1255,7 +1257,8 @@ class RecentTasks { for (int i = 0; i < recentsCount; i++) { final TaskRecord tr = mTasks.get(i); if (task != tr) { if (!task.hasCompatibleActivityType(tr) || task.userId != tr.userId) { if (!hasCompatibleActivityTypeAndWindowingMode(task, tr) || task.userId != tr.userId) { continue; } final Intent trIntent = tr.intent; Loading Loading @@ -1547,4 +1550,29 @@ class RecentTasks { return rti; } /** * @return Whether the activity types and windowing modes of the two tasks are considered * compatible. This is necessary because we currently don't persist the activity type * or the windowing mode with the task, so they can be undefined when restored. */ private boolean hasCompatibleActivityTypeAndWindowingMode(TaskRecord t1, TaskRecord t2) { final int activityType = t1.getActivityType(); final int windowingMode = t1.getWindowingMode(); final boolean isUndefinedType = activityType == ACTIVITY_TYPE_UNDEFINED; final boolean isUndefinedMode = windowingMode == WINDOWING_MODE_UNDEFINED; final int otherActivityType = t2.getActivityType(); final int otherWindowingMode = t2.getWindowingMode(); final boolean isOtherUndefinedType = otherActivityType == ACTIVITY_TYPE_UNDEFINED; final boolean isOtherUndefinedMode = otherWindowingMode == WINDOWING_MODE_UNDEFINED; // An activity type and windowing mode is compatible if they are the exact same type/mode, // or if one of the type/modes is undefined final boolean isCompatibleType = activityType == otherActivityType || isUndefinedType || isOtherUndefinedType; final boolean isCompatibleMode = windowingMode == otherWindowingMode || isUndefinedMode || isOtherUndefinedMode; return isCompatibleType && isCompatibleMode; } } services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +62 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 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_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; Loading Loading @@ -303,6 +304,8 @@ public class RecentTasksTest extends ActivityTestsBase { @Test public void testAddTaskCompatibleActivityType_expectRemove() throws Exception { // Test with undefined activity type since the type is not persisted by the task persister // and we want to ensure that a new task will match a restored task Configuration config1 = new Configuration(); config1.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); TaskRecord task1 = createTaskBuilder(".Task1") Loading Loading @@ -354,6 +357,65 @@ public class RecentTasksTest extends ActivityTestsBase { assertTrue(mCallbacksRecorder.removed.isEmpty()); } @Test public void testAddTaskCompatibleWindowingMode_expectRemove() throws Exception { Configuration config1 = new Configuration(); config1.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task1.onConfigurationChanged(config1); assertTrue(task1.getWindowingMode() == WINDOWING_MODE_UNDEFINED); mRecentTasks.add(task1); mCallbacksRecorder.clear(); Configuration config2 = new Configuration(); config2.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); TaskRecord task2 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task2.onConfigurationChanged(config2); assertTrue(task2.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); mRecentTasks.add(task2); assertTrue(mCallbacksRecorder.added.size() == 1); assertTrue(mCallbacksRecorder.added.contains(task2)); assertTrue(mCallbacksRecorder.trimmed.isEmpty()); assertTrue(mCallbacksRecorder.removed.size() == 1); assertTrue(mCallbacksRecorder.removed.contains(task1)); } @Test public void testAddTaskIncompatibleWindowingMode_expectNoRemove() throws Exception { Configuration config1 = new Configuration(); config1.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task1.onConfigurationChanged(config1); assertTrue(task1.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); mRecentTasks.add(task1); Configuration config2 = new Configuration(); config2.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED); TaskRecord task2 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task2.onConfigurationChanged(config2); assertTrue(task2.getWindowingMode() == WINDOWING_MODE_PINNED); mRecentTasks.add(task2); assertTrue(mCallbacksRecorder.added.size() == 2); assertTrue(mCallbacksRecorder.added.contains(task1)); assertTrue(mCallbacksRecorder.added.contains(task2)); assertTrue(mCallbacksRecorder.trimmed.isEmpty()); assertTrue(mCallbacksRecorder.removed.isEmpty()); } @Test public void testUsersTasks() throws Exception { mRecentTasks.setOnlyTestVisibleRange(); Loading Loading
services/core/java/com/android/server/am/RecentTasks.java +29 −1 Original line number Diff line number Diff line Loading @@ -22,8 +22,10 @@ import static android.app.ActivityManager.RECENT_WITH_EXCLUDED; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; Loading Loading @@ -1255,7 +1257,8 @@ class RecentTasks { for (int i = 0; i < recentsCount; i++) { final TaskRecord tr = mTasks.get(i); if (task != tr) { if (!task.hasCompatibleActivityType(tr) || task.userId != tr.userId) { if (!hasCompatibleActivityTypeAndWindowingMode(task, tr) || task.userId != tr.userId) { continue; } final Intent trIntent = tr.intent; Loading Loading @@ -1547,4 +1550,29 @@ class RecentTasks { return rti; } /** * @return Whether the activity types and windowing modes of the two tasks are considered * compatible. This is necessary because we currently don't persist the activity type * or the windowing mode with the task, so they can be undefined when restored. */ private boolean hasCompatibleActivityTypeAndWindowingMode(TaskRecord t1, TaskRecord t2) { final int activityType = t1.getActivityType(); final int windowingMode = t1.getWindowingMode(); final boolean isUndefinedType = activityType == ACTIVITY_TYPE_UNDEFINED; final boolean isUndefinedMode = windowingMode == WINDOWING_MODE_UNDEFINED; final int otherActivityType = t2.getActivityType(); final int otherWindowingMode = t2.getWindowingMode(); final boolean isOtherUndefinedType = otherActivityType == ACTIVITY_TYPE_UNDEFINED; final boolean isOtherUndefinedMode = otherWindowingMode == WINDOWING_MODE_UNDEFINED; // An activity type and windowing mode is compatible if they are the exact same type/mode, // or if one of the type/modes is undefined final boolean isCompatibleType = activityType == otherActivityType || isUndefinedType || isOtherUndefinedType; final boolean isCompatibleMode = windowingMode == otherWindowingMode || isUndefinedMode || isOtherUndefinedMode; return isCompatibleType && isCompatibleMode; } }
services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +62 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 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_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; Loading Loading @@ -303,6 +304,8 @@ public class RecentTasksTest extends ActivityTestsBase { @Test public void testAddTaskCompatibleActivityType_expectRemove() throws Exception { // Test with undefined activity type since the type is not persisted by the task persister // and we want to ensure that a new task will match a restored task Configuration config1 = new Configuration(); config1.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); TaskRecord task1 = createTaskBuilder(".Task1") Loading Loading @@ -354,6 +357,65 @@ public class RecentTasksTest extends ActivityTestsBase { assertTrue(mCallbacksRecorder.removed.isEmpty()); } @Test public void testAddTaskCompatibleWindowingMode_expectRemove() throws Exception { Configuration config1 = new Configuration(); config1.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task1.onConfigurationChanged(config1); assertTrue(task1.getWindowingMode() == WINDOWING_MODE_UNDEFINED); mRecentTasks.add(task1); mCallbacksRecorder.clear(); Configuration config2 = new Configuration(); config2.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); TaskRecord task2 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task2.onConfigurationChanged(config2); assertTrue(task2.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); mRecentTasks.add(task2); assertTrue(mCallbacksRecorder.added.size() == 1); assertTrue(mCallbacksRecorder.added.contains(task2)); assertTrue(mCallbacksRecorder.trimmed.isEmpty()); assertTrue(mCallbacksRecorder.removed.size() == 1); assertTrue(mCallbacksRecorder.removed.contains(task1)); } @Test public void testAddTaskIncompatibleWindowingMode_expectNoRemove() throws Exception { Configuration config1 = new Configuration(); config1.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task1.onConfigurationChanged(config1); assertTrue(task1.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); mRecentTasks.add(task1); Configuration config2 = new Configuration(); config2.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED); TaskRecord task2 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); task2.onConfigurationChanged(config2); assertTrue(task2.getWindowingMode() == WINDOWING_MODE_PINNED); mRecentTasks.add(task2); assertTrue(mCallbacksRecorder.added.size() == 2); assertTrue(mCallbacksRecorder.added.contains(task1)); assertTrue(mCallbacksRecorder.added.contains(task2)); assertTrue(mCallbacksRecorder.trimmed.isEmpty()); assertTrue(mCallbacksRecorder.removed.isEmpty()); } @Test public void testUsersTasks() throws Exception { mRecentTasks.setOnlyTestVisibleRange(); Loading