Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cbe5d27 authored by Anton Potapov's avatar Anton Potapov
Browse files

Make SliceViewManager calls from the main thread

SliceViewManager is not thread-safe which causes some
ConcurrentModificationException.

Flag: aconfig new_volume_panel NEXTFOOD
Test: atest AncSliceRepositoryTest
Test: manual on the phone with the headset. Check that callback register/unregister and slice binding happens on the main thread.
Fixes: 336713865
Fixes: 338240912
Change-Id: Idbc789d5b008fcb87551a95649f9eb4fc5fef582
parent 72c37464
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ class AncSliceRepositoryTest : SysuiTestCase() {
                AncSliceRepositoryImpl(
                AncSliceRepositoryImpl(
                    localMediaRepositoryFactory,
                    localMediaRepositoryFactory,
                    testScope.testScheduler,
                    testScope.testScheduler,
                    testScope.testScheduler,
                    sliceViewManager,
                    sliceViewManager,
                )
                )
        }
        }
+3 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,9 @@ import kotlinx.coroutines.launch
 * Returns updating [Slice] for a [sliceUri]. It's null when there is no slice available for the
 * Returns updating [Slice] for a [sliceUri]. It's null when there is no slice available for the
 * provided Uri. This can change overtime because of external changes (like device being
 * provided Uri. This can change overtime because of external changes (like device being
 * connected/disconnected).
 * connected/disconnected).
 *
 * The flow should be [kotlinx.coroutines.flow.flowOn] the main thread because [SliceViewManager]
 * isn't thread-safe. An exception will be thrown otherwise.
 */
 */
fun SliceViewManager.sliceForUri(sliceUri: Uri): Flow<Slice?> =
fun SliceViewManager.sliceForUri(sliceUri: Uri): Flow<Slice?> =
    ConflatedCallbackFlow.conflatedCallbackFlow {
    ConflatedCallbackFlow.conflatedCallbackFlow {
+3 −1
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import androidx.slice.SliceViewManager
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.media.BluetoothMediaDevice
import com.android.settingslib.media.BluetoothMediaDevice
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.slice.sliceForUri
import com.android.systemui.slice.sliceForUri
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import dagger.assisted.Assisted
import dagger.assisted.Assisted
@@ -57,6 +58,7 @@ class AncSliceRepositoryImpl
constructor(
constructor(
    mediaRepositoryFactory: LocalMediaRepositoryFactory,
    mediaRepositoryFactory: LocalMediaRepositoryFactory,
    @Background private val backgroundCoroutineContext: CoroutineContext,
    @Background private val backgroundCoroutineContext: CoroutineContext,
    @Main private val mainCoroutineContext: CoroutineContext,
    @Assisted private val sliceViewManager: SliceViewManager,
    @Assisted private val sliceViewManager: SliceViewManager,
) : AncSliceRepository {
) : AncSliceRepository {


@@ -73,7 +75,7 @@ constructor(
            .distinctUntilChanged()
            .distinctUntilChanged()
            .flatMapLatest { sliceUri ->
            .flatMapLatest { sliceUri ->
                sliceUri ?: return@flatMapLatest flowOf(null)
                sliceUri ?: return@flatMapLatest flowOf(null)
                sliceViewManager.sliceForUri(sliceUri)
                sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext)
            }
            }
            .flowOn(backgroundCoroutineContext)
            .flowOn(backgroundCoroutineContext)
    }
    }