summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Aaron Liu <aaronjli@google.com> 2024-02-28 23:31:39 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-02-28 23:31:39 +0000
commite27d800a7f80cb65eeef4607cb1fb678e0286fdd (patch)
treee13d9029099fa468eb69548572b0b191cfb8eceb
parentcd94108a7e4a94ea74f97cf230f984f9e2221ac4 (diff)
parent741747931b0fa8931a09bdd75efdcc1e2fda13b6 (diff)
Merge "Add Media Carousel to compose lockscreen" into main
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt72
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt2
11 files changed, 179 insertions, 19 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 452dc03facfd..d23cd0c06aab 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -35,11 +35,13 @@ import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSect
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
@@ -63,6 +65,7 @@ constructor(
private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
+ private val mediaCarouselSection: MediaCarouselSection,
private val clockInteractor: KeyguardClockInteractor,
) : ComposableLockscreenSceneBlueprint {
@@ -112,10 +115,16 @@ constructor(
if (viewModel.isLargeClockVisible) {
Spacer(modifier = Modifier.weight(weight = 1f))
- with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) }
+ with(clockSection) {
+ LargeClock(
+ modifier = Modifier.fillMaxWidth(),
+ )
+ }
}
- if (viewModel.areNotificationsVisible) {
+ with(mediaCarouselSection) { MediaCarousel() }
+
+ if (viewModel.areNotificationsVisible(resources = resources)) {
with(notificationSection) {
Notifications(
modifier = Modifier.fillMaxWidth().weight(weight = 1f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index 71c60c70a655..c422c4b58b55 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -35,6 +35,7 @@ import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSect
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
@@ -63,6 +64,7 @@ constructor(
private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
+ private val mediaCarouselSection: MediaCarouselSection,
private val clockInteractor: KeyguardClockInteractor,
) : ComposableLockscreenSceneBlueprint {
@@ -115,7 +117,9 @@ constructor(
with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) }
}
- if (viewModel.areNotificationsVisible) {
+ with(mediaCarouselSection) { MediaCarousel() }
+
+ if (viewModel.areNotificationsVisible(resources = resources)) {
with(notificationSection) {
Notifications(
modifier = Modifier.fillMaxWidth().weight(weight = 1f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
index af836b68544c..d2184252102b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
@@ -41,6 +41,7 @@ import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSect
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
@@ -70,6 +71,7 @@ constructor(
private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
+ private val mediaCarouselSection: MediaCarouselSection,
private val clockInteractor: KeyguardClockInteractor,
private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
) : ComposableLockscreenSceneBlueprint {
@@ -100,6 +102,14 @@ constructor(
modifier = Modifier.fillMaxHeight().weight(weight = 1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
+ with(clockSection) {
+ SmallClock(
+ burnInParams = burnIn.parameters,
+ onTopChanged = burnIn.onSmallClockTopChanged,
+ modifier = Modifier.fillMaxWidth(),
+ )
+ }
+
with(smartSpaceSection) {
SmartSpace(
burnInParams = burnIn.parameters,
@@ -121,9 +131,13 @@ constructor(
)
}
- Spacer(modifier = Modifier.weight(weight = 1f))
- with(clockSection) { LargeClock() }
- Spacer(modifier = Modifier.weight(weight = 1f))
+ if (viewModel.isLargeClockVisible) {
+ Spacer(modifier = Modifier.weight(weight = 1f))
+ with(clockSection) { LargeClock() }
+ Spacer(modifier = Modifier.weight(weight = 1f))
+ }
+
+ with(mediaCarouselSection) { MediaCarousel() }
}
with(notificationSection) {
val splitShadeTopMargin: Dp =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
index e2e7a950cdfd..f86623fe935c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
@@ -41,12 +41,14 @@ import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
import dagger.Binds
@@ -68,6 +70,7 @@ constructor(
private val bottomAreaSection: BottomAreaSection,
private val settingsMenuSection: SettingsMenuSection,
private val clockInteractor: KeyguardClockInteractor,
+ private val mediaCarouselSection: MediaCarouselSection,
) : ComposableLockscreenSceneBlueprint {
override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
@@ -107,7 +110,9 @@ constructor(
)
}
- if (viewModel.areNotificationsVisible) {
+ with(mediaCarouselSection) { MediaCarousel() }
+
+ if (viewModel.areNotificationsVisible(resources = resources)) {
with(notificationSection) {
Notifications(
modifier = Modifier.fillMaxWidth().weight(weight = 1f)
@@ -228,6 +233,7 @@ constructor(
private val clockInteractor: KeyguardClockInteractor,
private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
private val weatherClockSection: WeatherClockSection,
+ private val mediaCarouselSection: MediaCarouselSection,
) : ComposableLockscreenSceneBlueprint {
override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
@@ -276,6 +282,8 @@ constructor(
),
)
}
+
+ with(mediaCarouselSection) { MediaCarousel() }
}
with(notificationSection) {
val splitShadeTopMargin: Dp =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 335c915411ee..152cc67f6c9e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -39,7 +39,6 @@ import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChange
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
/** Provides small clock and large clock composables for the default clock face. */
@@ -49,7 +48,6 @@ constructor(
private val viewModel: KeyguardClockViewModel,
private val clockInteractor: KeyguardClockInteractor,
private val aodBurnInViewModel: AodBurnInViewModel,
- private val lockscreenSmartspaceController: LockscreenSmartspaceController,
) {
@Composable
@@ -62,15 +60,11 @@ constructor(
val currentClock by viewModel.currentClock.collectAsState()
viewModel.clock = currentClock
- if (clockSize != KeyguardClockSwitch.SMALL) {
+ if (clockSize != KeyguardClockSwitch.SMALL || currentClock?.smallClock?.view == null) {
onTopChanged(null)
return
}
- if (currentClock?.smallClock?.view == null) {
- return
- }
-
val view = LocalView.current
DisposableEffect(view) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
new file mode 100644
index 000000000000..dae120cca981
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.keyguard.ui.composable.section
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.dimensionResource
+import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.keyguard.ui.viewmodel.MediaCarouselViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
+import com.android.systemui.media.controls.ui.view.MediaHost
+import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
+import com.android.systemui.util.animation.MeasurementInput
+import javax.inject.Inject
+import javax.inject.Named
+
+class MediaCarouselSection
+@Inject
+constructor(
+ private val mediaCarouselController: MediaCarouselController,
+ @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost,
+ private val mediaCarouselViewModel: MediaCarouselViewModel,
+) {
+
+ @Composable
+ fun SceneScope.MediaCarousel(modifier: Modifier = Modifier) {
+ if (!mediaCarouselViewModel.isMediaVisible) {
+ return
+ }
+
+ if (mediaCarouselController.mediaFrame == null) {
+ return
+ }
+
+ val mediaHeight = dimensionResource(R.dimen.qs_media_session_height_expanded)
+ // TODO(b/312714128): MediaPlayer background size is not as expected.
+ MediaCarousel(
+ modifier =
+ modifier.height(mediaHeight).fillMaxWidth().onSizeChanged { size ->
+ // Notify controller to size the carousel for the
+ // current space
+ mediaHost.measurementInput = MeasurementInput(size.width, size.height)
+ mediaCarouselController.setSceneContainerSize(size.width, size.height)
+ },
+ mediaHost = mediaHost,
+ layoutWidth = 0, // Layout width is not used.
+ layoutHeight = with(LocalDensity.current) { mediaHeight.toPx() }.toInt(),
+ carouselController = mediaCarouselController,
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 61b2d4e26097..d3e4553be209 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -16,9 +16,12 @@
package com.android.systemui.media.controls.ui.composable
+import android.view.ViewGroup
+import android.widget.FrameLayout
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.view.contains
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -45,6 +48,20 @@ fun SceneScope.MediaCarousel(
AndroidView(
modifier = modifier.element(MediaCarousel.Elements.Content),
- factory = { _ -> carouselController.mediaFrame },
+ factory = { context ->
+ FrameLayout(context).apply {
+ val mediaFrame = carouselController.mediaFrame
+ (mediaFrame.parent as? ViewGroup)?.removeView(mediaFrame)
+ addView(mediaFrame)
+ }
+ },
+ update = {
+ if (it.contains(carouselController.mediaFrame)) {
+ return@AndroidView
+ }
+ val mediaFrame = carouselController.mediaFrame
+ (mediaFrame.parent as? ViewGroup)?.removeView(mediaFrame)
+ it.addView(mediaFrame)
+ },
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
index d4dd2ac78e2a..ad1cef1c1e92 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -46,6 +47,7 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
fun setup() {
with(kosmos) {
fakeFeatureFlagsClassic.set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, true)
+ overrideResource(R.bool.config_use_split_notification_shade, false)
underTest = lockscreenContentViewModel
}
}
@@ -87,11 +89,21 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
}
@Test
+ fun areNotificationsVisible_splitShadeTrue_true() =
+ with(kosmos) {
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE)
+
+ assertThat(underTest.areNotificationsVisible(context.resources)).isTrue()
+ }
+ }
+ @Test
fun areNotificationsVisible_withSmallClock_true() =
with(kosmos) {
testScope.runTest {
kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL)
- assertThat(underTest.areNotificationsVisible).isTrue()
+ assertThat(underTest.areNotificationsVisible(context.resources)).isTrue()
}
}
@@ -100,7 +112,7 @@ class LockscreenContentViewModelTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE)
- assertThat(underTest.areNotificationsVisible).isFalse()
+ assertThat(underTest.areNotificationsVisible(context.resources)).isFalse()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index d79288947e78..23320be129fd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -23,6 +23,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -39,6 +40,7 @@ constructor(
private val interactor: KeyguardBlueprintInteractor,
private val authController: AuthController,
val longPress: KeyguardLongPressViewModel,
+ val splitShadeStateController: SplitShadeStateController,
) {
private val clockSize = clockInteractor.clockSize
@@ -46,8 +48,10 @@ constructor(
get() = authController.isUdfpsSupported
val isLargeClockVisible: Boolean
get() = clockSize.value == KeyguardClockSwitch.LARGE
- val areNotificationsVisible: Boolean
- get() = !isLargeClockVisible
+ fun areNotificationsVisible(resources: Resources): Boolean {
+ return !isLargeClockVisible ||
+ splitShadeStateController.shouldUseSplitNotificationShade(resources)
+ }
fun getSmartSpacePaddingTop(resources: Resources): Int {
return if (isLargeClockVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt
new file mode 100644
index 000000000000..027a739b4abf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
+import javax.inject.Inject
+
+class MediaCarouselViewModel @Inject constructor(mediaDataManager: MediaDataManager) {
+ val isMediaVisible: Boolean = mediaDataManager.hasActiveMediaOrRecommendation()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
index 96de4bae63d4..8da5dd46b62a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.biometrics.authController
import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.splitShadeStateController
val Kosmos.lockscreenContentViewModel by
Kosmos.Fixture {
@@ -28,5 +29,6 @@ val Kosmos.lockscreenContentViewModel by
interactor = keyguardBlueprintInteractor,
authController = authController,
longPress = keyguardLongPressViewModel,
+ splitShadeStateController = splitShadeStateController,
)
}