Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +230 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState Loading @@ -62,6 +64,8 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.settings.fakeUserTracker import com.android.systemui.shade.ShadeTestUtil import com.android.systemui.shade.domain.interactor.shadeInteractor Loading @@ -71,7 +75,6 @@ import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf Loading @@ -85,6 +88,7 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.whenever import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters Loading Loading @@ -138,6 +142,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { ) whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) kosmos.powerInteractor.setAwakeForTest() underTest = CommunalViewModel( testScope, Loading Loading @@ -468,6 +474,229 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(isFocusable).isEqualTo(false) } @Test fun isCommunalContentFlowFrozen_whenActivityStartedWhileDreaming() = testScope.runTest { val isCommunalContentFlowFrozen by collectLastValue(underTest.isCommunalContentFlowFrozen) // 1. When dreaming not dozing keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) keyguardRepository.setDreaming(true) keyguardRepository.setDreamingWithOverlay(true) advanceTimeBy(60L) // And keyguard is occluded by dream keyguardRepository.setKeyguardOccluded(true) // And on hub keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) // 2. When dreaming stopped by the new activity about to show on lock screen keyguardRepository.setDreamingWithOverlay(false) advanceTimeBy(60L) // Then flow is frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(true) // 3. When transitioned to OCCLUDED and activity shows keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, testScope = testScope, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) } @Test fun isCommunalContentFlowFrozen_whenActivityStartedInHandheldMode() = testScope.runTest { val isCommunalContentFlowFrozen by collectLastValue(underTest.isCommunalContentFlowFrozen) // 1. When on keyguard and not occluded keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) // And transitioned to hub keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) // 2. When occluded by a new activity keyguardRepository.setKeyguardOccluded(true) runCurrent() // And transitioning to occluded keyguardTransitionRepository.sendTransitionStep( TransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, transitionState = TransitionState.STARTED, ) ) keyguardTransitionRepository.sendTransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, transitionState = TransitionState.RUNNING, value = 0.5f, ) // Then flow is frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(true) // 3. When transition is finished keyguardTransitionRepository.sendTransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, transitionState = TransitionState.FINISHED, value = 1f, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) } @Test fun communalContent_emitsFrozenContent_whenFrozen() = testScope.runTest { val communalContent by collectLastValue(underTest.communalContent) tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) // When dreaming keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) keyguardRepository.setDreaming(true) keyguardRepository.setDreamingWithOverlay(true) advanceTimeBy(60L) keyguardRepository.setKeyguardOccluded(true) // And transitioned to hub keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // Widgets available val widgets = listOf( CommunalWidgetContentModel.Available( appWidgetId = 0, priority = 30, providerInfo = providerInfo, ), CommunalWidgetContentModel.Available( appWidgetId = 1, priority = 20, providerInfo = providerInfo, ), ) widgetRepository.setCommunalWidgets(widgets) // Then hub shows widgets and the CTA tile assertThat(communalContent).hasSize(3) // When dreaming stopped by another activity which should freeze flow keyguardRepository.setDreamingWithOverlay(false) advanceTimeBy(60L) // New timer available val target = Mockito.mock(SmartspaceTarget::class.java) whenever<String?>(target.smartspaceTargetId).thenReturn("target") whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER) whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java)) smartspaceRepository.setCommunalSmartspaceTargets(listOf(target)) runCurrent() // Still only emits widgets and the CTA tile assertThat(communalContent).hasSize(3) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } @Test fun communalContent_emitsLatestContent_whenNotFrozen() = testScope.runTest { val communalContent by collectLastValue(underTest.communalContent) tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) // When dreaming keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) keyguardRepository.setDreaming(true) keyguardRepository.setDreamingWithOverlay(true) advanceTimeBy(60L) keyguardRepository.setKeyguardOccluded(true) // Transitioned to Glanceable hub. keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // And widgets available val widgets = listOf( CommunalWidgetContentModel.Available( appWidgetId = 0, priority = 30, providerInfo = providerInfo, ), CommunalWidgetContentModel.Available( appWidgetId = 1, priority = 20, providerInfo = providerInfo, ), ) widgetRepository.setCommunalWidgets(widgets) // Then emits widgets and the CTA tile assertThat(communalContent).hasSize(3) // When new timer available val target = Mockito.mock(SmartspaceTarget::class.java) whenever(target.smartspaceTargetId).thenReturn("target") whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER) whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java)) smartspaceRepository.setCommunalSmartspaceTargets(listOf(target)) runCurrent() // Then emits timer, widgets and the CTA tile assertThat(communalContent).hasSize(4) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.Smartspace::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(3)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } private suspend fun setIsMainUser(isMainUser: Boolean) { whenever(user.isMain).thenReturn(isMainUser) userRepository.setUserInfos(listOf(user)) Loading packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +6 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,12 @@ abstract class BaseCommunalViewModel( /** A list of all the communal content to be displayed in the communal hub. */ abstract val communalContent: Flow<List<CommunalContentModel>> /** * Whether to freeze the emission of the communalContent flow to prevent recomposition. Defaults * to false, indicating that the flow will emit new update. */ open val isCommunalContentFlowFrozen: Flow<Boolean> = flowOf(false) /** Whether in edit mode for the communal hub. */ open val isEditMode = false Loading packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +37 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.dagger.MediaModule 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.flatMapLatestConflated import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineScope Loading Loading @@ -76,8 +78,11 @@ constructor( private val logger = Logger(logBuffer, "CommunalViewModel") /** Communal content saved from the previous emission when the flow is active (not "frozen"). */ private var frozenCommunalContent: List<CommunalContentModel>? = null @OptIn(ExperimentalCoroutinesApi::class) override val communalContent: Flow<List<CommunalContentModel>> = private val latestCommunalContent: Flow<List<CommunalContentModel>> = tutorialInteractor.isTutorialAvailable .flatMapLatest { isTutorialMode -> if (isTutorialMode) { Loading @@ -93,9 +98,40 @@ constructor( } } .onEach { models -> frozenCommunalContent = models logger.d({ "Content updated: $str1" }) { str1 = models.joinToString { it.key } } } /** * Freeze the content flow, when an activity is about to show, like starting a timer via voice: * 1) in handheld mode, use the keyguard occluded state; * 2) in dreaming mode, where keyguard is already occluded by dream, use the dream wakeup * signal. Since in this case the shell transition info does not include * KEYGUARD_VISIBILITY_TRANSIT_FLAGS, KeyguardTransitionHandler will not run the * occludeAnimation on KeyguardViewMediator. */ override val isCommunalContentFlowFrozen: Flow<Boolean> = allOf( keyguardTransitionInteractor.isFinishedInState(KeyguardState.GLANCEABLE_HUB), keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isAbleToDream) ) .distinctUntilChanged() .onEach { logger.d("isCommunalContentFlowFrozen: $it") } override val communalContent: Flow<List<CommunalContentModel>> = isCommunalContentFlowFrozen .flatMapLatestConflated { isFrozen -> if (isFrozen) { flowOf(frozenCommunalContent ?: emptyList()) } else { latestCommunalContent } } .onEach { models -> logger.d({ "CommunalContent: $str1" }) { str1 = models.joinToString { it.key } } } override val isEmptyState: Flow<Boolean> = communalInteractor.widgetContent .map { it.isEmpty() } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +230 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState Loading @@ -62,6 +64,8 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.settings.fakeUserTracker import com.android.systemui.shade.ShadeTestUtil import com.android.systemui.shade.domain.interactor.shadeInteractor Loading @@ -71,7 +75,6 @@ import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf Loading @@ -85,6 +88,7 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.whenever import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters Loading Loading @@ -138,6 +142,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { ) whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) kosmos.powerInteractor.setAwakeForTest() underTest = CommunalViewModel( testScope, Loading Loading @@ -468,6 +474,229 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(isFocusable).isEqualTo(false) } @Test fun isCommunalContentFlowFrozen_whenActivityStartedWhileDreaming() = testScope.runTest { val isCommunalContentFlowFrozen by collectLastValue(underTest.isCommunalContentFlowFrozen) // 1. When dreaming not dozing keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) keyguardRepository.setDreaming(true) keyguardRepository.setDreamingWithOverlay(true) advanceTimeBy(60L) // And keyguard is occluded by dream keyguardRepository.setKeyguardOccluded(true) // And on hub keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) // 2. When dreaming stopped by the new activity about to show on lock screen keyguardRepository.setDreamingWithOverlay(false) advanceTimeBy(60L) // Then flow is frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(true) // 3. When transitioned to OCCLUDED and activity shows keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, testScope = testScope, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) } @Test fun isCommunalContentFlowFrozen_whenActivityStartedInHandheldMode() = testScope.runTest { val isCommunalContentFlowFrozen by collectLastValue(underTest.isCommunalContentFlowFrozen) // 1. When on keyguard and not occluded keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) // And transitioned to hub keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) // 2. When occluded by a new activity keyguardRepository.setKeyguardOccluded(true) runCurrent() // And transitioning to occluded keyguardTransitionRepository.sendTransitionStep( TransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, transitionState = TransitionState.STARTED, ) ) keyguardTransitionRepository.sendTransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, transitionState = TransitionState.RUNNING, value = 0.5f, ) // Then flow is frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(true) // 3. When transition is finished keyguardTransitionRepository.sendTransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, transitionState = TransitionState.FINISHED, value = 1f, ) // Then flow is not frozen assertThat(isCommunalContentFlowFrozen).isEqualTo(false) } @Test fun communalContent_emitsFrozenContent_whenFrozen() = testScope.runTest { val communalContent by collectLastValue(underTest.communalContent) tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) // When dreaming keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) keyguardRepository.setDreaming(true) keyguardRepository.setDreamingWithOverlay(true) advanceTimeBy(60L) keyguardRepository.setKeyguardOccluded(true) // And transitioned to hub keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // Widgets available val widgets = listOf( CommunalWidgetContentModel.Available( appWidgetId = 0, priority = 30, providerInfo = providerInfo, ), CommunalWidgetContentModel.Available( appWidgetId = 1, priority = 20, providerInfo = providerInfo, ), ) widgetRepository.setCommunalWidgets(widgets) // Then hub shows widgets and the CTA tile assertThat(communalContent).hasSize(3) // When dreaming stopped by another activity which should freeze flow keyguardRepository.setDreamingWithOverlay(false) advanceTimeBy(60L) // New timer available val target = Mockito.mock(SmartspaceTarget::class.java) whenever<String?>(target.smartspaceTargetId).thenReturn("target") whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER) whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java)) smartspaceRepository.setCommunalSmartspaceTargets(listOf(target)) runCurrent() // Still only emits widgets and the CTA tile assertThat(communalContent).hasSize(3) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } @Test fun communalContent_emitsLatestContent_whenNotFrozen() = testScope.runTest { val communalContent by collectLastValue(underTest.communalContent) tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) // When dreaming keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) keyguardRepository.setDreaming(true) keyguardRepository.setDreamingWithOverlay(true) advanceTimeBy(60L) keyguardRepository.setKeyguardOccluded(true) // Transitioned to Glanceable hub. keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, testScope = testScope, ) // And widgets available val widgets = listOf( CommunalWidgetContentModel.Available( appWidgetId = 0, priority = 30, providerInfo = providerInfo, ), CommunalWidgetContentModel.Available( appWidgetId = 1, priority = 20, providerInfo = providerInfo, ), ) widgetRepository.setCommunalWidgets(widgets) // Then emits widgets and the CTA tile assertThat(communalContent).hasSize(3) // When new timer available val target = Mockito.mock(SmartspaceTarget::class.java) whenever(target.smartspaceTargetId).thenReturn("target") whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER) whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java)) smartspaceRepository.setCommunalSmartspaceTargets(listOf(target)) runCurrent() // Then emits timer, widgets and the CTA tile assertThat(communalContent).hasSize(4) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.Smartspace::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(3)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } private suspend fun setIsMainUser(isMainUser: Boolean) { whenever(user.isMain).thenReturn(isMainUser) userRepository.setUserInfos(listOf(user)) Loading
packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +6 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,12 @@ abstract class BaseCommunalViewModel( /** A list of all the communal content to be displayed in the communal hub. */ abstract val communalContent: Flow<List<CommunalContentModel>> /** * Whether to freeze the emission of the communalContent flow to prevent recomposition. Defaults * to false, indicating that the flow will emit new update. */ open val isCommunalContentFlowFrozen: Flow<Boolean> = flowOf(false) /** Whether in edit mode for the communal hub. */ open val isEditMode = false Loading
packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +37 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.dagger.MediaModule 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.flatMapLatestConflated import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineScope Loading Loading @@ -76,8 +78,11 @@ constructor( private val logger = Logger(logBuffer, "CommunalViewModel") /** Communal content saved from the previous emission when the flow is active (not "frozen"). */ private var frozenCommunalContent: List<CommunalContentModel>? = null @OptIn(ExperimentalCoroutinesApi::class) override val communalContent: Flow<List<CommunalContentModel>> = private val latestCommunalContent: Flow<List<CommunalContentModel>> = tutorialInteractor.isTutorialAvailable .flatMapLatest { isTutorialMode -> if (isTutorialMode) { Loading @@ -93,9 +98,40 @@ constructor( } } .onEach { models -> frozenCommunalContent = models logger.d({ "Content updated: $str1" }) { str1 = models.joinToString { it.key } } } /** * Freeze the content flow, when an activity is about to show, like starting a timer via voice: * 1) in handheld mode, use the keyguard occluded state; * 2) in dreaming mode, where keyguard is already occluded by dream, use the dream wakeup * signal. Since in this case the shell transition info does not include * KEYGUARD_VISIBILITY_TRANSIT_FLAGS, KeyguardTransitionHandler will not run the * occludeAnimation on KeyguardViewMediator. */ override val isCommunalContentFlowFrozen: Flow<Boolean> = allOf( keyguardTransitionInteractor.isFinishedInState(KeyguardState.GLANCEABLE_HUB), keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isAbleToDream) ) .distinctUntilChanged() .onEach { logger.d("isCommunalContentFlowFrozen: $it") } override val communalContent: Flow<List<CommunalContentModel>> = isCommunalContentFlowFrozen .flatMapLatestConflated { isFrozen -> if (isFrozen) { flowOf(frozenCommunalContent ?: emptyList()) } else { latestCommunalContent } } .onEach { models -> logger.d({ "CommunalContent: $str1" }) { str1 = models.joinToString { it.key } } } override val isEmptyState: Flow<Boolean> = communalInteractor.widgetContent .map { it.isEmpty() } Loading