diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt index a3157754b3..8a1b211ad9 100644 --- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt +++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt @@ -50,14 +50,15 @@ class TasksRepository( override fun getAllTaskData(forceRefresh: Boolean): Flow> { if (forceRefresh) { - recentsModel.getTasks { result -> + recentsModel.getTasks { newTaskList -> + val oldTaskMap = tasks.value val recentTasks = - result + newTaskList .flatMap { groupTask -> groupTask.tasks } .associateBy { it.key.id } - .also { hashMap -> + .also { newTaskMap -> // Clean tasks that are not in the latest group tasks list. - val tasksNoLongerVisible = hashMap.keys.subtract(tasks.value.keys) + val tasksNoLongerVisible = oldTaskMap.keys.subtract(newTaskMap.keys) removeTasks(tasksNoLongerVisible) // Use pre-loaded thumbnail data and icon from the previous list. @@ -66,12 +67,12 @@ class TasksRepository( val cache = taskRequests.keys .mapNotNull { key -> - val task = tasks.value[key] ?: return@mapNotNull null + val task = oldTaskMap[key] ?: return@mapNotNull null key to Pair(task.thumbnail, task.icon) } .toMap() - hashMap.values.forEach { task -> + newTaskMap.values.forEach { task -> task.thumbnail = task.thumbnail ?: cache[task.key.id]?.first task.icon = task.icon ?: cache[task.key.id]?.second } 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 624310b785..ee1ec6e387 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 @@ -37,7 +37,9 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.spy import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @OptIn(ExperimentalCoroutinesApi::class) @@ -56,7 +58,7 @@ class TasksRepositoryTest { private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier() private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier() private val taskVisualsChangedDelegate = - TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier) + spy(TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)) private val dispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(dispatcher) @@ -130,6 +132,29 @@ class TasksRepositoryTest { assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1) } + @Test + fun getAllTaskData_clearsPreviouslyLoadedImagesForRemovedTasks() = + testScope.runTest { + // Setup data + recentsModel.seedTasks(defaultTaskList) + systemUnderTest.getAllTaskData(forceRefresh = true) + val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1] + + // Load images for task 1 + systemUnderTest.setVisibleTasks(setOf(1)) + assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1) + + // Remove task 1 from "all data" + recentsModel.seedTasks( + defaultTaskList.filterNot { groupTask -> groupTask.tasks.any { it.key.id == 1 } } + ) + systemUnderTest.getAllTaskData(forceRefresh = true) + + // Assert task 1 was fully removed + assertThat(systemUnderTest.getThumbnailById(1).first()?.thumbnail).isNull() + verify(taskVisualsChangedDelegate).unregisterTaskThumbnailChangedCallback(tasks[1].key) + } + @Test fun getCurrentThumbnailByIdReturnsThumbnailWithLoadedThumbnails() = testScope.runTest {