Loading packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt +31 −5 Original line number Original line Diff line number Diff line Loading @@ -23,7 +23,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.ElementKey Loading @@ -34,6 +34,13 @@ import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.media.controls.ui.composable.isLandscape import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.COLLAPSED import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.EXPANDED import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.res.R import com.android.systemui.res.R Loading @@ -42,10 +49,11 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.OverlayShadeHeader import com.android.systemui.shade.ui.composable.OverlayShadeHeader import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.util.Utils import dagger.Lazy import dagger.Lazy import javax.inject.Inject import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow @SysUISingleton @SysUISingleton Loading @@ -58,6 +66,8 @@ constructor( private val stackScrollView: Lazy<NotificationScrollView>, private val stackScrollView: Lazy<NotificationScrollView>, private val clockSection: DefaultClockSection, private val clockSection: DefaultClockSection, private val keyguardClockViewModel: KeyguardClockViewModel, private val keyguardClockViewModel: KeyguardClockViewModel, private val mediaCarouselController: MediaCarouselController, @Named(QUICK_QS_PANEL) private val mediaHost: Lazy<MediaHost>, ) : Overlay { ) : Overlay { override val key = Overlays.NotificationsShade override val key = Overlays.NotificationsShade Loading @@ -84,6 +94,11 @@ constructor( viewModel.notificationsPlaceholderViewModelFactory.create() viewModel.notificationsPlaceholderViewModelFactory.create() } } val usingCollapsedLandscapeMedia = Utils.useCollapsedMediaInLandscape(LocalResources.current) mediaHost.get().expansion = if (usingCollapsedLandscapeMedia && isLandscape()) COLLAPSED else EXPANDED OverlayShade( OverlayShade( panelElement = NotificationsShade.Elements.Panel, panelElement = NotificationsShade.Elements.Panel, alignmentOnWideScreens = Alignment.TopStart, alignmentOnWideScreens = Alignment.TopStart, Loading @@ -96,9 +111,7 @@ constructor( } } OverlayShadeHeader( OverlayShadeHeader( viewModel = headerViewModel, viewModel = headerViewModel, modifier = modifier = Modifier.element(NotificationsShade.Elements.StatusBar), Modifier.element(NotificationsShade.Elements.StatusBar) .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader), ) ) }, }, ) { ) { Loading @@ -116,6 +129,19 @@ constructor( } } } } MediaCarousel( isVisible = viewModel.showMedia, mediaHost = mediaHost.get(), carouselController = mediaCarouselController, usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia, modifier = Modifier.padding( top = notificationStackPadding, start = notificationStackPadding, end = notificationStackPadding, ), ) NotificationScrollingStack( NotificationScrollingStack( shadeSession = shadeSession, shadeSession = shadeSession, stackScrollView = stackScrollView.get(), stackScrollView = stackScrollView.get(), Loading packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt +37 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.notifications.ui.viewmodel package com.android.systemui.notifications.ui.viewmodel import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS import android.testing.TestableLooper import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest Loading @@ -28,6 +29,8 @@ import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.domain.interactor.powerInteractor Loading @@ -39,10 +42,13 @@ import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs import com.android.systemui.testKosmos import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.update import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest Loading @@ -50,6 +56,7 @@ import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @SmallTest @RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @TestableLooper.RunWithLooper Loading Loading @@ -155,6 +162,36 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() { assertThat(underTest.showClock).isFalse() assertThat(underTest.showClock).isFalse() } } @Test fun showMedia_activeMedia_true() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) runCurrent() assertThat(underTest.showMedia).isTrue() } @Test fun showMedia_noActiveMedia_false() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false)) runCurrent() assertThat(underTest.showMedia).isFalse() } @Test fun showMedia_qsDisabled_false() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) kosmos.fakeDisableFlagsRepository.disableFlags.update { it.copy(disable2 = DISABLE2_QUICK_SETTINGS) } runCurrent() assertThat(underTest.showMedia).isFalse() } private fun TestScope.lockDevice() { private fun TestScope.lockDevice() { val currentScene by collectLastValue(sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) kosmos.powerInteractor.setAsleepForTest() kosmos.powerInteractor.setAsleepForTest() Loading packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt +22 −0 Original line number Original line Diff line number Diff line Loading @@ -20,12 +20,15 @@ import androidx.compose.runtime.getValue import com.android.app.tracing.coroutines.launchTraced as launch import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.lifecycle.Hydrator import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation Loading @@ -33,6 +36,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOf /** /** * Models UI state used to render the content of the notifications shade overlay. * Models UI state used to render the content of the notifications shade overlay. Loading @@ -47,6 +51,8 @@ constructor( val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, val sceneInteractor: SceneInteractor, val sceneInteractor: SceneInteractor, private val shadeInteractor: ShadeInteractor, private val shadeInteractor: ShadeInteractor, disableFlagsInteractor: DisableFlagsInteractor, mediaCarouselInteractor: MediaCarouselInteractor, activeNotificationsInteractor: ActiveNotificationsInteractor, activeNotificationsInteractor: ActiveNotificationsInteractor, ) : ExclusiveActivatable() { ) : ExclusiveActivatable() { Loading @@ -69,6 +75,22 @@ constructor( ), ), ) ) val showMedia: Boolean by hydrator.hydratedStateOf( traceName = "showMedia", initialValue = disableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled() && mediaCarouselInteractor.hasActiveMediaOrRecommendation.value, source = disableFlagsInteractor.disableFlags.flatMapLatestConflated { if (it.isQuickSettingsEnabled()) { mediaCarouselInteractor.hasActiveMediaOrRecommendation } else { flowOf(false) } }, ) override suspend fun onActivated(): Nothing { override suspend fun onActivated(): Nothing { coroutineScope { coroutineScope { launch { hydrator.activate() } launch { hydrator.activate() } Loading packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.systemui.shade.ui.viewmodel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory Loading @@ -31,6 +33,8 @@ val Kosmos.notificationsShadeOverlayContentViewModel: notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory, notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory, sceneInteractor = sceneInteractor, sceneInteractor = sceneInteractor, shadeInteractor = shadeInteractor, shadeInteractor = shadeInteractor, disableFlagsInteractor = disableFlagsInteractor, mediaCarouselInteractor = mediaCarouselInteractor, activeNotificationsInteractor = activeNotificationsInteractor, activeNotificationsInteractor = activeNotificationsInteractor, ) ) } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt +31 −5 Original line number Original line Diff line number Diff line Loading @@ -23,7 +23,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.ElementKey Loading @@ -34,6 +34,13 @@ import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.media.controls.ui.composable.isLandscape import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.COLLAPSED import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.EXPANDED import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.res.R import com.android.systemui.res.R Loading @@ -42,10 +49,11 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.OverlayShadeHeader import com.android.systemui.shade.ui.composable.OverlayShadeHeader import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.util.Utils import dagger.Lazy import dagger.Lazy import javax.inject.Inject import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow @SysUISingleton @SysUISingleton Loading @@ -58,6 +66,8 @@ constructor( private val stackScrollView: Lazy<NotificationScrollView>, private val stackScrollView: Lazy<NotificationScrollView>, private val clockSection: DefaultClockSection, private val clockSection: DefaultClockSection, private val keyguardClockViewModel: KeyguardClockViewModel, private val keyguardClockViewModel: KeyguardClockViewModel, private val mediaCarouselController: MediaCarouselController, @Named(QUICK_QS_PANEL) private val mediaHost: Lazy<MediaHost>, ) : Overlay { ) : Overlay { override val key = Overlays.NotificationsShade override val key = Overlays.NotificationsShade Loading @@ -84,6 +94,11 @@ constructor( viewModel.notificationsPlaceholderViewModelFactory.create() viewModel.notificationsPlaceholderViewModelFactory.create() } } val usingCollapsedLandscapeMedia = Utils.useCollapsedMediaInLandscape(LocalResources.current) mediaHost.get().expansion = if (usingCollapsedLandscapeMedia && isLandscape()) COLLAPSED else EXPANDED OverlayShade( OverlayShade( panelElement = NotificationsShade.Elements.Panel, panelElement = NotificationsShade.Elements.Panel, alignmentOnWideScreens = Alignment.TopStart, alignmentOnWideScreens = Alignment.TopStart, Loading @@ -96,9 +111,7 @@ constructor( } } OverlayShadeHeader( OverlayShadeHeader( viewModel = headerViewModel, viewModel = headerViewModel, modifier = modifier = Modifier.element(NotificationsShade.Elements.StatusBar), Modifier.element(NotificationsShade.Elements.StatusBar) .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader), ) ) }, }, ) { ) { Loading @@ -116,6 +129,19 @@ constructor( } } } } MediaCarousel( isVisible = viewModel.showMedia, mediaHost = mediaHost.get(), carouselController = mediaCarouselController, usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia, modifier = Modifier.padding( top = notificationStackPadding, start = notificationStackPadding, end = notificationStackPadding, ), ) NotificationScrollingStack( NotificationScrollingStack( shadeSession = shadeSession, shadeSession = shadeSession, stackScrollView = stackScrollView.get(), stackScrollView = stackScrollView.get(), Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt +37 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.notifications.ui.viewmodel package com.android.systemui.notifications.ui.viewmodel import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS import android.testing.TestableLooper import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest Loading @@ -28,6 +29,8 @@ import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.domain.interactor.powerInteractor Loading @@ -39,10 +42,13 @@ import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs import com.android.systemui.testKosmos import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.update import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest Loading @@ -50,6 +56,7 @@ import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @SmallTest @RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @TestableLooper.RunWithLooper Loading Loading @@ -155,6 +162,36 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() { assertThat(underTest.showClock).isFalse() assertThat(underTest.showClock).isFalse() } } @Test fun showMedia_activeMedia_true() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) runCurrent() assertThat(underTest.showMedia).isTrue() } @Test fun showMedia_noActiveMedia_false() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false)) runCurrent() assertThat(underTest.showMedia).isFalse() } @Test fun showMedia_qsDisabled_false() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) kosmos.fakeDisableFlagsRepository.disableFlags.update { it.copy(disable2 = DISABLE2_QUICK_SETTINGS) } runCurrent() assertThat(underTest.showMedia).isFalse() } private fun TestScope.lockDevice() { private fun TestScope.lockDevice() { val currentScene by collectLastValue(sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) kosmos.powerInteractor.setAsleepForTest() kosmos.powerInteractor.setAsleepForTest() Loading
packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt +22 −0 Original line number Original line Diff line number Diff line Loading @@ -20,12 +20,15 @@ import androidx.compose.runtime.getValue import com.android.app.tracing.coroutines.launchTraced as launch import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.lifecycle.Hydrator import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation Loading @@ -33,6 +36,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOf /** /** * Models UI state used to render the content of the notifications shade overlay. * Models UI state used to render the content of the notifications shade overlay. Loading @@ -47,6 +51,8 @@ constructor( val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, val sceneInteractor: SceneInteractor, val sceneInteractor: SceneInteractor, private val shadeInteractor: ShadeInteractor, private val shadeInteractor: ShadeInteractor, disableFlagsInteractor: DisableFlagsInteractor, mediaCarouselInteractor: MediaCarouselInteractor, activeNotificationsInteractor: ActiveNotificationsInteractor, activeNotificationsInteractor: ActiveNotificationsInteractor, ) : ExclusiveActivatable() { ) : ExclusiveActivatable() { Loading @@ -69,6 +75,22 @@ constructor( ), ), ) ) val showMedia: Boolean by hydrator.hydratedStateOf( traceName = "showMedia", initialValue = disableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled() && mediaCarouselInteractor.hasActiveMediaOrRecommendation.value, source = disableFlagsInteractor.disableFlags.flatMapLatestConflated { if (it.isQuickSettingsEnabled()) { mediaCarouselInteractor.hasActiveMediaOrRecommendation } else { flowOf(false) } }, ) override suspend fun onActivated(): Nothing { override suspend fun onActivated(): Nothing { coroutineScope { coroutineScope { launch { hydrator.activate() } launch { hydrator.activate() } Loading
packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.systemui.shade.ui.viewmodel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory Loading @@ -31,6 +33,8 @@ val Kosmos.notificationsShadeOverlayContentViewModel: notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory, notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory, sceneInteractor = sceneInteractor, sceneInteractor = sceneInteractor, shadeInteractor = shadeInteractor, shadeInteractor = shadeInteractor, disableFlagsInteractor = disableFlagsInteractor, mediaCarouselInteractor = mediaCarouselInteractor, activeNotificationsInteractor = activeNotificationsInteractor, activeNotificationsInteractor = activeNotificationsInteractor, ) ) } }