diff options
3 files changed, 315 insertions, 98 deletions
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java index 4300e84e8044..2ca011bfe000 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java @@ -16,10 +16,12 @@ package com.android.wm.shell.shared; +import static android.app.WindowConfiguration.windowingModeToString; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; + import android.annotation.IntDef; import android.app.ActivityManager.RecentTaskInfo; import android.app.TaskInfo; -import android.app.WindowConfiguration; import android.os.Parcel; import android.os.Parcelable; @@ -28,11 +30,14 @@ import androidx.annotation.Nullable; import com.android.wm.shell.shared.split.SplitBounds; +import kotlin.collections.CollectionsKt; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; /** * Simple container for recent tasks which should be presented as a single task within the @@ -43,11 +48,13 @@ public class GroupedTaskInfo implements Parcelable { public static final int TYPE_FULLSCREEN = 1; public static final int TYPE_SPLIT = 2; public static final int TYPE_FREEFORM = 3; + public static final int TYPE_MIXED = 4; @IntDef(prefix = {"TYPE_"}, value = { TYPE_FULLSCREEN, TYPE_SPLIT, - TYPE_FREEFORM + TYPE_FREEFORM, + TYPE_MIXED }) public @interface GroupType {} @@ -64,7 +71,7 @@ public class GroupedTaskInfo implements Parcelable { * TYPE_SPLIT: Contains the two split roots of each side * TYPE_FREEFORM: Contains the set of tasks currently in freeform mode */ - @NonNull + @Nullable protected final List<TaskInfo> mTasks; /** @@ -85,6 +92,14 @@ public class GroupedTaskInfo implements Parcelable { protected final int[] mMinimizedTaskIds; /** + * Only set for TYPE_MIXED. + * + * The mixed set of task infos in this group. + */ + @Nullable + protected final List<GroupedTaskInfo> mGroupedTasks; + + /** * Create new for a stack of fullscreen tasks */ public static GroupedTaskInfo forFullscreenTasks(@NonNull TaskInfo task) { @@ -111,18 +126,41 @@ public class GroupedTaskInfo implements Parcelable { minimizedFreeformTasks.stream().mapToInt(i -> i).toArray()); } + /** + * Create new for a group of grouped task infos, those grouped task infos may not be mixed + * themselves (ie. multiple depths of mixed grouped task infos are not allowed). + */ + public static GroupedTaskInfo forMixed(@NonNull List<GroupedTaskInfo> groupedTasks) { + if (groupedTasks.isEmpty()) { + throw new IllegalArgumentException("Expected non-empty grouped task list"); + } + if (groupedTasks.stream().anyMatch(task -> task.mType == TYPE_MIXED)) { + throw new IllegalArgumentException("Unexpected grouped task list"); + } + return new GroupedTaskInfo(groupedTasks); + } + private GroupedTaskInfo( @NonNull List<TaskInfo> tasks, @Nullable SplitBounds splitBounds, @GroupType int type, @Nullable int[] minimizedFreeformTaskIds) { mTasks = tasks; + mGroupedTasks = null; mSplitBounds = splitBounds; mType = type; mMinimizedTaskIds = minimizedFreeformTaskIds; ensureAllMinimizedIdsPresent(tasks, minimizedFreeformTaskIds); } + private GroupedTaskInfo(@NonNull List<GroupedTaskInfo> groupedTasks) { + mTasks = null; + mGroupedTasks = groupedTasks; + mSplitBounds = null; + mType = TYPE_MIXED; + mMinimizedTaskIds = null; + } + private void ensureAllMinimizedIdsPresent( @NonNull List<TaskInfo> tasks, @Nullable int[] minimizedFreeformTaskIds) { @@ -141,26 +179,47 @@ public class GroupedTaskInfo implements Parcelable { for (int i = 0; i < numTasks; i++) { mTasks.add(new TaskInfo(parcel)); } + mGroupedTasks = parcel.createTypedArrayList(GroupedTaskInfo.CREATOR); mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR); mType = parcel.readInt(); mMinimizedTaskIds = parcel.createIntArray(); } /** - * Get primary {@link RecentTaskInfo} + * If TYPE_MIXED, returns the root of the grouped tasks + * For all other types, returns this task itself + */ + @NonNull + public GroupedTaskInfo getBaseGroupedTask() { + if (mType == TYPE_MIXED) { + return mGroupedTasks.getFirst(); + } + return this; + } + + /** + * Get primary {@link TaskInfo}. + * + * @throws IllegalStateException if the group is TYPE_MIXED. */ @NonNull public TaskInfo getTaskInfo1() { + if (mType == TYPE_MIXED) { + throw new IllegalStateException("No indexed tasks for a mixed task"); + } return mTasks.getFirst(); } /** - * Get secondary {@link RecentTaskInfo}. + * Get secondary {@link TaskInfo}, used primarily for TYPE_SPLIT. * - * Used in split screen. + * @throws IllegalStateException if the group is TYPE_MIXED. */ @Nullable public TaskInfo getTaskInfo2() { + if (mType == TYPE_MIXED) { + throw new IllegalStateException("No indexed tasks for a mixed task"); + } if (mTasks.size() > 1) { return mTasks.get(1); } @@ -172,9 +231,7 @@ public class GroupedTaskInfo implements Parcelable { */ @Nullable public TaskInfo getTaskById(int taskId) { - return mTasks.stream() - .filter(task -> task.taskId == taskId) - .findFirst().orElse(null); + return CollectionsKt.firstOrNull(getTaskInfoList(), taskInfo -> taskInfo.taskId == taskId); } /** @@ -182,35 +239,59 @@ public class GroupedTaskInfo implements Parcelable { */ @NonNull public List<TaskInfo> getTaskInfoList() { - return mTasks; + if (mType == TYPE_MIXED) { + return CollectionsKt.flatMap(mGroupedTasks, groupedTaskInfo -> groupedTaskInfo.mTasks); + } else { + return mTasks; + } } /** * @return Whether this grouped task contains a task with the given {@code taskId}. */ public boolean containsTask(int taskId) { - return mTasks.stream() - .anyMatch((task -> task.taskId == taskId)); + return getTaskById(taskId) != null; } /** - * Return {@link SplitBounds} if this is a split screen entry or {@code null} + * Returns whether the group is of the given type, if this is a TYPE_MIXED group, then returns + * whether the root task info is of the given type. + */ + public boolean isBaseType(@GroupType int type) { + return getBaseGroupedTask().mType == type; + } + + /** + * Return {@link SplitBounds} if this is a split screen entry or {@code null}. Only valid for + * TYPE_SPLIT. */ @Nullable public SplitBounds getSplitBounds() { + if (mType == TYPE_MIXED) { + throw new IllegalStateException("No split bounds for a mixed task"); + } return mSplitBounds; } /** - * Get type of this recents entry. One of {@link GroupType} + * Get type of this recents entry. One of {@link GroupType}. + * Note: This is deprecated, callers should use `isBaseType()` and not make assumptions about + * specific group types */ + @Deprecated @GroupType public int getType() { return mType; } + /** + * Returns the set of minimized task ids, only valid for TYPE_FREEFORM. + */ @Nullable public int[] getMinimizedTaskIds() { + if (mType == TYPE_MIXED) { + throw new IllegalStateException("No minimized task ids for a mixed task"); + } return mMinimizedTaskIds; } @@ -222,67 +303,64 @@ public class GroupedTaskInfo implements Parcelable { GroupedTaskInfo other = (GroupedTaskInfo) obj; return mType == other.mType && Objects.equals(mTasks, other.mTasks) + && Objects.equals(mGroupedTasks, other.mGroupedTasks) && Objects.equals(mSplitBounds, other.mSplitBounds) && Arrays.equals(mMinimizedTaskIds, other.mMinimizedTaskIds); } @Override public int hashCode() { - return Objects.hash(mType, mTasks, mSplitBounds, Arrays.hashCode(mMinimizedTaskIds)); + return Objects.hash(mType, mTasks, mGroupedTasks, mSplitBounds, + Arrays.hashCode(mMinimizedTaskIds)); } @Override public String toString() { StringBuilder taskString = new StringBuilder(); - for (int i = 0; i < mTasks.size(); i++) { - if (i == 0) { - taskString.append("Task"); - } else { - taskString.append(", Task"); + if (mType == TYPE_MIXED) { + taskString.append("GroupedTasks=" + mGroupedTasks.stream() + .map(GroupedTaskInfo::toString) + .collect(Collectors.joining(",\n\t", "[\n\t", "\n]"))); + } else { + taskString.append("Tasks=" + mTasks.stream() + .map(taskInfo -> getTaskInfoDumpString(taskInfo)) + .collect(Collectors.joining(", ", "[", "]"))); + if (mSplitBounds != null) { + taskString.append(", SplitBounds=").append(mSplitBounds); } - taskString.append(i + 1).append(": ").append(getTaskInfo(mTasks.get(i))); + taskString.append(", Type=" + typeToString(mType)); + taskString.append(", Minimized Task IDs=" + Arrays.toString(mMinimizedTaskIds)); } - if (mSplitBounds != null) { - taskString.append(", SplitBounds: ").append(mSplitBounds); - } - taskString.append(", Type="); - switch (mType) { - case TYPE_FULLSCREEN: - taskString.append("TYPE_FULLSCREEN"); - break; - case TYPE_SPLIT: - taskString.append("TYPE_SPLIT"); - break; - case TYPE_FREEFORM: - taskString.append("TYPE_FREEFORM"); - break; - } - taskString.append(", Minimized Task IDs: "); - taskString.append(Arrays.toString(mMinimizedTaskIds)); return taskString.toString(); } - private String getTaskInfo(TaskInfo taskInfo) { + private String getTaskInfoDumpString(TaskInfo taskInfo) { if (taskInfo == null) { return null; } + final boolean isExcluded = (taskInfo.baseIntent.getFlags() + & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; return "id=" + taskInfo.taskId - + " baseIntent=" + - (taskInfo.baseIntent != null && taskInfo.baseIntent.getComponent() != null - ? taskInfo.baseIntent.getComponent().flattenToString() - : "null") - + " winMode=" + WindowConfiguration.windowingModeToString( - taskInfo.getWindowingMode()); + + " winMode=" + windowingModeToString(taskInfo.getWindowingMode()) + + " visReq=" + taskInfo.isVisibleRequested + + " vis=" + taskInfo.isVisible + + " excluded=" + isExcluded + + " baseIntent=" + + (taskInfo.baseIntent != null && taskInfo.baseIntent.getComponent() != null + ? taskInfo.baseIntent.getComponent().flattenToShortString() + : "null"); } @Override public void writeToParcel(Parcel parcel, int flags) { // We don't use the parcel list methods because we want to only write the TaskInfo state // and not the subclasses (Recents/RunningTaskInfo) whose fields are all deprecated - parcel.writeInt(mTasks.size()); - for (int i = 0; i < mTasks.size(); i++) { + final int tasksSize = mTasks != null ? mTasks.size() : 0; + parcel.writeInt(tasksSize); + for (int i = 0; i < tasksSize; i++) { mTasks.get(i).writeTaskToParcel(parcel, flags); } + parcel.writeTypedList(mGroupedTasks); parcel.writeTypedObject(mSplitBounds, flags); parcel.writeInt(mType); parcel.writeIntArray(mMinimizedTaskIds); @@ -293,6 +371,16 @@ public class GroupedTaskInfo implements Parcelable { return 0; } + private String typeToString(@GroupType int type) { + return switch (type) { + case TYPE_FULLSCREEN -> "FULLSCREEN"; + case TYPE_SPLIT -> "SPLIT"; + case TYPE_FREEFORM -> "FREEFORM"; + case TYPE_MIXED -> "MIXED"; + default -> "UNKNOWN"; + }; + } + public static final Creator<GroupedTaskInfo> CREATOR = new Creator() { @Override public GroupedTaskInfo createFromParcel(Parcel in) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt index fd3adabfd44b..32096645aea7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt @@ -40,6 +40,7 @@ import org.mockito.Mockito.mock /** * Tests for [GroupedTaskInfo] + * Build & Run: atest WMShellUnitTests:GroupedTaskInfoTest */ @SmallTest @RunWith(AndroidTestingRunner::class) @@ -47,7 +48,7 @@ class GroupedTaskInfoTest : ShellTestCase() { @Test fun testSingleTask_hasCorrectType() { - assertThat(singleTaskGroupInfo().type).isEqualTo(TYPE_FULLSCREEN) + assertThat(singleTaskGroupInfo().isBaseType(TYPE_FULLSCREEN)).isTrue() } @Test @@ -66,7 +67,7 @@ class GroupedTaskInfoTest : ShellTestCase() { @Test fun testSplitTasks_hasCorrectType() { - assertThat(splitTasksGroupInfo().type).isEqualTo(TYPE_SPLIT) + assertThat(splitTasksGroupInfo().isBaseType(TYPE_SPLIT)).isTrue() } @Test @@ -87,8 +88,8 @@ class GroupedTaskInfoTest : ShellTestCase() { @Test fun testFreeformTasks_hasCorrectType() { - assertThat(freeformTasksGroupInfo(freeformTaskIds = arrayOf(1)).type) - .isEqualTo(TYPE_FREEFORM) + assertThat(freeformTasksGroupInfo(freeformTaskIds = arrayOf(1)).isBaseType(TYPE_FREEFORM)) + .isTrue() } @Test @@ -111,83 +112,155 @@ class GroupedTaskInfoTest : ShellTestCase() { } @Test + fun testMixedWithFullscreenBase_hasCorrectType() { + assertThat(mixedTaskGroupInfoWithFullscreenBase().isBaseType(TYPE_FULLSCREEN)).isTrue() + } + + @Test + fun testMixedWithSplitBase_hasCorrectType() { + assertThat(mixedTaskGroupInfoWithSplitBase().isBaseType(TYPE_SPLIT)).isTrue() + } + + @Test + fun testMixedWithFreeformBase_hasCorrectType() { + assertThat(mixedTaskGroupInfoWithFreeformBase().isBaseType(TYPE_FREEFORM)).isTrue() + } + + @Test + fun testMixed_disallowEmptyMixed() { + assertThrows(IllegalArgumentException::class.java) { + GroupedTaskInfo.forMixed(listOf()) + } + } + + @Test + fun testMixed_disallowNestedMixed() { + assertThrows(IllegalArgumentException::class.java) { + GroupedTaskInfo.forMixed(listOf( + GroupedTaskInfo.forMixed(listOf(singleTaskGroupInfo())))) + } + } + + @Test + fun testMixed_disallowNonMixedAccessors() { + val mixed = mixedTaskGroupInfoWithFullscreenBase() + assertThrows(IllegalStateException::class.java) { + mixed.taskInfo1 + } + assertThrows(IllegalStateException::class.java) { + mixed.taskInfo2 + } + assertThrows(IllegalStateException::class.java) { + mixed.splitBounds + } + assertThrows(IllegalStateException::class.java) { + mixed.minimizedTaskIds + } + } + + @Test fun testParcelling_singleTask() { - val recentTaskInfo = singleTaskGroupInfo() + val taskInfo = singleTaskGroupInfo() val parcel = Parcel.obtain() - recentTaskInfo.writeToParcel(parcel, 0) + taskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) // Read the object back from the parcel - val recentTaskInfoParcel: GroupedTaskInfo = + val taskInfoFromParcel: GroupedTaskInfo = GroupedTaskInfo.CREATOR.createFromParcel(parcel) - assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FULLSCREEN) - assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1) - assertThat(recentTaskInfoParcel.taskInfo2).isNull() + assertThat(taskInfoFromParcel.isBaseType(TYPE_FULLSCREEN)).isTrue() + assertThat(taskInfoFromParcel.taskInfo1.taskId).isEqualTo(1) + assertThat(taskInfoFromParcel.taskInfo2).isNull() } @Test fun testParcelling_splitTasks() { - val recentTaskInfo = splitTasksGroupInfo() + val taskInfo = splitTasksGroupInfo() val parcel = Parcel.obtain() - recentTaskInfo.writeToParcel(parcel, 0) + taskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) // Read the object back from the parcel - val recentTaskInfoParcel: GroupedTaskInfo = + val taskInfoFromParcel: GroupedTaskInfo = GroupedTaskInfo.CREATOR.createFromParcel(parcel) - assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SPLIT) - assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1) - assertThat(recentTaskInfoParcel.taskInfo2).isNotNull() - assertThat(recentTaskInfoParcel.taskInfo2!!.taskId).isEqualTo(2) - assertThat(recentTaskInfoParcel.splitBounds).isNotNull() - assertThat(recentTaskInfoParcel.splitBounds!!.snapPosition).isEqualTo(SNAP_TO_2_50_50) + assertThat(taskInfoFromParcel.isBaseType(TYPE_SPLIT)).isTrue() + assertThat(taskInfoFromParcel.taskInfo1.taskId).isEqualTo(1) + assertThat(taskInfoFromParcel.taskInfo2).isNotNull() + assertThat(taskInfoFromParcel.taskInfo2!!.taskId).isEqualTo(2) + assertThat(taskInfoFromParcel.splitBounds).isNotNull() + assertThat(taskInfoFromParcel.splitBounds!!.snapPosition).isEqualTo(SNAP_TO_2_50_50) } @Test fun testParcelling_freeformTasks() { - val recentTaskInfo = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)) + val taskInfo = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)) val parcel = Parcel.obtain() - recentTaskInfo.writeToParcel(parcel, 0) + taskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) // Read the object back from the parcel - val recentTaskInfoParcel: GroupedTaskInfo = + val taskInfoFromParcel: GroupedTaskInfo = GroupedTaskInfo.CREATOR.createFromParcel(parcel) - assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM) - assertThat(recentTaskInfoParcel.taskInfoList).hasSize(3) + assertThat(taskInfoFromParcel.isBaseType(TYPE_FREEFORM)).isTrue() + assertThat(taskInfoFromParcel.taskInfoList).hasSize(3) // Only compare task ids val taskIdComparator = Correspondence.transforming<TaskInfo, Int>( { it?.taskId }, "has taskId of" ) - assertThat(recentTaskInfoParcel.taskInfoList).comparingElementsUsing(taskIdComparator) - .containsExactly(1, 2, 3) + assertThat(taskInfoFromParcel.taskInfoList).comparingElementsUsing(taskIdComparator) + .containsExactly(1, 2, 3).inOrder() } @Test fun testParcelling_freeformTasks_minimizedTasks() { - val recentTaskInfo = freeformTasksGroupInfo( + val taskInfo = freeformTasksGroupInfo( freeformTaskIds = arrayOf(1, 2, 3), minimizedTaskIds = arrayOf(2)) val parcel = Parcel.obtain() - recentTaskInfo.writeToParcel(parcel, 0) + taskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) // Read the object back from the parcel - val recentTaskInfoParcel: GroupedTaskInfo = + val taskInfoFromParcel: GroupedTaskInfo = GroupedTaskInfo.CREATOR.createFromParcel(parcel) - assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM) - assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray()) + assertThat(taskInfoFromParcel.isBaseType(TYPE_FREEFORM)).isTrue() + assertThat(taskInfoFromParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray()) } @Test - fun testGetTaskById_singleTasks() { + fun testParcelling_mixedTasks() { + val taskInfo = GroupedTaskInfo.forMixed(listOf( + freeformTasksGroupInfo(freeformTaskIds = arrayOf(4, 5, 6), + minimizedTaskIds = arrayOf(5)), + splitTasksGroupInfo(firstId = 2, secondId = 3), + singleTaskGroupInfo(id = 1))) + + val parcel = Parcel.obtain() + taskInfo.writeToParcel(parcel, 0) + parcel.setDataPosition(0) + + // Read the object back from the parcel + val taskInfoFromParcel: GroupedTaskInfo = + GroupedTaskInfo.CREATOR.createFromParcel(parcel) + assertThat(taskInfoFromParcel.isBaseType(TYPE_FREEFORM)).isTrue() + assertThat(taskInfoFromParcel.baseGroupedTask.minimizedTaskIds).isEqualTo( + arrayOf(5).toIntArray()) + for (i in 1..6) { + assertThat(taskInfoFromParcel.containsTask(i)).isTrue() + } + assertThat(taskInfoFromParcel.taskInfoList).hasSize(taskInfo.taskInfoList.size) + } + + @Test + fun testTaskProperties_singleTasks() { val task1 = createTaskInfo(id = 1234) val taskInfo = GroupedTaskInfo.forFullscreenTasks(task1) assertThat(taskInfo.getTaskById(1234)).isEqualTo(task1) assertThat(taskInfo.containsTask(1234)).isTrue() + assertThat(taskInfo.taskInfoList).isEqualTo(listOf(task1)) } @Test - fun testGetTaskById_multipleTasks() { + fun testTaskProperties_splitTasks() { val task1 = createTaskInfo(id = 1) val task2 = createTaskInfo(id = 2) val splitBounds = SplitBounds(Rect(), Rect(), 1, 2, SNAP_TO_2_50_50) @@ -198,6 +271,41 @@ class GroupedTaskInfoTest : ShellTestCase() { assertThat(taskInfo.getTaskById(2)).isEqualTo(task2) assertThat(taskInfo.containsTask(1)).isTrue() assertThat(taskInfo.containsTask(2)).isTrue() + assertThat(taskInfo.taskInfoList).isEqualTo(listOf(task1, task2)) + } + + @Test + fun testTaskProperties_freeformTasks() { + val task1 = createTaskInfo(id = 1) + val task2 = createTaskInfo(id = 2) + + val taskInfo = GroupedTaskInfo.forFreeformTasks(listOf(task1, task2), setOf()) + + assertThat(taskInfo.getTaskById(1)).isEqualTo(task1) + assertThat(taskInfo.getTaskById(2)).isEqualTo(task2) + assertThat(taskInfo.containsTask(1)).isTrue() + assertThat(taskInfo.containsTask(2)).isTrue() + assertThat(taskInfo.taskInfoList).isEqualTo(listOf(task1, task2)) + } + + @Test + fun testTaskProperties_mixedTasks() { + val task1 = createTaskInfo(id = 1) + val task2 = createTaskInfo(id = 2) + val task3 = createTaskInfo(id = 3) + val splitBounds = SplitBounds(Rect(), Rect(), 1, 2, SNAP_TO_2_50_50) + + val splitTasks = GroupedTaskInfo.forSplitTasks(task1, task2, splitBounds) + val fullscreenTasks = GroupedTaskInfo.forFullscreenTasks(task3) + val mixedTasks = GroupedTaskInfo.forMixed(listOf(splitTasks, fullscreenTasks)) + + assertThat(mixedTasks.getTaskById(1)).isEqualTo(task1) + assertThat(mixedTasks.getTaskById(2)).isEqualTo(task2) + assertThat(mixedTasks.getTaskById(3)).isEqualTo(task3) + assertThat(mixedTasks.containsTask(1)).isTrue() + assertThat(mixedTasks.containsTask(2)).isTrue() + assertThat(mixedTasks.containsTask(3)).isTrue() + assertThat(mixedTasks.taskInfoList).isEqualTo(listOf(task1, task2, task3)) } private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply { @@ -205,14 +313,14 @@ class GroupedTaskInfoTest : ShellTestCase() { token = WindowContainerToken(mock(IWindowContainerToken::class.java)) } - private fun singleTaskGroupInfo(): GroupedTaskInfo { - val task = createTaskInfo(id = 1) + private fun singleTaskGroupInfo(id: Int = 1): GroupedTaskInfo { + val task = createTaskInfo(id) return GroupedTaskInfo.forFullscreenTasks(task) } - private fun splitTasksGroupInfo(): GroupedTaskInfo { - val task1 = createTaskInfo(id = 1) - val task2 = createTaskInfo(id = 2) + private fun splitTasksGroupInfo(firstId: Int = 1, secondId: Int = 2): GroupedTaskInfo { + val task1 = createTaskInfo(firstId) + val task2 = createTaskInfo(secondId) val splitBounds = SplitBounds(Rect(), Rect(), 1, 2, SNAP_TO_2_50_50) return GroupedTaskInfo.forSplitTasks(task1, task2, splitBounds) } @@ -225,4 +333,22 @@ class GroupedTaskInfoTest : ShellTestCase() { freeformTaskIds.map { createTaskInfo(it) }.toList(), minimizedTaskIds.toSet()) } + + private fun mixedTaskGroupInfoWithFullscreenBase(): GroupedTaskInfo { + return GroupedTaskInfo.forMixed(listOf( + singleTaskGroupInfo(id = 1), + singleTaskGroupInfo(id = 2))) + } + + private fun mixedTaskGroupInfoWithSplitBase(): GroupedTaskInfo { + return GroupedTaskInfo.forMixed(listOf( + splitTasksGroupInfo(firstId = 2, secondId = 3), + singleTaskGroupInfo(id = 1))) + } + + private fun mixedTaskGroupInfoWithFreeformBase(): GroupedTaskInfo { + return GroupedTaskInfo.forMixed(listOf( + freeformTasksGroupInfo(freeformTaskIds = arrayOf(2, 3, 4)), + singleTaskGroupInfo(id = 1))) + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index 22b45e8c63af..7e5d6ce38c5a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -24,6 +24,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.launcher3.Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE; +import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_FREEFORM; +import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_FULLSCREEN; +import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_SPLIT; import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50; import static org.junit.Assert.assertEquals; @@ -346,9 +349,9 @@ public class RecentTasksControllerTest extends ShellTestCase { GroupedTaskInfo singleGroup2 = recentTasks.get(2); // Check that groups have expected types - assertEquals(GroupedTaskInfo.TYPE_FREEFORM, freeformGroup.getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, singleGroup1.getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, singleGroup2.getType()); + assertTrue(freeformGroup.isBaseType(TYPE_FREEFORM)); + assertTrue(singleGroup1.isBaseType(TYPE_FULLSCREEN)); + assertTrue(singleGroup2.isBaseType(TYPE_FULLSCREEN)); // Check freeform group entries assertEquals(t1, freeformGroup.getTaskInfoList().get(0)); @@ -385,9 +388,9 @@ public class RecentTasksControllerTest extends ShellTestCase { GroupedTaskInfo singleGroup = recentTasks.get(2); // Check that groups have expected types - assertEquals(GroupedTaskInfo.TYPE_SPLIT, splitGroup.getType()); - assertEquals(GroupedTaskInfo.TYPE_FREEFORM, freeformGroup.getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, singleGroup.getType()); + assertTrue(splitGroup.isBaseType(TYPE_SPLIT)); + assertTrue(freeformGroup.isBaseType(TYPE_FREEFORM)); + assertTrue(singleGroup.isBaseType(TYPE_FULLSCREEN)); // Check freeform group entries assertEquals(t3, freeformGroup.getTaskInfoList().get(0)); @@ -420,10 +423,10 @@ public class RecentTasksControllerTest extends ShellTestCase { // Expect no grouping of tasks assertEquals(4, recentTasks.size()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, recentTasks.get(0).getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, recentTasks.get(1).getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, recentTasks.get(2).getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, recentTasks.get(3).getType()); + assertTrue(recentTasks.get(0).isBaseType(TYPE_FULLSCREEN)); + assertTrue(recentTasks.get(1).isBaseType(TYPE_FULLSCREEN)); + assertTrue(recentTasks.get(2).isBaseType(TYPE_FULLSCREEN)); + assertTrue(recentTasks.get(3).isBaseType(TYPE_FULLSCREEN)); assertEquals(t1, recentTasks.get(0).getTaskInfo1()); assertEquals(t2, recentTasks.get(1).getTaskInfo1()); @@ -457,9 +460,9 @@ public class RecentTasksControllerTest extends ShellTestCase { GroupedTaskInfo singleGroup2 = recentTasks.get(2); // Check that groups have expected types - assertEquals(GroupedTaskInfo.TYPE_FREEFORM, freeformGroup.getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, singleGroup1.getType()); - assertEquals(GroupedTaskInfo.TYPE_FULLSCREEN, singleGroup2.getType()); + assertTrue(freeformGroup.isBaseType(TYPE_FREEFORM)); + assertTrue(singleGroup1.isBaseType(TYPE_FULLSCREEN)); + assertTrue(singleGroup2.isBaseType(TYPE_FULLSCREEN)); // Check freeform group entries assertEquals(3, freeformGroup.getTaskInfoList().size()); |