Merge "Fix blank recent tasks thumbnails." into main
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 8c26d8f..a315775 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -51,17 +51,32 @@
     override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
         if (forceRefresh) {
             recentsModel.getTasks { result ->
-                tasks.value =
-                    MapForStateFlow(
-                        result
-                            .flatMap { groupTask -> groupTask.tasks }
-                            .associateBy { it.key.id }
-                            .also {
-                                // Clean tasks that are not in the latest group tasks list.
-                                val tasksNoLongerVisible = it.keys.subtract(tasks.value.keys)
-                                removeTasks(tasksNoLongerVisible)
+                val recentTasks =
+                    result
+                        .flatMap { groupTask -> groupTask.tasks }
+                        .associateBy { it.key.id }
+                        .also { hashMap ->
+                            // Clean tasks that are not in the latest group tasks list.
+                            val tasksNoLongerVisible = hashMap.keys.subtract(tasks.value.keys)
+                            removeTasks(tasksNoLongerVisible)
+
+                            // Use pre-loaded thumbnail data and icon from the previous list.
+                            // This reduces the Thumbnail loading time in the Overview and prevent
+                            // empty thumbnail and icon.
+                            val cache =
+                                taskRequests.keys
+                                    .mapNotNull { key ->
+                                        val task = tasks.value[key] ?: return@mapNotNull null
+                                        key to Pair(task.thumbnail, task.icon)
+                                    }
+                                    .toMap()
+
+                            hashMap.values.forEach { task ->
+                                task.thumbnail = task.thumbnail ?: cache[task.key.id]?.first
+                                task.icon = task.icon ?: cache[task.key.id]?.second
                             }
-                    )
+                        }
+                tasks.value = MapForStateFlow(recentTasks)
             }
         }
         return tasks.map { it.values.toList() }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
index eaeb513..9e99a0b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
@@ -20,10 +20,12 @@
 import java.util.function.Consumer
 
 class FakeRecentTasksDataSource : RecentTasksDataSource {
-    var taskList: List<GroupTask> = listOf()
+    private var taskList: List<GroupTask> = listOf()
 
     override fun getTasks(callback: Consumer<List<GroupTask>>?): Int {
-        callback?.accept(taskList)
+        // Makes a copy of the GroupTask to create a new GroupTask instance and to simulate
+        // RecentsModel::getTasks behavior.
+        callback?.accept(taskList.map { it.copy() })
         return 0
     }
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index e0e7f28..624310b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -117,6 +117,20 @@
         }
 
     @Test
+    fun whenThumbnailIsLoaded_getAllTaskData_usesPreviousLoadedThumbnailAndIcon() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+            val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+
+            systemUnderTest.setVisibleTasks(setOf(1))
+            assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
+
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+            assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
+        }
+
+    @Test
     fun getCurrentThumbnailByIdReturnsThumbnailWithLoadedThumbnails() =
         testScope.runTest {
             recentsModel.seedTasks(defaultTaskList)