diff options
| author | 2024-10-18 23:25:39 +0000 | |
|---|---|---|
| committer | 2024-10-24 01:10:10 +0000 | |
| commit | 12dcc650a078dfc9ca782da988dda712afcaff21 (patch) | |
| tree | 78de1d28946994708ece55c42e402a689b9fce5e | |
| parent | d7e892095d61d765ed98389e27d795f9de33377d (diff) | |
Fix notification bottom sent from SysUI is inaccurate and refactor
Bug: 374382849
Test: atest SharedNotificationContainerViewModelTest
Flag: com.android.systemui.magic_portrait_wallpapers
Change-Id: I97ca05d891cd0bc00a16778657306d5fd8912e23
11 files changed, 169 insertions, 36 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index 25670cb0bb0c..3827dfa533cb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -1229,6 +1229,75 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S assertThat(alpha).isEqualTo(1f) } + @Test + @DisableSceneContainer + fun notificationAbsoluteBottom() = + testScope.runTest { + var notificationCount = 2 + val calculateSpace = { _: Float, _: Boolean -> notificationCount } + val shelfHeight = 10F + val heightForNotification = 20F + val calculateHeight = { count: Int -> count * heightForNotification + shelfHeight } + val stackAbsoluteBottom by + collectLastValue( + underTest.getNotificationStackAbsoluteBottom( + calculateSpace, + calculateHeight, + shelfHeight, + ) + ) + advanceTimeBy(50L) + showLockscreen() + + shadeTestUtil.setSplitShade(false) + keyguardInteractor.setNotificationContainerBounds( + NotificationContainerBounds(top = 100F, bottom = 300F) + ) + configurationRepository.onAnyConfigurationChange() + + assertThat(stackAbsoluteBottom).isEqualTo(150F) + + // Also updates when directly requested (as it would from NotificationStackScrollLayout) + notificationCount = 3 + sharedNotificationContainerInteractor.notificationStackChanged() + advanceTimeBy(50L) + assertThat(stackAbsoluteBottom).isEqualTo(170F) + } + + @Test + @DisableSceneContainer + fun notificationAbsoluteBottom_maxNotificationIsZero_noShelfHeight() = + testScope.runTest { + var notificationCount = 2 + val calculateSpace = { _: Float, _: Boolean -> notificationCount } + val shelfHeight = 10F + val heightForNotification = 20F + val calculateHeight = { count: Int -> count * heightForNotification + shelfHeight } + val stackAbsoluteBottom by + collectLastValue( + underTest.getNotificationStackAbsoluteBottom( + calculateSpace, + calculateHeight, + shelfHeight, + ) + ) + advanceTimeBy(50L) + showLockscreen() + + shadeTestUtil.setSplitShade(false) + keyguardInteractor.setNotificationContainerBounds( + NotificationContainerBounds(top = 100F, bottom = 300F) + ) + configurationRepository.onAnyConfigurationChange() + + assertThat(stackAbsoluteBottom).isEqualTo(150F) + + notificationCount = 0 + sharedNotificationContainerInteractor.notificationStackChanged() + advanceTimeBy(50L) + assertThat(stackAbsoluteBottom).isEqualTo(100F) + } + private suspend fun TestScope.showLockscreen() { shadeTestUtil.setQsExpansion(0f) shadeTestUtil.setLockscreenShadeExpansion(0f) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt index 59676ce126da..111c232280c3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -25,9 +25,4 @@ class FakeWallpaperRepository : WallpaperRepository { override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null) override val wallpaperSupportsAmbientMode = MutableStateFlow(false) override var rootView: View? = null - private val _notificationStackAbsoluteBottom = MutableStateFlow(0F) - - override fun setNotificationStackAbsoluteBottom(bottom: Float) { - _notificationStackAbsoluteBottom.value = bottom - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index 9e99a879be41..a6be5bc4ada0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -269,6 +269,8 @@ interface KeyguardRepository { /** The top of shortcut in screen, used by wallpaper to find remaining space in lockscreen */ val shortcutAbsoluteTop: StateFlow<Float> + val notificationStackAbsoluteBottom: StateFlow<Float> + /** * Returns `true` if the keyguard is showing; `false` otherwise. * @@ -339,6 +341,12 @@ interface KeyguardRepository { fun isShowKeyguardWhenReenabled(): Boolean fun setShortcutAbsoluteTop(top: Float) + + /** + * Set bottom of notifications from notification stack, and Magic Portrait will layout base on + * this value + */ + fun setNotificationStackAbsoluteBottom(bottom: Float) } /** Encapsulates application state for the keyguard. */ @@ -635,6 +643,9 @@ constructor( private val _shortcutAbsoluteTop = MutableStateFlow(0F) override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow() + private val _notificationStackAbsoluteBottom = MutableStateFlow(0F) + override val notificationStackAbsoluteBottom = _notificationStackAbsoluteBottom.asStateFlow() + init { val callback = object : KeyguardStateController.Callback { @@ -717,6 +728,10 @@ constructor( _shortcutAbsoluteTop.value = top } + override fun setNotificationStackAbsoluteBottom(bottom: Float) { + _notificationStackAbsoluteBottom.value = bottom + } + private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel { return when (state) { DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 29c6d5aa5ea2..b24ca1a8d345 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -545,6 +545,10 @@ constructor( repository.isKeyguardGoingAway.value = isGoingAway } + fun setNotificationStackAbsoluteBottom(bottom: Float) { + repository.setNotificationStackAbsoluteBottom(bottom) + } + companion object { private const val TAG = "KeyguardInteractor" } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 87b16efc64fc..1d4916c6cd82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -1200,7 +1200,6 @@ public class NotificationStackScrollLayout if (!SceneContainerFlag.isEnabled()) { setMaxLayoutHeight(getHeight()); updateContentHeight(); - mWallpaperInteractor.setNotificationStackAbsoluteBottom(mContentHeight); } clampScrollPosition(); requestChildrenUpdate(); @@ -1278,7 +1277,6 @@ public class NotificationStackScrollLayout if (mAmbientState.getStackTop() != stackTop) { mAmbientState.setStackTop(stackTop); onTopPaddingChanged(/* animate = */ isAddOrRemoveAnimationPending()); - mWallpaperInteractor.setNotificationStackAbsoluteBottom((int) stackTop); } } @@ -2648,6 +2646,7 @@ public class NotificationStackScrollLayout // The topPadding can be bigger than the regular padding when qs is expanded, in that // state the maxPanelHeight and the contentHeight should be bigger + mContentHeight = (int) (height + Math.max(getIntrinsicPadding(), getTopPadding()) + mBottomPadding); updateScrollability(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index b22143f03b44..6f17455241ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -18,10 +18,12 @@ package com.android.systemui.statusbar.notification.stack.ui.viewbinder import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.Flags import com.android.systemui.common.ui.view.onLayoutChanged import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -48,8 +50,19 @@ constructor( private val notificationScrollViewBinder: NotificationScrollViewBinder, private val communalSettingsInteractor: CommunalSettingsInteractor, @Main private val mainImmediateDispatcher: CoroutineDispatcher, + val keyguardInteractor: KeyguardInteractor, ) { + private val calculateMaxNotifications: (Float, Boolean) -> Int = { space, extraShelfSpace -> + val shelfHeight = controller.getShelfHeight().toFloat() + notificationStackSizeCalculator.computeMaxKeyguardNotifications( + controller.view, + space, + if (extraShelfSpace) shelfHeight else 0f, + shelfHeight, + ) + } + fun bind( view: SharedNotificationContainer, viewModel: SharedNotificationContainerViewModel, @@ -107,17 +120,9 @@ constructor( } launch { - viewModel - .getMaxNotifications { space, extraShelfSpace -> - val shelfHeight = controller.getShelfHeight().toFloat() - notificationStackSizeCalculator.computeMaxKeyguardNotifications( - controller.getView(), - space, - if (extraShelfSpace) shelfHeight else 0f, - shelfHeight, - ) - } - .collect { controller.setMaxDisplayedNotifications(it) } + viewModel.getMaxNotifications(calculateMaxNotifications).collect { + controller.setMaxDisplayedNotifications(it) + } } if (!SceneContainerFlag.isEnabled) { @@ -136,6 +141,30 @@ constructor( } } + if (!SceneContainerFlag.isEnabled) { + if (Flags.magicPortraitWallpapers()) { + launch { + viewModel + .getNotificationStackAbsoluteBottom( + calculateMaxNotifications = calculateMaxNotifications, + calculateHeight = { maxNotifications -> + notificationStackSizeCalculator.computeHeight( + maxNotifs = maxNotifications, + shelfHeight = controller.getShelfHeight().toFloat(), + stack = controller.view, + ) + }, + controller.getShelfHeight().toFloat(), + ) + .collect { bottom -> + keyguardInteractor.setNotificationStackAbsoluteBottom( + bottom + ) + } + } + } + } + launch { viewModel.translationX.collect { x -> controller.translationX = x } } launch { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index 9515029962ea..99e5fdad85bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -672,6 +672,36 @@ constructor( .dumpWhileCollecting("maxNotifications") } + /** + * Wallpaper needs the absolute bottom of notification stack to avoid occlusion + * + * @param calculateMaxNotifications is required by getMaxNotifications as calculateSpace by + * calling computeMaxKeyguardNotifications in NotificationStackSizeCalculator + * @param calculateHeight is calling computeHeight in NotificationStackSizeCalculator The edge + * case is that when maxNotifications is 0, we won't take shelfHeight into account + */ + fun getNotificationStackAbsoluteBottom( + calculateMaxNotifications: (Float, Boolean) -> Int, + calculateHeight: (Int) -> Float, + shelfHeight: Float, + ): Flow<Float> { + SceneContainerFlag.assertInLegacyMode() + + return combine( + getMaxNotifications(calculateMaxNotifications).map { + val height = calculateHeight(it) + if (it == 0) { + height - shelfHeight + } else { + height + } + }, + bounds.map { it.top }, + ) { height, top -> + top + height + } + } + fun notificationStackChanged() { interactor.notificationStackChanged() } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt index 54953c9c2574..9055d18a9f55 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt @@ -35,6 +35,4 @@ class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow() override val wallpaperSupportsAmbientMode = MutableStateFlow(false).asStateFlow() override var rootView: View? = null - - override fun setNotificationStackAbsoluteBottom(bottom: Float) {} } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt index efdd98d5498a..4373a10f7a7d 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -45,7 +45,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map @@ -64,12 +63,6 @@ interface WallpaperRepository { /** Set rootView to get its windowToken afterwards */ var rootView: View? - - /** - * Set bottom of notifications from notification stack, and Magic Portrait will layout base on - * this value - */ - fun setNotificationStackAbsoluteBottom(bottom: Float) } @SysUISingleton @@ -106,7 +99,8 @@ constructor( .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } /** The bottom of notification stack respect to the top of screen. */ - private val notificationStackAbsoluteBottom: MutableStateFlow<Float> = MutableStateFlow(0F) + private val notificationStackAbsoluteBottom: StateFlow<Float> = + keyguardRepository.notificationStackAbsoluteBottom /** The top of shortcut respect to the top of screen. */ private val shortcutAbsoluteTop: StateFlow<Float> = keyguardRepository.shortcutAbsoluteTop @@ -206,10 +200,6 @@ constructor( initialValue = false, ) - override fun setNotificationStackAbsoluteBottom(bottom: Float) { - notificationStackAbsoluteBottom.value = bottom - } - private suspend fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? { return withContext(bgDispatcher) { wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id) diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt index fe6977c367b5..88795cada716 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt @@ -21,10 +21,6 @@ import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow class WallpaperInteractor @Inject constructor(val wallpaperRepository: WallpaperRepository) { - fun setNotificationStackAbsoluteBottom(bottom: Float) { - wallpaperRepository.setNotificationStackAbsoluteBottom(bottom) - } - val wallpaperSupportsAmbientMode: StateFlow<Boolean> = wallpaperRepository.wallpaperSupportsAmbientMode } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt index 08786495eca4..693ec7954d70 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt @@ -131,6 +131,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { override val shortcutAbsoluteTop: StateFlow<Float> get() = _shortcutAbsoluteTop.asStateFlow() + private val _notificationStackAbsoluteBottom = MutableStateFlow(0F) + override val notificationStackAbsoluteBottom: StateFlow<Float> + get() = _notificationStackAbsoluteBottom.asStateFlow() + private val _isKeyguardEnabled = MutableStateFlow(true) override val isKeyguardEnabled: StateFlow<Boolean> = _isKeyguardEnabled.asStateFlow() @@ -294,6 +298,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { _shortcutAbsoluteTop.value = top } + override fun setNotificationStackAbsoluteBottom(bottom: Float) { + _notificationStackAbsoluteBottom.value = bottom + } + override fun setCanIgnoreAuthAndReturnToGone(canWake: Boolean) { _canIgnoreAuthAndReturnToGone.value = canWake } |