From 4dc3313044eb38751673c85dcfa9f2bcbf276715 Mon Sep 17 00:00:00 2001 From: Uwais Ashraf Date: Sat, 12 Apr 2025 00:38:19 +0000 Subject: [PATCH] Use concurrent list to prevent ConcurrentModificationException TasksRepository.setVisibleTasks can add/remove listeners while HighResLoadingState.updateState iterates over them. Bug: 408978565 Flag: com.android.launcher3.enable_refactor_task_thumbnail Test: SwitchBackToSplitFromRecentGesturalNavLandscape#switchBackToSplitFromRecent Test: Manual - made exception extremely likely by constantly adding/removing listeners. Could easily repro exceptions, then added this CL and could no longer repro. Change-Id: Ic04717527fcbdb9301a6e313f9e666e2f5135b3e --- quickstep/src/com/android/quickstep/HighResLoadingState.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/HighResLoadingState.kt b/quickstep/src/com/android/quickstep/HighResLoadingState.kt index 8a21c4f613..aabaecfdfe 100644 --- a/quickstep/src/com/android/quickstep/HighResLoadingState.kt +++ b/quickstep/src/com/android/quickstep/HighResLoadingState.kt @@ -18,6 +18,7 @@ package com.android.quickstep import android.content.res.Resources import com.android.quickstep.recents.data.HighResLoadingStateNotifier +import java.util.concurrent.CopyOnWriteArrayList /** Determines when high res or low res thumbnails should be loaded. */ class HighResLoadingState : HighResLoadingStateNotifier { @@ -38,7 +39,7 @@ class HighResLoadingState : HighResLoadingStateNotifier { var isEnabled: Boolean = false private set - private val callbacks = ArrayList() + private val callbacks = CopyOnWriteArrayList() interface HighResLoadingStateChangedCallback { fun onHighResLoadingStateChanged(enabled: Boolean) @@ -56,7 +57,7 @@ class HighResLoadingState : HighResLoadingStateNotifier { val prevState = isEnabled isEnabled = forceHighResThumbnails || (visible && !flingingFast) if (prevState != isEnabled) { - for (callback in callbacks.asReversed()) { + for (callback in callbacks) { callback.onHighResLoadingStateChanged(isEnabled) } }