Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +18 −4 Original line number Diff line number Diff line Loading @@ -295,7 +295,7 @@ class CommunalInteractorTest : SysuiTestCase() { val targets = listOf(target1, target2, target3) smartspaceRepository.setCommunalSmartspaceTargets(targets) val smartspaceContent by collectLastValue(underTest.ongoingContent) val smartspaceContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(smartspaceContent?.size).isEqualTo(1) assertThat(smartspaceContent?.get(0)?.key) .isEqualTo(CommunalContentModel.KEY.smartspace("target3")) Loading Loading @@ -393,7 +393,7 @@ class CommunalInteractorTest : SysuiTestCase() { smartspaceRepository.setCommunalSmartspaceTargets(targets) val smartspaceContent by collectLastValue(underTest.ongoingContent) val smartspaceContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(smartspaceContent?.size).isEqualTo(totalTargets) for (index in 0 until totalTargets) { assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index]) Loading @@ -409,13 +409,27 @@ class CommunalInteractorTest : SysuiTestCase() { // Media is playing. mediaRepository.mediaActive() val umoContent by collectLastValue(underTest.ongoingContent) val umoContent by collectLastValue(underTest.getOngoingContent(true)) 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 { Loading @@ -439,7 +453,7 @@ class CommunalInteractorTest : SysuiTestCase() { val timer3 = smartspaceTimer("timer3", timestamp = 4L) smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2, timer3)) val ongoingContent by collectLastValue(underTest.ongoingContent) val ongoingContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(ongoingContent?.size).isEqualTo(4) assertThat(ongoingContent?.get(0)?.key) .isEqualTo(CommunalContentModel.KEY.smartspace("timer3")) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +43 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS import com.android.systemui.communal.ui.viewmodel.PopupType import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic Loading @@ -61,6 +62,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager Loading Loading @@ -142,11 +144,13 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { selectedUserIndex = 0, ) whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) whenever(mediaHost.visible).thenReturn(true) kosmos.powerInteractor.setAwakeForTest() underTest = CommunalViewModel( kosmos.testDispatcher, testScope, context.resources, kosmos.keyguardTransitionInteractor, Loading Loading @@ -234,6 +238,45 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } @Test fun communalContent_mediaHostVisible_umoIncluded() = testScope.runTest { // Media playing. mediaRepository.mediaActive() val communalContent by collectLastValue(underTest.communalContent) assertThat(communalContent?.size).isEqualTo(2) assertThat(communalContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java) } @Test fun communalContent_mediaHostVisible_umoExcluded() = testScope.runTest { whenever(mediaHost.visible).thenReturn(false) mediaHost.updateViewVisibility() // Media playing. mediaRepository.mediaActive() val communalContent by collectLastValue(underTest.communalContent) assertThat(communalContent?.size).isEqualTo(1) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } @Test fun communalContent_mediaHostVisible_umoToggle() = testScope.runTest { mediaHost.updateViewVisibility() mediaRepository.mediaActive() val communalContent by collectValues(underTest.communalContent) whenever(mediaHost.visible).thenReturn(false) mediaHost.updateViewVisibility() assertThat(communalContent.size).isEqualTo(1) } @Test fun isEmptyState_isTrue_noWidgetButActiveLiveContent() = testScope.runTest { Loading packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +29 −28 Original line number Diff line number Diff line Loading @@ -98,7 +98,7 @@ constructor( broadcastDispatcher: BroadcastDispatcher, private val widgetRepository: CommunalWidgetRepository, private val communalPrefsRepository: CommunalPrefsRepository, mediaRepository: CommunalMediaRepository, private val mediaRepository: CommunalMediaRepository, smartspaceRepository: SmartspaceRepository, keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, Loading Loading @@ -479,7 +479,7 @@ constructor( * A flow of ongoing content, including smartspace timers and umo, ordered by creation time and * sized dynamically. */ val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> = fun getOngoingContent(mediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> = combine(smartspaceTargets, mediaRepository.mediaModel) { smartspace, media -> val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>() Loading @@ -495,7 +495,7 @@ constructor( ) // Add UMO if (media.hasActiveMediaOrRecommendation) { if (mediaHostVisible && media.hasActiveMediaOrRecommendation) { ongoingContent.add( CommunalContentModel.Umo( createdTimestampMillis = media.createdTimestampMillis, Loading @@ -511,8 +511,9 @@ constructor( model.size = dynamicContentSize(ongoingContent.size, index) } return@combine ongoingContent ongoingContent } .flowOn(bgDispatcher) /** * Filter and retain widgets associated with an existing user, safeguarding against displaying Loading packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +21 −1 Original line number Diff line number Diff line Loading @@ -42,12 +42,15 @@ import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow Loading @@ -56,8 +59,10 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch /** The default view model used for showing the communal hub. */ Loading @@ -66,6 +71,7 @@ import kotlinx.coroutines.launch class CommunalViewModel @Inject constructor( @Main val mainDispatcher: CoroutineDispatcher, @Application private val scope: CoroutineScope, @Main private val resources: Resources, keyguardTransitionInteractor: KeyguardTransitionInteractor, Loading @@ -79,6 +85,18 @@ constructor( @CommunalLog logBuffer: LogBuffer, ) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) { private val _isMediaHostVisible = conflatedCallbackFlow<Boolean> { val callback = { visible: Boolean -> trySend(visible) Unit } mediaHost.addVisibilityChangeListener(callback) awaitClose { mediaHost.removeVisibilityChangeListener(callback) } } .onStart { emit(mediaHost.visible) } .flowOn(mainDispatcher) private val logger = Logger(logBuffer, "CommunalViewModel") /** Communal content saved from the previous emission when the flow is active (not "frozen"). */ Loading @@ -91,8 +109,10 @@ constructor( if (isTutorialMode) { return@flatMapLatest flowOf(communalInteractor.tutorialContent) } val ongoingContent = _isMediaHostVisible.flatMapLatest { communalInteractor.getOngoingContent(it) } combine( communalInteractor.ongoingContent, ongoingContent, communalInteractor.widgetContent, communalInteractor.ctaTileContent, ) { ongoing, widgets, ctaTile, Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +18 −4 Original line number Diff line number Diff line Loading @@ -295,7 +295,7 @@ class CommunalInteractorTest : SysuiTestCase() { val targets = listOf(target1, target2, target3) smartspaceRepository.setCommunalSmartspaceTargets(targets) val smartspaceContent by collectLastValue(underTest.ongoingContent) val smartspaceContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(smartspaceContent?.size).isEqualTo(1) assertThat(smartspaceContent?.get(0)?.key) .isEqualTo(CommunalContentModel.KEY.smartspace("target3")) Loading Loading @@ -393,7 +393,7 @@ class CommunalInteractorTest : SysuiTestCase() { smartspaceRepository.setCommunalSmartspaceTargets(targets) val smartspaceContent by collectLastValue(underTest.ongoingContent) val smartspaceContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(smartspaceContent?.size).isEqualTo(totalTargets) for (index in 0 until totalTargets) { assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index]) Loading @@ -409,13 +409,27 @@ class CommunalInteractorTest : SysuiTestCase() { // Media is playing. mediaRepository.mediaActive() val umoContent by collectLastValue(underTest.ongoingContent) val umoContent by collectLastValue(underTest.getOngoingContent(true)) 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 { Loading @@ -439,7 +453,7 @@ class CommunalInteractorTest : SysuiTestCase() { val timer3 = smartspaceTimer("timer3", timestamp = 4L) smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2, timer3)) val ongoingContent by collectLastValue(underTest.ongoingContent) val ongoingContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(ongoingContent?.size).isEqualTo(4) assertThat(ongoingContent?.get(0)?.key) .isEqualTo(CommunalContentModel.KEY.smartspace("timer3")) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +43 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS import com.android.systemui.communal.ui.viewmodel.PopupType import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic Loading @@ -61,6 +62,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager Loading Loading @@ -142,11 +144,13 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { selectedUserIndex = 0, ) whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) whenever(mediaHost.visible).thenReturn(true) kosmos.powerInteractor.setAwakeForTest() underTest = CommunalViewModel( kosmos.testDispatcher, testScope, context.resources, kosmos.keyguardTransitionInteractor, Loading Loading @@ -234,6 +238,45 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } @Test fun communalContent_mediaHostVisible_umoIncluded() = testScope.runTest { // Media playing. mediaRepository.mediaActive() val communalContent by collectLastValue(underTest.communalContent) assertThat(communalContent?.size).isEqualTo(2) assertThat(communalContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java) } @Test fun communalContent_mediaHostVisible_umoExcluded() = testScope.runTest { whenever(mediaHost.visible).thenReturn(false) mediaHost.updateViewVisibility() // Media playing. mediaRepository.mediaActive() val communalContent by collectLastValue(underTest.communalContent) assertThat(communalContent?.size).isEqualTo(1) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } @Test fun communalContent_mediaHostVisible_umoToggle() = testScope.runTest { mediaHost.updateViewVisibility() mediaRepository.mediaActive() val communalContent by collectValues(underTest.communalContent) whenever(mediaHost.visible).thenReturn(false) mediaHost.updateViewVisibility() assertThat(communalContent.size).isEqualTo(1) } @Test fun isEmptyState_isTrue_noWidgetButActiveLiveContent() = testScope.runTest { Loading
packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +29 −28 Original line number Diff line number Diff line Loading @@ -98,7 +98,7 @@ constructor( broadcastDispatcher: BroadcastDispatcher, private val widgetRepository: CommunalWidgetRepository, private val communalPrefsRepository: CommunalPrefsRepository, mediaRepository: CommunalMediaRepository, private val mediaRepository: CommunalMediaRepository, smartspaceRepository: SmartspaceRepository, keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, Loading Loading @@ -479,7 +479,7 @@ constructor( * A flow of ongoing content, including smartspace timers and umo, ordered by creation time and * sized dynamically. */ val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> = fun getOngoingContent(mediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> = combine(smartspaceTargets, mediaRepository.mediaModel) { smartspace, media -> val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>() Loading @@ -495,7 +495,7 @@ constructor( ) // Add UMO if (media.hasActiveMediaOrRecommendation) { if (mediaHostVisible && media.hasActiveMediaOrRecommendation) { ongoingContent.add( CommunalContentModel.Umo( createdTimestampMillis = media.createdTimestampMillis, Loading @@ -511,8 +511,9 @@ constructor( model.size = dynamicContentSize(ongoingContent.size, index) } return@combine ongoingContent ongoingContent } .flowOn(bgDispatcher) /** * Filter and retain widgets associated with an existing user, safeguarding against displaying Loading
packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +21 −1 Original line number Diff line number Diff line Loading @@ -42,12 +42,15 @@ import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow Loading @@ -56,8 +59,10 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch /** The default view model used for showing the communal hub. */ Loading @@ -66,6 +71,7 @@ import kotlinx.coroutines.launch class CommunalViewModel @Inject constructor( @Main val mainDispatcher: CoroutineDispatcher, @Application private val scope: CoroutineScope, @Main private val resources: Resources, keyguardTransitionInteractor: KeyguardTransitionInteractor, Loading @@ -79,6 +85,18 @@ constructor( @CommunalLog logBuffer: LogBuffer, ) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) { private val _isMediaHostVisible = conflatedCallbackFlow<Boolean> { val callback = { visible: Boolean -> trySend(visible) Unit } mediaHost.addVisibilityChangeListener(callback) awaitClose { mediaHost.removeVisibilityChangeListener(callback) } } .onStart { emit(mediaHost.visible) } .flowOn(mainDispatcher) private val logger = Logger(logBuffer, "CommunalViewModel") /** Communal content saved from the previous emission when the flow is active (not "frozen"). */ Loading @@ -91,8 +109,10 @@ constructor( if (isTutorialMode) { return@flatMapLatest flowOf(communalInteractor.tutorialContent) } val ongoingContent = _isMediaHostVisible.flatMapLatest { communalInteractor.getOngoingContent(it) } combine( communalInteractor.ongoingContent, ongoingContent, communalInteractor.widgetContent, communalInteractor.ctaTileContent, ) { ongoing, widgets, ctaTile, Loading