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

Commit 3cc2461e authored by Lucas Silva's avatar Lucas Silva
Browse files

Update UMO visibility each time ongoing content is updated

If media is started while the hub is already showing, UMO visibility may
not update correctly and therefore the UMO will not show until the next
time the hub is opened. This change ensures we update the visibility
each time new ongoing content arrives.

This change also immediately snaps to the new UMO to workaround a bug in
the animateScrollToItem function.

Bug: 362304980
Test: atest CommunalViewModelTest
Test: atest CommunalInteractorTest
Flag: com.android.systemui.communal_hub
Change-Id: I1019a42af22a1c398fe5698e7deb2ebb486ec3ee
parent ace98e70
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -567,16 +567,8 @@ private fun ScrollOnUpdatedLiveContentEffect(
        // Do nothing if there is no new live content
        val indexOfFirstUpdatedContent =
            newLiveContentKeys.indexOfFirst { !prevLiveContentKeys.contains(it) }
        if (indexOfFirstUpdatedContent < 0) {
            return@LaunchedEffect
        }

        // Scroll if the live content is not visible
        val lastVisibleItemIndex = gridState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
        if (lastVisibleItemIndex != null && indexOfFirstUpdatedContent > lastVisibleItemIndex) {
            // Launching with a scope to prevent the job from being canceled in the case of a
            // recomposition during scrolling
            coroutineScope.launch { gridState.animateScrollToItem(indexOfFirstUpdatedContent) }
        if (indexOfFirstUpdatedContent in 0 until gridState.firstVisibleItemIndex) {
            gridState.scrollToItem(indexOfFirstUpdatedContent)
        }
    }
}
+3 −17
Original line number Diff line number Diff line
@@ -352,7 +352,7 @@ class CommunalInteractorTest : SysuiTestCase() {

            smartspaceRepository.setTimers(targets)

            val smartspaceContent by collectLastValue(underTest.getOngoingContent(true))
            val smartspaceContent by collectLastValue(underTest.ongoingContent)
            assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
            for (index in 0 until totalTargets) {
                assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
@@ -368,27 +368,13 @@ class CommunalInteractorTest : SysuiTestCase() {
            // Media is playing.
            mediaRepository.mediaActive()

            val umoContent by collectLastValue(underTest.getOngoingContent(true))
            val umoContent by collectLastValue(underTest.ongoingContent)

            assertThat(umoContent?.size).isEqualTo(1)
            assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
            assertThat(umoContent?.get(0)?.key).isEqualTo(CommunalContentModel.KEY.umo())
        }

    @Test
    fun umo_mediaPlaying_doNotShowUmo() =
        testScope.run {
            // Tutorial completed.
            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            // Media is playing.
            mediaRepository.mediaActive()

            val umoContent by collectLastValue(underTest.getOngoingContent(false))

            assertThat(umoContent?.size).isEqualTo(0)
        }

    @Test
    fun ongoing_shouldOrderAndSizeByTimestamp() =
        testScope.runTest {
@@ -412,7 +398,7 @@ class CommunalInteractorTest : SysuiTestCase() {
            val timer3 = smartspaceTimer("timer3", timestamp = 4L)
            smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))

            val ongoingContent by collectLastValue(underTest.getOngoingContent(true))
            val ongoingContent by collectLastValue(underTest.ongoingContent)
            assertThat(ongoingContent?.size).isEqualTo(4)
            assertThat(ongoingContent?.get(0)?.key)
                .isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
+2 −1
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
@@ -757,7 +758,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {

            // updateViewVisibility is called when the flow is collected.
            assertThat(communalContent).isNotNull()
            verify(mediaHost).updateViewVisibility()
            verify(mediaHost, atLeastOnce()).updateViewVisibility()
        }

    @Test
+2 −2
Original line number Diff line number Diff line
@@ -510,7 +510,7 @@ constructor(
     * A flow of ongoing content, including smartspace timers and umo, ordered by creation time and
     * sized dynamically.
     */
    fun getOngoingContent(mediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> =
    val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> =
        combine(smartspaceRepository.timers, mediaRepository.mediaModel) { timers, media ->
                val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>()

@@ -526,7 +526,7 @@ constructor(
                )

                // Add UMO
                if (mediaHostVisible && media.hasAnyMediaOrRecommendation) {
                if (media.hasAnyMediaOrRecommendation) {
                    ongoingContent.add(
                        CommunalContentModel.Umo(
                            createdTimestampMillis = media.createdTimestampMillis,
+15 −3
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ constructor(

    private val logger = Logger(logBuffer, "CommunalViewModel")

    private val _isMediaHostVisible =
    private val isMediaHostVisible =
        conflatedCallbackFlow {
                val callback = { visible: Boolean ->
                    trySend(visible)
@@ -117,12 +117,26 @@ constructor(
                mediaHost.updateViewVisibility()
                emit(mediaHost.visible)
            }
            .distinctUntilChanged()
            .onEach { logger.d({ "_isMediaHostVisible: $bool1" }) { bool1 = it } }
            .flowOn(mainDispatcher)

    /** Communal content saved from the previous emission when the flow is active (not "frozen"). */
    private var frozenCommunalContent: List<CommunalContentModel>? = null

    private val ongoingContent =
        combine(
            isMediaHostVisible,
            communalInteractor.ongoingContent.onEach { mediaHost.updateViewVisibility() }
        ) { mediaVisible, ongoingContent ->
            if (mediaVisible) {
                ongoingContent
            } else {
                // Media is not visible, don't show UMO
                ongoingContent.filterNot { it is CommunalContentModel.Umo }
            }
        }

    @OptIn(ExperimentalCoroutinesApi::class)
    private val latestCommunalContent: Flow<List<CommunalContentModel>> =
        tutorialInteractor.isTutorialAvailable
@@ -130,8 +144,6 @@ constructor(
                if (isTutorialMode) {
                    return@flatMapLatest flowOf(communalInteractor.tutorialContent)
                }
                val ongoingContent =
                    _isMediaHostVisible.flatMapLatest { communalInteractor.getOngoingContent(it) }
                combine(
                    ongoingContent,
                    communalInteractor.widgetContent,