Loading libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +10 −2 Original line number Diff line number Diff line Loading @@ -65,9 +65,11 @@ import com.android.wm.shell.util.SplitBounds; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; Loading Loading @@ -394,6 +396,7 @@ public class RecentTasksController implements TaskStackListenerCallback, } ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>(); Set<Integer> minimizedFreeformTasks = new HashSet<>(); int mostRecentFreeformTaskIndex = Integer.MAX_VALUE; Loading @@ -414,6 +417,9 @@ public class RecentTasksController implements TaskStackListenerCallback, mostRecentFreeformTaskIndex = recentTasks.size(); } freeformTasks.add(taskInfo); if (mDesktopModeTaskRepository.get().isMinimizedTask(taskInfo.taskId)) { minimizedFreeformTasks.add(taskInfo.taskId); } continue; } Loading @@ -431,8 +437,10 @@ public class RecentTasksController implements TaskStackListenerCallback, // Add a special entry for freeform tasks if (!freeformTasks.isEmpty()) { recentTasks.add(mostRecentFreeformTaskIndex, GroupedRecentTaskInfo.forFreeformTasks( freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0]))); recentTasks.add(mostRecentFreeformTaskIndex, GroupedRecentTaskInfo.forFreeformTasks( freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0]), minimizedFreeformTasks)); } return recentTasks; Loading libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java +40 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import java.util.Arrays; import java.util.List; import java.util.Set; /** * Simple container for recent tasks. May contain either a single or pair of tasks. Loading @@ -50,6 +51,9 @@ public class GroupedRecentTaskInfo implements Parcelable { private final SplitBounds mSplitBounds; @GroupType private final int mType; // TODO(b/348332802): move isMinimized inside each Task object instead once we have a // replacement for RecentTaskInfo private final int[] mMinimizedTaskIds; /** * Create new for a single task Loading @@ -57,7 +61,7 @@ public class GroupedRecentTaskInfo implements Parcelable { public static GroupedRecentTaskInfo forSingleTask( @NonNull ActivityManager.RecentTaskInfo task) { return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null, TYPE_SINGLE); TYPE_SINGLE, null /* minimizedFreeformTasks */); } /** Loading @@ -66,28 +70,51 @@ public class GroupedRecentTaskInfo implements Parcelable { public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1, @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) { return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2}, splitBounds, TYPE_SPLIT); splitBounds, TYPE_SPLIT, null /* minimizedFreeformTasks */); } /** * Create new for a group of freeform tasks */ public static GroupedRecentTaskInfo forFreeformTasks( @NonNull ActivityManager.RecentTaskInfo... tasks) { return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM); } private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks, @Nullable SplitBounds splitBounds, @GroupType int type) { @NonNull ActivityManager.RecentTaskInfo[] tasks, @NonNull Set<Integer> minimizedFreeformTasks) { return new GroupedRecentTaskInfo( tasks, null /* splitBounds */, TYPE_FREEFORM, minimizedFreeformTasks.stream().mapToInt(i -> i).toArray()); } private GroupedRecentTaskInfo( @NonNull ActivityManager.RecentTaskInfo[] tasks, @Nullable SplitBounds splitBounds, @GroupType int type, @Nullable int[] minimizedFreeformTaskIds) { mTasks = tasks; mSplitBounds = splitBounds; mType = type; mMinimizedTaskIds = minimizedFreeformTaskIds; ensureAllMinimizedIdsPresent(tasks, minimizedFreeformTaskIds); } private static void ensureAllMinimizedIdsPresent( @NonNull ActivityManager.RecentTaskInfo[] tasks, @Nullable int[] minimizedFreeformTaskIds) { if (minimizedFreeformTaskIds == null) { return; } if (!Arrays.stream(minimizedFreeformTaskIds).allMatch( taskId -> Arrays.stream(tasks).anyMatch(task -> task.taskId == taskId))) { throw new IllegalArgumentException("Minimized task IDs contain non-existent Task ID."); } } GroupedRecentTaskInfo(Parcel parcel) { mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR); mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR); mType = parcel.readInt(); mMinimizedTaskIds = parcel.createIntArray(); } /** Loading Loading @@ -135,6 +162,10 @@ public class GroupedRecentTaskInfo implements Parcelable { return mType; } public int[] getMinimizedTaskIds() { return mMinimizedTaskIds; } @Override public String toString() { StringBuilder taskString = new StringBuilder(); Loading @@ -161,6 +192,8 @@ public class GroupedRecentTaskInfo implements Parcelable { taskString.append("TYPE_FREEFORM"); break; } taskString.append(", Minimized Task IDs: "); taskString.append(Arrays.toString(mMinimizedTaskIds)); return taskString.toString(); } Loading @@ -181,6 +214,7 @@ public class GroupedRecentTaskInfo implements Parcelable { parcel.writeTypedArray(mTasks, flags); parcel.writeTypedObject(mSplitBounds, flags); parcel.writeInt(mType); parcel.writeIntArray(mMinimizedTaskIds); } @Override Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt +39 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.recents import android.app.ActivityManager import android.app.ActivityManager.RecentTaskInfo import android.graphics.Rect import android.os.Parcel import android.testing.AndroidTestingRunner Loading @@ -33,6 +34,7 @@ import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT import com.android.wm.shell.util.SplitBounds import com.google.common.truth.Correspondence import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock Loading Loading @@ -86,18 +88,29 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { @Test fun testFreeformTasks_hasCorrectType() { assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM) assertThat(freeformTasksGroupInfo(freeformTaskIds = arrayOf(1)).type) .isEqualTo(TYPE_FREEFORM) } @Test fun testSplitTasks_taskInfoList_hasThreeTasks() { val list = freeformTasksGroupInfo().taskInfoList fun testCreateFreeformTasks_hasCorrectNumberOfTasks() { val list = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)).taskInfoList assertThat(list).hasSize(3) assertThat(list[0].taskId).isEqualTo(1) assertThat(list[1].taskId).isEqualTo(2) assertThat(list[2].taskId).isEqualTo(3) } @Test fun testCreateFreeformTasks_nonExistentMinimizedTaskId_throwsException() { assertThrows(IllegalArgumentException::class.java) { freeformTasksGroupInfo( freeformTaskIds = arrayOf(1, 2, 3), minimizedTaskIds = arrayOf(1, 4) ) } } @Test fun testParcelling_singleTask() { val recentTaskInfo = singleTaskGroupInfo() Loading Loading @@ -129,7 +142,7 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { @Test fun testParcelling_freeformTasks() { val recentTaskInfo = freeformTasksGroupInfo() val recentTaskInfo = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)) val parcel = Parcel.obtain() recentTaskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) Loading @@ -145,6 +158,21 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { .containsExactly(1, 2, 3) } @Test fun testParcelling_freeformTasks_minimizedTasks() { val recentTaskInfo = freeformTasksGroupInfo( freeformTaskIds = arrayOf(1, 2, 3), minimizedTaskIds = arrayOf(2)) val parcel = Parcel.obtain() recentTaskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) // Read the object back from the parcel val recentTaskInfoParcel = CREATOR.createFromParcel(parcel) assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM) assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray()) } private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply { taskId = id token = WindowContainerToken(mock(IWindowContainerToken::class.java)) Loading @@ -162,10 +190,12 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds) } private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo { val task1 = createTaskInfo(id = 1) val task2 = createTaskInfo(id = 2) val task3 = createTaskInfo(id = 3) return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3) private fun freeformTasksGroupInfo( freeformTaskIds: Array<Int>, minimizedTaskIds: Array<Int> = emptyArray() ): GroupedRecentTaskInfo { return GroupedRecentTaskInfo.forFreeformTasks( freeformTaskIds.map { createTaskInfo(it) }.toTypedArray(), minimizedTaskIds.toSet()) } } packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +4 −0 Original line number Diff line number Diff line Loading @@ -249,6 +249,9 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public boolean isVisible; @ViewDebug.ExportedProperty(category = "recents") public boolean isMinimized; public Task() { // Do nothing } Loading Loading @@ -283,6 +286,7 @@ public class Task { positionInParent = other.positionInParent; appBounds = other.appBounds; isVisible = other.isVisible; isMinimized = other.isMinimized; } /** Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +10 −2 Original line number Diff line number Diff line Loading @@ -65,9 +65,11 @@ import com.android.wm.shell.util.SplitBounds; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; Loading Loading @@ -394,6 +396,7 @@ public class RecentTasksController implements TaskStackListenerCallback, } ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>(); Set<Integer> minimizedFreeformTasks = new HashSet<>(); int mostRecentFreeformTaskIndex = Integer.MAX_VALUE; Loading @@ -414,6 +417,9 @@ public class RecentTasksController implements TaskStackListenerCallback, mostRecentFreeformTaskIndex = recentTasks.size(); } freeformTasks.add(taskInfo); if (mDesktopModeTaskRepository.get().isMinimizedTask(taskInfo.taskId)) { minimizedFreeformTasks.add(taskInfo.taskId); } continue; } Loading @@ -431,8 +437,10 @@ public class RecentTasksController implements TaskStackListenerCallback, // Add a special entry for freeform tasks if (!freeformTasks.isEmpty()) { recentTasks.add(mostRecentFreeformTaskIndex, GroupedRecentTaskInfo.forFreeformTasks( freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0]))); recentTasks.add(mostRecentFreeformTaskIndex, GroupedRecentTaskInfo.forFreeformTasks( freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0]), minimizedFreeformTasks)); } return recentTasks; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java +40 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import java.util.Arrays; import java.util.List; import java.util.Set; /** * Simple container for recent tasks. May contain either a single or pair of tasks. Loading @@ -50,6 +51,9 @@ public class GroupedRecentTaskInfo implements Parcelable { private final SplitBounds mSplitBounds; @GroupType private final int mType; // TODO(b/348332802): move isMinimized inside each Task object instead once we have a // replacement for RecentTaskInfo private final int[] mMinimizedTaskIds; /** * Create new for a single task Loading @@ -57,7 +61,7 @@ public class GroupedRecentTaskInfo implements Parcelable { public static GroupedRecentTaskInfo forSingleTask( @NonNull ActivityManager.RecentTaskInfo task) { return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null, TYPE_SINGLE); TYPE_SINGLE, null /* minimizedFreeformTasks */); } /** Loading @@ -66,28 +70,51 @@ public class GroupedRecentTaskInfo implements Parcelable { public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1, @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) { return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2}, splitBounds, TYPE_SPLIT); splitBounds, TYPE_SPLIT, null /* minimizedFreeformTasks */); } /** * Create new for a group of freeform tasks */ public static GroupedRecentTaskInfo forFreeformTasks( @NonNull ActivityManager.RecentTaskInfo... tasks) { return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM); } private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks, @Nullable SplitBounds splitBounds, @GroupType int type) { @NonNull ActivityManager.RecentTaskInfo[] tasks, @NonNull Set<Integer> minimizedFreeformTasks) { return new GroupedRecentTaskInfo( tasks, null /* splitBounds */, TYPE_FREEFORM, minimizedFreeformTasks.stream().mapToInt(i -> i).toArray()); } private GroupedRecentTaskInfo( @NonNull ActivityManager.RecentTaskInfo[] tasks, @Nullable SplitBounds splitBounds, @GroupType int type, @Nullable int[] minimizedFreeformTaskIds) { mTasks = tasks; mSplitBounds = splitBounds; mType = type; mMinimizedTaskIds = minimizedFreeformTaskIds; ensureAllMinimizedIdsPresent(tasks, minimizedFreeformTaskIds); } private static void ensureAllMinimizedIdsPresent( @NonNull ActivityManager.RecentTaskInfo[] tasks, @Nullable int[] minimizedFreeformTaskIds) { if (minimizedFreeformTaskIds == null) { return; } if (!Arrays.stream(minimizedFreeformTaskIds).allMatch( taskId -> Arrays.stream(tasks).anyMatch(task -> task.taskId == taskId))) { throw new IllegalArgumentException("Minimized task IDs contain non-existent Task ID."); } } GroupedRecentTaskInfo(Parcel parcel) { mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR); mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR); mType = parcel.readInt(); mMinimizedTaskIds = parcel.createIntArray(); } /** Loading Loading @@ -135,6 +162,10 @@ public class GroupedRecentTaskInfo implements Parcelable { return mType; } public int[] getMinimizedTaskIds() { return mMinimizedTaskIds; } @Override public String toString() { StringBuilder taskString = new StringBuilder(); Loading @@ -161,6 +192,8 @@ public class GroupedRecentTaskInfo implements Parcelable { taskString.append("TYPE_FREEFORM"); break; } taskString.append(", Minimized Task IDs: "); taskString.append(Arrays.toString(mMinimizedTaskIds)); return taskString.toString(); } Loading @@ -181,6 +214,7 @@ public class GroupedRecentTaskInfo implements Parcelable { parcel.writeTypedArray(mTasks, flags); parcel.writeTypedObject(mSplitBounds, flags); parcel.writeInt(mType); parcel.writeIntArray(mMinimizedTaskIds); } @Override Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt +39 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.recents import android.app.ActivityManager import android.app.ActivityManager.RecentTaskInfo import android.graphics.Rect import android.os.Parcel import android.testing.AndroidTestingRunner Loading @@ -33,6 +34,7 @@ import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT import com.android.wm.shell.util.SplitBounds import com.google.common.truth.Correspondence import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock Loading Loading @@ -86,18 +88,29 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { @Test fun testFreeformTasks_hasCorrectType() { assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM) assertThat(freeformTasksGroupInfo(freeformTaskIds = arrayOf(1)).type) .isEqualTo(TYPE_FREEFORM) } @Test fun testSplitTasks_taskInfoList_hasThreeTasks() { val list = freeformTasksGroupInfo().taskInfoList fun testCreateFreeformTasks_hasCorrectNumberOfTasks() { val list = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)).taskInfoList assertThat(list).hasSize(3) assertThat(list[0].taskId).isEqualTo(1) assertThat(list[1].taskId).isEqualTo(2) assertThat(list[2].taskId).isEqualTo(3) } @Test fun testCreateFreeformTasks_nonExistentMinimizedTaskId_throwsException() { assertThrows(IllegalArgumentException::class.java) { freeformTasksGroupInfo( freeformTaskIds = arrayOf(1, 2, 3), minimizedTaskIds = arrayOf(1, 4) ) } } @Test fun testParcelling_singleTask() { val recentTaskInfo = singleTaskGroupInfo() Loading Loading @@ -129,7 +142,7 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { @Test fun testParcelling_freeformTasks() { val recentTaskInfo = freeformTasksGroupInfo() val recentTaskInfo = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)) val parcel = Parcel.obtain() recentTaskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) Loading @@ -145,6 +158,21 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { .containsExactly(1, 2, 3) } @Test fun testParcelling_freeformTasks_minimizedTasks() { val recentTaskInfo = freeformTasksGroupInfo( freeformTaskIds = arrayOf(1, 2, 3), minimizedTaskIds = arrayOf(2)) val parcel = Parcel.obtain() recentTaskInfo.writeToParcel(parcel, 0) parcel.setDataPosition(0) // Read the object back from the parcel val recentTaskInfoParcel = CREATOR.createFromParcel(parcel) assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM) assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray()) } private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply { taskId = id token = WindowContainerToken(mock(IWindowContainerToken::class.java)) Loading @@ -162,10 +190,12 @@ class GroupedRecentTaskInfoTest : ShellTestCase() { return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds) } private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo { val task1 = createTaskInfo(id = 1) val task2 = createTaskInfo(id = 2) val task3 = createTaskInfo(id = 3) return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3) private fun freeformTasksGroupInfo( freeformTaskIds: Array<Int>, minimizedTaskIds: Array<Int> = emptyArray() ): GroupedRecentTaskInfo { return GroupedRecentTaskInfo.forFreeformTasks( freeformTaskIds.map { createTaskInfo(it) }.toTypedArray(), minimizedTaskIds.toSet()) } }
packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +4 −0 Original line number Diff line number Diff line Loading @@ -249,6 +249,9 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public boolean isVisible; @ViewDebug.ExportedProperty(category = "recents") public boolean isMinimized; public Task() { // Do nothing } Loading Loading @@ -283,6 +286,7 @@ public class Task { positionInParent = other.positionInParent; appBounds = other.appBounds; isVisible = other.isVisible; isMinimized = other.isMinimized; } /** Loading