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

Commit bae762cf authored by Michael Mikhail's avatar Michael Mikhail
Browse files

Switch currentMedia from StateFlow to snapshot state

Flag: com.android.systemui.media_controls_in_compose
Bug: 397989775
Test: atest SystemUiRoboTests:MediaRepositoryTest
Change-Id: Idd7b7238117ab584f0a9346b8b2e216b1c5ed913
parent 28329855
Loading
Loading
Loading
Loading
+38 −27
Original line number Diff line number Diff line
@@ -24,14 +24,19 @@ import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.remedia.data.model.MediaDataModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class MediaRepositoryTest : SysuiTestCase() {
@@ -42,6 +47,11 @@ class MediaRepositoryTest : SysuiTestCase() {

    private val underTest: MediaRepositoryImpl = kosmos.mediaRepository

    @Before
    fun setUp() {
        underTest.activateIn(testScope)
    }

    @Test
    fun addCurrentUserMediaEntry_activeThenInactivate() =
        testScope.runTest {
@@ -125,21 +135,20 @@ class MediaRepositoryTest : SysuiTestCase() {
    @Test
    fun addMediaControlPlayingThenRemote() =
        testScope.runTest {
            val currentMedia by collectLastValue(underTest.currentMedia)
            val playingInstanceId = InstanceId.fakeInstanceId(123)
            val remoteInstanceId = InstanceId.fakeInstanceId(321)
            val playingData = createMediaData("app1", true, LOCAL, false, playingInstanceId)
            val remoteData = createMediaData("app2", true, REMOTE, false, remoteInstanceId)

            underTest.addCurrentUserMediaEntry(playingData)

            underTest.addCurrentUserMediaEntry(remoteData)
            runCurrent()

            assertThat(currentMedia?.size).isEqualTo(2)
            assertThat(currentMedia)
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData.toDataModel(currentMedia!![0].controller),
                    remoteData.toDataModel(currentMedia!![1].controller),
                    playingData.toDataModel(underTest.currentMedia[0].controller),
                    remoteData.toDataModel(underTest.currentMedia[1].controller),
                )
                .inOrder()
        }
@@ -147,7 +156,6 @@ class MediaRepositoryTest : SysuiTestCase() {
    @Test
    fun switchMediaControlsPlaying() =
        testScope.runTest {
            val currentMedia by collectLastValue(underTest.currentMedia)
            val playingInstanceId1 = InstanceId.fakeInstanceId(123)
            val playingInstanceId2 = InstanceId.fakeInstanceId(321)
            var playingData1 = createMediaData("app1", true, LOCAL, false, playingInstanceId1)
@@ -155,12 +163,13 @@ class MediaRepositoryTest : SysuiTestCase() {

            underTest.addCurrentUserMediaEntry(playingData1)
            underTest.addCurrentUserMediaEntry(playingData2)
            runCurrent()

            assertThat(currentMedia?.size).isEqualTo(2)
            assertThat(currentMedia)
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData1.toDataModel(currentMedia!![0].controller),
                    playingData2.toDataModel(currentMedia!![1].controller),
                    playingData1.toDataModel(underTest.currentMedia[0].controller),
                    playingData2.toDataModel(underTest.currentMedia[1].controller),
                )
                .inOrder()

@@ -169,22 +178,24 @@ class MediaRepositoryTest : SysuiTestCase() {

            underTest.addCurrentUserMediaEntry(playingData1)
            underTest.addCurrentUserMediaEntry(playingData2)
            runCurrent()

            assertThat(currentMedia?.size).isEqualTo(2)
            assertThat(currentMedia)
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData1.toDataModel(currentMedia!![0].controller),
                    playingData2.toDataModel(currentMedia!![1].controller),
                    playingData1.toDataModel(underTest.currentMedia[0].controller),
                    playingData2.toDataModel(underTest.currentMedia[1].controller),
                )
                .inOrder()

            underTest.reorderMedia()
            runCurrent()

            assertThat(currentMedia?.size).isEqualTo(2)
            assertThat(currentMedia)
            assertThat(underTest.currentMedia.size).isEqualTo(2)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingData2.toDataModel(currentMedia!![0].controller),
                    playingData1.toDataModel(currentMedia!![1].controller),
                    playingData2.toDataModel(underTest.currentMedia[0].controller),
                    playingData1.toDataModel(underTest.currentMedia[1].controller),
                )
                .inOrder()
        }
@@ -192,7 +203,6 @@ class MediaRepositoryTest : SysuiTestCase() {
    @Test
    fun fullOrderTest() =
        testScope.runTest {
            val currentMedia by collectLastValue(underTest.currentMedia)
            val instanceId1 = InstanceId.fakeInstanceId(123)
            val instanceId2 = InstanceId.fakeInstanceId(456)
            val instanceId3 = InstanceId.fakeInstanceId(321)
@@ -215,15 +225,16 @@ class MediaRepositoryTest : SysuiTestCase() {
            underTest.addCurrentUserMediaEntry(playingAndRemoteData)

            underTest.reorderMedia()
            runCurrent()

            assertThat(currentMedia?.size).isEqualTo(5)
            assertThat(currentMedia)
            assertThat(underTest.currentMedia.size).isEqualTo(5)
            assertThat(underTest.currentMedia)
                .containsExactly(
                    playingAndLocalData.toDataModel(currentMedia!![0].controller),
                    playingAndRemoteData.toDataModel(currentMedia!![1].controller),
                    stoppedAndRemoteData.toDataModel(currentMedia!![2].controller),
                    stoppedAndLocalData.toDataModel(currentMedia!![3].controller),
                    canResumeData.toDataModel(currentMedia!![4].controller),
                    playingAndLocalData.toDataModel(underTest.currentMedia[0].controller),
                    playingAndRemoteData.toDataModel(underTest.currentMedia[1].controller),
                    stoppedAndRemoteData.toDataModel(underTest.currentMedia[2].controller),
                    stoppedAndLocalData.toDataModel(underTest.currentMedia[3].controller),
                    canResumeData.toDataModel(underTest.currentMedia[4].controller),
                )
                .inOrder()
        }
+12 −5
Original line number Diff line number Diff line
@@ -18,11 +18,14 @@ package com.android.systemui.media.remedia.data.repository

import android.content.Context
import android.media.session.MediaController
import androidx.compose.runtime.getValue
import com.android.internal.logging.InstanceId
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.lifecycle.Activatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.media.controls.data.model.MediaSortKeyModel
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.remedia.data.model.MediaDataModel
@@ -30,13 +33,11 @@ import com.android.systemui.util.time.SystemClock
import java.util.TreeMap
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

/** A repository that holds the state of current media on the device. */
interface MediaRepository {
interface MediaRepository : Activatable {
    /** Current sorted media sessions. */
    val currentMedia: StateFlow<List<MediaDataModel>>
    val currentMedia: List<MediaDataModel>

    /** Seek to [to], in milliseconds on the media session with the given [sessionKey]. */
    fun seek(sessionKey: InstanceId, to: Long)
@@ -51,9 +52,11 @@ class MediaRepositoryImpl
constructor(@Application private val context: Context, private val systemClock: SystemClock) :
    MediaRepository, MediaPipelineRepository() {

    private val hydrator = Hydrator(traceName = "MediaRepository.hydrator")
    private val mutableCurrentMedia: MutableStateFlow<List<MediaDataModel>> =
        MutableStateFlow(mutableListOf())
    override val currentMedia: StateFlow<List<MediaDataModel>> = mutableCurrentMedia.asStateFlow()
    override val currentMedia by
        hydrator.hydratedStateOf(traceName = "currentMedia", source = mutableCurrentMedia)

    private var sortedMedia = TreeMap<MediaSortKeyModel, MediaDataModel>(comparator)

@@ -91,6 +94,10 @@ constructor(@Application private val context: Context, private val systemClock:
        mutableCurrentMedia.value = sortedMedia.values.toList()
    }

    override suspend fun activate(): Nothing {
        hydrator.activate()
    }

    private fun addToSortedMedia(data: MediaData) {
        val sortedMap = TreeMap<MediaSortKeyModel, MediaDataModel>(comparator)
        val currentModel = sortedMedia.values.find { it.instanceId == data.instanceId }