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

Commit 5e7a6fa6 authored by Darrell Shi's avatar Darrell Shi
Browse files

Listen for ongoing updates when communal enabled

This change makes it so that updates for ongoing content (media and
smartspace timers) are listened to as long as communal enabled.
Previously, media updates are always listened to, even when not
applicable. Smartspace updates were only listened to when communal was
showing, leading to delays and unexpected behavior when connections were
closed and reopened.

Test: atest CommunalOngoingContentStartable
Test: atest CommunalSmartspaceRepositoryImplTest
Test: atest CommunalMediaRepositoryImplTest
Bug: 322869039
Flag: com.android.systemui.communal_hub
Change-Id: I10c02d0a1e54d2dddef4f7979cdbee6fd0ba0efe
parent 3e0123cf
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.communal

import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalSmartspaceRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalEnabled
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
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
@EnableFlags(FLAG_COMMUNAL_HUB)
@RunWith(AndroidJUnit4::class)
class CommunalOngoingContentStartableTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    private val mediaRepository = kosmos.fakeCommunalMediaRepository
    private val smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository
    private val featureFlags =
        kosmos.fakeFeatureFlagsClassic.apply { set(Flags.COMMUNAL_SERVICE_ENABLED, true) }

    private lateinit var underTest: CommunalOngoingContentStartable

    @Before
    fun setUp() {
        underTest =
            CommunalOngoingContentStartable(
                bgScope = kosmos.applicationCoroutineScope,
                communalInteractor = kosmos.communalInteractor,
                communalMediaRepository = mediaRepository,
                communalSmartspaceRepository = smartspaceRepository,
                featureFlags = featureFlags,
            )
    }

    @Test
    fun testListenForOngoingContentWhenCommunalIsEnabled() =
        testScope.runTest {
            underTest.start()
            runCurrent()

            assertThat(mediaRepository.isListening()).isFalse()
            assertThat(smartspaceRepository.isListening()).isFalse()

            kosmos.setCommunalEnabled(true)
            runCurrent()

            assertThat(mediaRepository.isListening()).isTrue()
            assertThat(smartspaceRepository.isListening()).isTrue()

            kosmos.setCommunalEnabled(false)
            runCurrent()

            assertThat(mediaRepository.isListening()).isFalse()
            assertThat(smartspaceRepository.isListening()).isFalse()
        }
}
+17 −18
Original line number Diff line number Diff line
@@ -20,46 +20,41 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.mock

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
class CommunalMediaRepositoryImplTest : SysuiTestCase() {
    @Mock private lateinit var mediaDataManager: MediaDataManager
    @Mock private lateinit var mediaData: MediaData
    @Mock private lateinit var tableLogBuffer: TableLogBuffer
    private val mediaDataManager = mock<MediaDataManager>()
    private val mediaData = mock<MediaData>()
    private val tableLogBuffer = mock<TableLogBuffer>()

    private lateinit var underTest: CommunalMediaRepositoryImpl

    private val mediaDataListenerCaptor: KotlinArgumentCaptor<MediaDataManager.Listener> by lazy {
        KotlinArgumentCaptor(MediaDataManager.Listener::class.java)
    }
    private val mediaDataListenerCaptor = argumentCaptor<MediaDataManager.Listener>()

    private val testDispatcher = StandardTestDispatcher()
    private val testScope = TestScope(testDispatcher)
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        underTest =
            CommunalMediaRepositoryImpl(
                mediaDataManager,
@@ -78,6 +73,8 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
    @Test
    fun mediaModel_updatesWhenMediaDataLoaded() =
        testScope.runTest {
            underTest.startListening()

            // Listener is added
            verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())

@@ -89,7 +86,7 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
            // Change to media available and notify the listener.
            whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
            whenever(mediaData.createdTimestampMillis).thenReturn(1234L)
            mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
            mediaDataListenerCaptor.firstValue.onMediaDataLoaded("key", null, mediaData)
            runCurrent()

            // Media active now returns true.
@@ -100,12 +97,14 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
    @Test
    fun mediaModel_updatesWhenMediaDataRemoved() =
        testScope.runTest {
            underTest.startListening()

            // Listener is added
            verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())

            // Change to media available and notify the listener.
            whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
            mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
            mediaDataListenerCaptor.firstValue.onMediaDataLoaded("key", null, mediaData)
            runCurrent()

            // Media active now returns true.
@@ -114,7 +113,7 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {

            // Change to media unavailable and notify the listener.
            whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(false)
            mediaDataListenerCaptor.value.onMediaDataRemoved("key", false)
            mediaDataListenerCaptor.firstValue.onMediaDataRemoved("key", false)
            runCurrent()

            // Media active now returns false.
+21 −3
Original line number Diff line number Diff line
@@ -64,19 +64,37 @@ class CommunalSmartspaceRepositoryImplTest : SysuiTestCase() {

    @DisableFlags(FLAG_REMOTE_VIEWS)
    @Test
    fun communalTimers_doNotListenForSmartspaceUpdatesWhenRemoteViewsFlagDisabled() =
    fun startListening_remoteViewsFlagDisabled_doNotListenForSmartspaceUpdates() =
        testScope.runTest {
            collectLastValue(underTest.timers)
            runCurrent()
            underTest.startListening()
            fakeExecutor.runAllReady()

            verify(smartspaceController, never()).addListener(any())
        }

    @EnableFlags(FLAG_REMOTE_VIEWS)
    @Test
    fun startListening_remoteViewsFlagEnabled_listenForSmartspaceUpdates() =
        testScope.runTest {
            underTest.startListening()
            fakeExecutor.runAllReady()

            // Verify listener added
            val listener = captureSmartspaceTargetListener()

            underTest.stopListening()
            fakeExecutor.runAllReady()

            // Verify listener removed
            verify(smartspaceController).removeListener(listener)
        }

    @EnableFlags(FLAG_REMOTE_VIEWS)
    @Test
    fun communalTimers_onlyShowTimersWithRemoteViews() =
        testScope.runTest {
            underTest.startListening()

            val communalTimers by collectLastValue(underTest.timers)
            runCurrent()
            fakeExecutor.runAllReady()
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.communal

import com.android.systemui.CoreStartable
import com.android.systemui.communal.data.repository.CommunalMediaRepository
import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@SysUISingleton
class CommunalOngoingContentStartable
@Inject
constructor(
    @Background val bgScope: CoroutineScope,
    private val communalInteractor: CommunalInteractor,
    private val communalMediaRepository: CommunalMediaRepository,
    private val communalSmartspaceRepository: CommunalSmartspaceRepository,
    private val featureFlags: FeatureFlagsClassic,
) : CoreStartable {

    override fun start() {
        if (
            !featureFlags.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) ||
                !com.android.systemui.Flags.communalHub()
        ) {
            return
        }

        bgScope.launch {
            communalInteractor.isCommunalEnabled.collect { enabled ->
                if (enabled) {
                    communalMediaRepository.startListening()
                    communalSmartspaceRepository.startListening()
                } else {
                    communalMediaRepository.stopListening()
                    communalSmartspaceRepository.stopListening()
                }
            }
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import kotlinx.coroutines.CoroutineScope
            CommunalPrefsRepositoryModule::class,
            CommunalSettingsRepositoryModule::class,
            CommunalSmartspaceRepositoryModule::class,
            CommunalStartableModule::class,
        ]
)
interface CommunalModule {
Loading