diff options
| author | 2024-02-28 23:31:39 +0000 | |
|---|---|---|
| committer | 2024-02-28 23:31:39 +0000 | |
| commit | e27d800a7f80cb65eeef4607cb1fb678e0286fdd (patch) | |
| tree | e13d9029099fa468eb69548572b0b191cfb8eceb | |
| parent | cd94108a7e4a94ea74f97cf230f984f9e2221ac4 (diff) | |
| parent | 741747931b0fa8931a09bdd75efdcc1e2fda13b6 (diff) | |
Merge "Add Media Carousel to compose lockscreen" into main
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, ) } |