diff options
5 files changed, 166 insertions, 24 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt index f40bfbdeb54b..8d678ef00b4a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt @@ -506,7 +506,7 @@ class NotificationListViewModelTest(flags: FlagsParameterization) : SysuiTestCas @EnableSceneContainer fun pinnedHeadsUpRows_filtersForPinnedItems() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) // WHEN there are no pinned rows val rows = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt index aa203d7c0aa9..e25127e3e0d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt @@ -39,10 +39,10 @@ class HeadsUpNotificationInteractor @Inject constructor( private val headsUpRepository: HeadsUpRepository, - private val faceAuthInteractor: DeviceEntryFaceAuthInteractor, - private val keyguardTransitionInteractor: KeyguardTransitionInteractor, - private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, - private val shadeInteractor: ShadeInteractor, + faceAuthInteractor: DeviceEntryFaceAuthInteractor, + keyguardTransitionInteractor: KeyguardTransitionInteractor, + notificationsKeyguardInteractor: NotificationsKeyguardInteractor, + shadeInteractor: ShadeInteractor, ) { /** The top-ranked heads up row, regardless of pinned state */ @@ -56,8 +56,7 @@ constructor( } .distinctUntilChanged() - /** Set of currently pinned top-level heads up rows to be displayed. */ - val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> by lazy { + private val activeHeadsUpRows: Flow<Set<Pair<HeadsUpRowKey, Boolean>>> by lazy { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { flowOf(emptySet()) } else { @@ -67,9 +66,7 @@ constructor( repositories.map { repo -> repo.isPinned.map { isPinned -> repo to isPinned } } - combine(toCombine) { pairs -> - pairs.filter { (_, isPinned) -> isPinned }.map { (repo, _) -> repo }.toSet() - } + combine(toCombine) { pairs -> pairs.toSet() } } else { // if the set is empty, there are no flows to combine flowOf(emptySet()) @@ -78,6 +75,26 @@ constructor( } } + /** Set of currently active top-level heads up rows to be displayed. */ + val activeHeadsUpRowKeys: Flow<Set<HeadsUpRowKey>> by lazy { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { + flowOf(emptySet()) + } else { + activeHeadsUpRows.map { it.map { (repo, _) -> repo }.toSet() } + } + } + + /** Set of currently pinned top-level heads up rows to be displayed. */ + val pinnedHeadsUpRowKeys: Flow<Set<HeadsUpRowKey>> by lazy { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { + flowOf(emptySet()) + } else { + activeHeadsUpRows.map { + it.filter { (_, isPinned) -> isPinned }.map { (repo, _) -> repo }.toSet() + } + } + } + /** Are there any pinned heads up rows to display? */ val hasPinnedRows: Flow<Boolean> by lazy { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt index 935e2a37b13c..38390e7bdb39 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt @@ -356,11 +356,23 @@ constructor( } } - val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> by lazy { + val activeHeadsUpRowKeys: Flow<Set<HeadsUpRowKey>> by lazy { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { flowOf(emptySet()) } else { - headsUpNotificationInteractor.pinnedHeadsUpRows.dumpWhileCollecting("pinnedHeadsUpRows") + headsUpNotificationInteractor.activeHeadsUpRowKeys.dumpWhileCollecting( + "pinnedHeadsUpRows" + ) + } + } + + val pinnedHeadsUpRowKeys: Flow<Set<HeadsUpRowKey>> by lazy { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { + flowOf(emptySet()) + } else { + headsUpNotificationInteractor.pinnedHeadsUpRowKeys.dumpWhileCollecting( + "pinnedHeadsUpRows" + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt index dc15970b318b..e2e5c5970ff5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt @@ -26,6 +26,7 @@ import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch class HeadsUpNotificationViewBinder @@ -35,18 +36,21 @@ constructor(private val viewModel: NotificationListViewModel) { coroutineScope { launch { var previousKeys = emptySet<HeadsUpRowKey>() - viewModel.pinnedHeadsUpRows + combine(viewModel.pinnedHeadsUpRowKeys, viewModel.activeHeadsUpRowKeys, ::Pair) .sample(viewModel.headsUpAnimationsEnabled, ::Pair) .collect { (newKeys, animationsEnabled) -> - val added = newKeys - previousKeys - val removed = previousKeys - newKeys - previousKeys = newKeys + val pinned = newKeys.first + val all = newKeys.second + val added = all.union(pinned) - previousKeys + val removed = previousKeys - pinned + previousKeys = pinned + Pair(added, removed) if (animationsEnabled) { added.forEach { key -> parentView.generateHeadsUpAnimation( obtainView(key), - /* isHeadsUp = */ true + /* isHeadsUp = */ true, ) } removed.forEach { key -> diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt index 7d5278ed1601..eb1bcc7fe147 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt @@ -146,9 +146,17 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { } @Test + fun activeRows_noRows_isEmpty() = + testScope.runTest { + val activeHeadsUpRows by collectLastValue(underTest.activeHeadsUpRowKeys) + + assertThat(activeHeadsUpRows).isEmpty() + } + + @Test fun pinnedRows_noRows_isEmpty() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) assertThat(pinnedHeadsUpRows).isEmpty() } @@ -156,7 +164,7 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { @Test fun pinnedRows_noPinnedRows_isEmpty() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) // WHEN no rows are pinned headsUpRepository.setNotifications( fakeHeadsUpRowRepository("key 0"), @@ -170,9 +178,27 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { } @Test + fun activeRows_noPinnedRows_containsAllRows() = + testScope.runTest { + val activeHeadsUpRows by collectLastValue(underTest.activeHeadsUpRowKeys) + // WHEN no rows are pinned + val rows = + arrayListOf( + fakeHeadsUpRowRepository("key 0"), + fakeHeadsUpRowRepository("key 1"), + fakeHeadsUpRowRepository("key 2"), + ) + headsUpRepository.setNotifications(rows) + runCurrent() + + // THEN all rows are present + assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2]) + } + + @Test fun pinnedRows_hasPinnedRows_containsPinnedRows() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) // WHEN some rows are pinned val rows = arrayListOf( @@ -188,9 +214,27 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { } @Test + fun pinnedRows_hasPinnedRows_containsAllRows() = + testScope.runTest { + val activeHeadsUpRows by collectLastValue(underTest.activeHeadsUpRowKeys) + // WHEN no rows are pinned + val rows = + arrayListOf( + fakeHeadsUpRowRepository("key 0", isPinned = true), + fakeHeadsUpRowRepository("key 1", isPinned = true), + fakeHeadsUpRowRepository("key 2"), + ) + headsUpRepository.setNotifications(rows) + runCurrent() + + // THEN all rows are present + assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2]) + } + + @Test fun pinnedRows_rowGetsPinned_containsPinnedRows() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) // GIVEN some rows are pinned val rows = arrayListOf( @@ -210,9 +254,34 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { } @Test + fun activeRows_rowGetsPinned_containsAllRows() = + testScope.runTest { + val activeHeadsUpRows by collectLastValue(underTest.activeHeadsUpRowKeys) + // GIVEN some rows are pinned + val rows = + arrayListOf( + fakeHeadsUpRowRepository("key 0", isPinned = true), + fakeHeadsUpRowRepository("key 1", isPinned = true), + fakeHeadsUpRowRepository("key 2"), + ) + headsUpRepository.setNotifications(rows) + runCurrent() + + // THEN all rows are present + assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2]) + + // WHEN all rows gets pinned + rows[2].isPinned.value = true + runCurrent() + + // THEN no change + assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2]) + } + + @Test fun pinnedRows_allRowsPinned_containsAllRows() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) // WHEN all rows are pinned val rows = arrayListOf( @@ -228,9 +297,27 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { } @Test + fun activeRows_allRowsPinned_containsAllRows() = + testScope.runTest { + val activeHeadsUpRows by collectLastValue(underTest.activeHeadsUpRowKeys) + // WHEN all rows are pinned + val rows = + arrayListOf( + fakeHeadsUpRowRepository("key 0", isPinned = true), + fakeHeadsUpRowRepository("key 1", isPinned = true), + fakeHeadsUpRowRepository("key 2", isPinned = true), + ) + headsUpRepository.setNotifications(rows) + runCurrent() + + // THEN no rows are filtered + assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2]) + } + + @Test fun pinnedRows_rowGetsUnPinned_containsPinnedRows() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) // GIVEN all rows are pinned val rows = arrayListOf( @@ -250,9 +337,31 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() { } @Test + fun activeRows_rowGetsUnPinned_containsAllRows() = + testScope.runTest { + val activeHeadsUpRows by collectLastValue(underTest.activeHeadsUpRowKeys) + // GIVEN all rows are pinned + val rows = + arrayListOf( + fakeHeadsUpRowRepository("key 0", isPinned = true), + fakeHeadsUpRowRepository("key 1", isPinned = true), + fakeHeadsUpRowRepository("key 2", isPinned = true), + ) + headsUpRepository.setNotifications(rows) + runCurrent() + + // WHEN a row gets unpinned + rows[0].isPinned.value = false + runCurrent() + + // THEN all rows are still present + assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2]) + } + + @Test fun pinnedRows_rowGetsPinnedAndUnPinned_containsTheSameInstance() = testScope.runTest { - val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows) + val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRowKeys) val rows = arrayListOf( |