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

Commit ab6d1114 authored by William Xiao's avatar William Xiao
Browse files

Always return blank scene when communal is not available

The glanceable hub can be disabled for many reasons, such as the flag
being turned off or the setting being turned off. Before this change,
CommunalRepository was the source of truth of the desired scene state,
and anyone observing isCommunalShowing through the interactor would see
it incorrectly returning that communal was showing.

This change makes the interactor always return Blank for the scene in
desiredScene when communal is not available. This prevents clients from
seeing an incorrect communal state.

Bug: 322549132
Bug: 325868439
Test: atest CommunalInteractorTest MediaHierarchyManagerTest
Flag: ACONFIG com.android.systemui.communal_hub STAGING
Change-Id: I1b5c7eb81cadb44a7e10135ea92a063589580be9
parent 5190facc
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dock.DockManager
@@ -33,6 +34,7 @@ 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.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
@@ -50,7 +52,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
    private lateinit var underTest: CommunalSceneStartable

    @Before
    fun setUp() =
    fun setUp() {
        with(kosmos) {
            underTest =
                CommunalSceneStartable(
@@ -61,6 +63,14 @@ class CommunalSceneStartableTest : SysuiTestCase() {
                        bgScope = applicationCoroutineScope,
                    )
                    .apply { start() }

            // Make communal available so that communalInteractor.desiredScene accurately reflects
            // scene changes instead of just returning Blank.
            with(kosmos.testScope) {
                launch { setCommunalAvailable(true) }
                testScheduler.runCurrent()
            }
        }
    }

    @Test
@@ -249,4 +259,10 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            fakeDockManager.setDockEvent(DockManager.STATE_DOCKED)
            runCurrent()
        }

    private suspend fun TestScope.enableCommunal() =
        with(kosmos) {
            setCommunalAvailable(true)
            runCurrent()
        }
}
+47 −0
Original line number Diff line number Diff line
@@ -455,6 +455,9 @@ class CommunalInteractorTest : SysuiTestCase() {
    @Test
    fun listensToSceneChange() =
        testScope.runTest {
            kosmos.setCommunalAvailable(true)
            runCurrent()

            var desiredScene = collectLastValue(underTest.desiredScene)
            runCurrent()
            assertThat(desiredScene()).isEqualTo(CommunalSceneKey.Blank)
@@ -478,6 +481,30 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(desiredScene()).isEqualTo(targetScene)
        }

    @Test
    fun desiredScene_communalNotAvailable_returnsBlank() =
        testScope.runTest {
            kosmos.setCommunalAvailable(true)
            runCurrent()

            val desiredScene by collectLastValue(underTest.desiredScene)

            underTest.onSceneChanged(CommunalSceneKey.Communal)
            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal)

            kosmos.setCommunalAvailable(false)
            runCurrent()

            // Scene returns blank when communal is not available.
            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Blank)

            kosmos.setCommunalAvailable(true)
            runCurrent()

            // After re-enabling, scene goes back to Communal.
            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal)
        }

    @Test
    fun transitionProgress_onTargetScene_fullProgress() =
        testScope.runTest {
@@ -603,9 +630,29 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(targetScene))
        }

    @Test
    fun isCommunalShowing() =
        testScope.runTest {
            kosmos.setCommunalAvailable(true)
            runCurrent()

            var isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
            runCurrent()
            assertThat(isCommunalShowing()).isEqualTo(false)

            underTest.onSceneChanged(CommunalSceneKey.Communal)

            isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
            runCurrent()
            assertThat(isCommunalShowing()).isEqualTo(true)
        }

    @Test
    fun isCommunalShowing_whenSceneContainerDisabled() =
        testScope.runTest {
            kosmos.setCommunalAvailable(true)
            runCurrent()

            // Verify default is false
            val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
            runCurrent()
+15 −39
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.communal.domain.interactor

import android.content.pm.UserInfo
import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED
import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_STARTED
@@ -61,7 +60,6 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        communalInteractor = kosmos.communalInteractor
        userRepository = kosmos.fakeUserRepository

        userRepository.setUserInfos(listOf(MAIN_USER_INFO))
        kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
        mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)

@@ -72,7 +70,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
    fun tutorialUnavailable_whenKeyguardNotVisible() =
        testScope.runTest {
            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
            setCommunalAvailable(true)
            kosmos.setCommunalAvailable(true)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
            keyguardRepository.setKeyguardShowing(false)
            assertThat(isTutorialAvailable).isFalse()
@@ -82,10 +80,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
    fun tutorialUnavailable_whenTutorialIsCompleted() =
        testScope.runTest {
            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
            setCommunalAvailable(true)
            keyguardRepository.setKeyguardShowing(true)
            keyguardRepository.setKeyguardOccluded(false)
            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
            assertThat(isTutorialAvailable).isFalse()
        }
@@ -94,7 +89,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
    fun tutorialUnavailable_whenCommunalNotAvailable() =
        testScope.runTest {
            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
            setCommunalAvailable(false)
            kosmos.setCommunalAvailable(false)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
            keyguardRepository.setKeyguardShowing(true)
            assertThat(isTutorialAvailable).isFalse()
@@ -104,10 +99,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
    fun tutorialAvailable_whenTutorialNotStarted() =
        testScope.runTest {
            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
            setCommunalAvailable(true)
            keyguardRepository.setKeyguardShowing(true)
            keyguardRepository.setKeyguardOccluded(false)
            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
            kosmos.setCommunalAvailable(true)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
            assertThat(isTutorialAvailable).isTrue()
        }
@@ -116,10 +108,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
    fun tutorialAvailable_whenTutorialIsStarted() =
        testScope.runTest {
            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
            setCommunalAvailable(true)
            keyguardRepository.setKeyguardShowing(true)
            keyguardRepository.setKeyguardOccluded(false)
            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
            assertThat(isTutorialAvailable).isTrue()
        }
@@ -129,10 +118,9 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val tutorialSettingState by
                collectLastValue(communalTutorialRepository.tutorialSettingState)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)

            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()

            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED)
        }
@@ -142,10 +130,10 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val tutorialSettingState by
                collectLastValue(communalTutorialRepository.tutorialSettingState)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)

            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)

            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()

            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED)
        }
@@ -155,10 +143,9 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val tutorialSettingState by
                collectLastValue(communalTutorialRepository.tutorialSettingState)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()

            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
        }
@@ -168,7 +155,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val tutorialSettingState by
                collectLastValue(communalTutorialRepository.tutorialSettingState)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
            kosmos.setCommunalAvailable(true)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)

            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
@@ -181,8 +168,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val tutorialSettingState by
                collectLastValue(communalTutorialRepository.tutorialSettingState)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)

            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
@@ -195,8 +181,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val tutorialSettingState by
                collectLastValue(communalTutorialRepository.tutorialSettingState)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
            goToCommunal()
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
@@ -204,17 +189,8 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
        }

    private suspend fun setCommunalAvailable(available: Boolean) {
        if (available) {
            keyguardRepository.setIsEncryptedOrLockdown(false)
            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
            keyguardRepository.setKeyguardShowing(true)
        } else {
            keyguardRepository.setIsEncryptedOrLockdown(true)
        }
    }

    private companion object {
        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
    private suspend fun goToCommunal() {
        kosmos.setCommunalAvailable(true)
        communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -125,8 +125,13 @@ constructor(
    /**
     * Target scene as requested by the underlying [SceneTransitionLayout] or through
     * [onSceneChanged].
     *
     * If [isCommunalAvailable] is false, will return [CommunalSceneKey.Blank]
     */
    val desiredScene: StateFlow<CommunalSceneKey> = communalRepository.desiredScene
    val desiredScene: Flow<CommunalSceneKey> =
        communalRepository.desiredScene.combine(isCommunalAvailable) { scene, available ->
            if (available) scene else CommunalSceneKey.Blank
        }

    /** Transition state of the hub mode. */
    val transitionState: StateFlow<ObservableCommunalTransitionState> =
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ abstract class BaseCommunalViewModel(
    private val communalInteractor: CommunalInteractor,
    val mediaHost: MediaHost,
) {
    val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene
    val currentScene: Flow<CommunalSceneKey> = communalInteractor.desiredScene

    /** Whether widgets are currently being re-ordered. */
    open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false)
Loading