From 405bed581ad1d4bd407ec090b529b138d79689d0 Mon Sep 17 00:00:00 2001 From: Steve Elliott <steell@google.com> Date: Mon, 16 Oct 2023 13:52:07 -0400 Subject: [PATCH] Introduce ActiveNotificationModel data model This class serves as an immutable snapshot of ListEntry, so that the recommended architecture stack doesn't have to worry about the notification pipeline mutating data out from under it. This CL also renames and unifies some of the various Notification-related repositories and interactors; "Active" is used to identify the outputs of the notification pipeline, which internally tracks "inactive" notifications (ones that are filtered from view). Flag: NOTIFICATION_ICON_CONTAINER_REFACTOR Bug: 290787599 Bug: 278765923 Test: atest SystemUITests Change-Id: I246b5a5e3a744caad4dcc252c96166e91fe2cc48 --- .../coordinator/KeyguardCoordinator.kt | 8 +-- .../data/NotificationDataLayerModule.kt | 9 +--- ...kt => ActiveNotificationListRepository.kt} | 28 +++------- .../ActiveNotificationsInteractor.kt | 32 +++++++++++ ...tor.kt => NotificationAlertsInteractor.kt} | 11 +--- .../RenderNotificationListInteractor.kt | 25 +++++++-- .../SeenNotificationsInteractor.kt} | 14 ++--- ...ficationIconContainerStatusBarViewModel.kt | 4 +- .../shared/ActiveNotificationModel.kt | 22 ++++++++ ...tificationStackScrollLayoutController.java | 10 ++-- .../repository/NotificationListRepository.kt | 35 ------------ .../phone/StatusBarNotificationPresenter.java | 10 ++-- .../tests/src/com/android/SysUITestModule.kt | 1 - .../coordinator/KeyguardCoordinatorTest.kt | 15 +++--- ...kt => NotificationAlertsInteractorTest.kt} | 6 +-- .../RenderNotificationsListInteractorTest.kt | 48 +++++++++++++++++ .../SeenNotificationsInteractorTest.kt | 54 +++++++++++++++++++ .../shared/TestActiveNotificationModel.kt | 21 ++++++++ ...cationStackScrollLayoutControllerTest.java | 12 ++--- .../StatusBarNotificationPresenterTest.java | 10 ++-- ...keStatusBarNotificationsDataLayerModule.kt | 9 +--- 21 files changed, 254 insertions(+), 130 deletions(-) rename packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/{NotificationStackRepository.kt => ActiveNotificationListRepository.kt} (58%) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt rename packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/{NotificationsInteractor.kt => NotificationAlertsInteractor.kt} (70%) rename packages/SystemUI/src/com/android/systemui/statusbar/notification/{stack/domain/interactor/NotificationListInteractor.kt => domain/interactor/SeenNotificationsInteractor.kt} (67%) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt rename packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/{NotificationsInteractorTest.kt => NotificationAlertsInteractorTest.kt} (92%) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 2d839704e0b73..0c69a65b96af8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -37,8 +37,8 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider +import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider -import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.asIndenting @@ -85,7 +85,7 @@ constructor( @Application private val scope: CoroutineScope, private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider, private val secureSettings: SecureSettings, - private val notificationListInteractor: NotificationListInteractor, + private val seenNotificationsInteractor: SeenNotificationsInteractor, private val statusBarStateController: StatusBarStateController, ) : Coordinator, Dumpable { @@ -351,7 +351,7 @@ constructor( override fun onCleanup() { logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs) - notificationListInteractor.setHasFilteredOutSeenNotifications(hasFilteredAnyNotifs) + seenNotificationsInteractor.setHasFilteredOutSeenNotifications(hasFilteredAnyNotifs) hasFilteredAnyNotifs = false } } @@ -389,7 +389,7 @@ constructor( with(pw.asIndenting()) { println( "notificationListInteractor.hasFilteredOutSeenNotifications.value=" + - notificationListInteractor.hasFilteredOutSeenNotifications.value + seenNotificationsInteractor.hasFilteredOutSeenNotifications.value ) println("unseen notifications:") indentIfPossible { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt index 4126c5eecba31..5435fb5449cd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt @@ -15,15 +15,8 @@ */ package com.android.systemui.statusbar.notification.data -import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepositoryModule import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardStateRepositoryModule import dagger.Module -@Module( - includes = - [ - NotificationStackRepositoryModule::class, - NotificationsKeyguardStateRepositoryModule::class, - ] -) +@Module(includes = [NotificationsKeyguardStateRepositoryModule::class]) interface NotificationDataLayerModule diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationStackRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt similarity index 58% rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationStackRepository.kt rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt index c371f4fee59ec..8064f049c88e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationStackRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt @@ -16,40 +16,26 @@ package com.android.systemui.statusbar.notification.data.repository import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.collection.ListEntry -import dagger.Binds -import dagger.Module +import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import javax.inject.Inject -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow /** - * Repository of notifications in the notification stack. + * Repository of "active" notifications in the notification list. * * This repository serves as the boundary between the * [com.android.systemui.statusbar.notification.collection.NotifPipeline] and the modern * notifications presentation codebase. */ -interface NotificationStackRepository { +@SysUISingleton +class ActiveNotificationListRepository @Inject constructor() { /** * Notifications actively presented to the user in the notification stack. * * @see com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener */ - val renderedEntries: Flow<List<ListEntry>> -} - -/** - * A mutable implementation of [NotificationStackRepository]. Like other "mutable" objects, the - * mutable type should only be exposed where necessary; most consumers should only have access to it - * from behind the immutable [NotificationStackRepository] interface. - */ -@SysUISingleton -class MutableNotificationStackRepository @Inject constructor() : NotificationStackRepository { - override val renderedEntries = MutableStateFlow(emptyList<ListEntry>()) -} + val activeNotifications = MutableStateFlow(emptyMap<String, ActiveNotificationModel>()) -@Module -interface NotificationStackRepositoryModule { - @Binds fun bindImpl(impl: MutableNotificationStackRepository): NotificationStackRepository + /** Are any already-seen notifications currently filtered out of the active list? */ + val hasFilteredOutSeenNotifications = MutableStateFlow(false) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt new file mode 100644 index 0000000000000..bfec60bcd6db4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 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.statusbar.notification.domain.interactor + +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository +import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class ActiveNotificationsInteractor +@Inject +constructor( + repository: ActiveNotificationListRepository, +) { + /** Notifications actively presented to the user in the notification stack, in order. */ + val notifications: Flow<Collection<ActiveNotificationModel>> = + repository.activeNotifications.map { it.values } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt similarity index 70% rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt index 02a667f9706d2..8079ce540e1b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt @@ -18,23 +18,16 @@ package com.android.systemui.statusbar.notification.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository -import com.android.systemui.statusbar.notification.collection.ListEntry -import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepository import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -/** Interactor for notifications in general. */ +/** Interactor for notification alerting. */ @SysUISingleton -class NotificationsInteractor +class NotificationAlertsInteractor @Inject constructor( private val disableFlagsRepository: DisableFlagsRepository, - stackRepository: NotificationStackRepository, ) { /** Returns true if notification alerts are allowed. */ fun areNotificationAlertsEnabled(): Boolean = disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled() - - /** Notifications actively presented to the user in the notification stack. */ - val notifications: Flow<List<ListEntry>> = stackRepository.renderedEntries } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt index ea9b4e70c398e..c5396ddbe565a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt @@ -16,8 +16,10 @@ package com.android.systemui.statusbar.notification.domain.interactor import com.android.systemui.statusbar.notification.collection.ListEntry -import com.android.systemui.statusbar.notification.data.repository.MutableNotificationStackRepository +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository +import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import javax.inject.Inject +import kotlinx.coroutines.flow.update /** * Logic for passing information from the @@ -27,15 +29,30 @@ import javax.inject.Inject class RenderNotificationListInteractor @Inject constructor( - private val repository: MutableNotificationStackRepository, + private val repository: ActiveNotificationListRepository, ) { /** * Sets the current list of rendered notification entries as displayed in the notification * stack. * - * @see com.android.systemui.statusbar.notification.data.repository.NotificationStackRepository.renderedEntries + * @see com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository.activeNotifications */ fun setRenderedList(entries: List<ListEntry>) { - repository.renderedEntries.value = entries.toList() + repository.activeNotifications.update { modelsByKey -> + entries.associateBy( + keySelector = { it.key }, + valueTransform = { it.toModel(modelsByKey[it.key]) } + ) + } + } + + private fun ListEntry.toModel(existing: ActiveNotificationModel?): ActiveNotificationModel { + val isCurrent = + when { + existing == null -> false + key == existing.key -> true + else -> false + } + return if (isCurrent) existing!! else ActiveNotificationModel(key = key) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt similarity index 67% rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt index 3fd68a8bdd7c3..f3e122ce690b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt @@ -14,25 +14,25 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.stack.domain.interactor +package com.android.systemui.statusbar.notification.domain.interactor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow /** Interactor for business logic associated with the notification stack. */ @SysUISingleton -class NotificationListInteractor +class SeenNotificationsInteractor @Inject constructor( - private val notificationListRepository: NotificationListRepository, + private val notificationListRepository: ActiveNotificationListRepository, ) { /** Are any already-seen notifications currently filtered out of the shade? */ - val hasFilteredOutSeenNotifications: StateFlow<Boolean> - get() = notificationListRepository.hasFilteredOutSeenNotifications + val hasFilteredOutSeenNotifications: StateFlow<Boolean> = + notificationListRepository.hasFilteredOutSeenNotifications fun setHasFilteredOutSeenNotifications(value: Boolean) { - notificationListRepository.setHasFilteredOutSeenNotifications(value) + notificationListRepository.hasFilteredOutSeenNotifications.value = value } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt index 40cc294016e55..ee01fcca82d47 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt @@ -19,7 +19,7 @@ import android.graphics.Rect import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor @@ -35,7 +35,7 @@ class NotificationIconContainerStatusBarViewModel constructor( darkIconInteractor: DarkIconInteractor, keyguardInteractor: KeyguardInteractor, - notificationsInteractor: NotificationsInteractor, + notificationsInteractor: ActiveNotificationsInteractor, shadeInteractor: ShadeInteractor, ) : NotificationIconContainerViewModel { override val animationsEnabled: Flow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt new file mode 100644 index 0000000000000..ea29cab3b7dcf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 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.statusbar.notification.shared + +/** Model for entries in the notification stack. */ +data class ActiveNotificationModel( + /** Notification key associated with this entry. */ + val key: String, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 6a70815f82f38..335458225e1d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -106,6 +106,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifStats; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; import com.android.systemui.statusbar.notification.dagger.SilentHeader; +import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -114,7 +115,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationSnooze; -import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor; import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder; import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; @@ -194,7 +194,7 @@ public class NotificationStackScrollLayoutController { private final GroupExpansionManager mGroupExpansionManager; private final NotifPipelineFlags mNotifPipelineFlags; - private final NotificationListInteractor mNotificationListInteractor; + private final SeenNotificationsInteractor mSeenNotificationsInteractor; private final KeyguardTransitionRepository mKeyguardTransitionRepo; private NotificationStackScrollLayout mView; @@ -662,7 +662,7 @@ public class NotificationStackScrollLayoutController { UiEventLogger uiEventLogger, NotificationRemoteInputManager remoteInputManager, VisibilityLocationProviderDelegator visibilityLocationProviderDelegator, - NotificationListInteractor notificationListInteractor, + SeenNotificationsInteractor seenNotificationsInteractor, ShadeController shadeController, InteractionJankMonitor jankMonitor, StackStateLogger stackLogger, @@ -715,7 +715,7 @@ public class NotificationStackScrollLayoutController { mUiEventLogger = uiEventLogger; mRemoteInputManager = remoteInputManager; mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator; - mNotificationListInteractor = notificationListInteractor; + mSeenNotificationsInteractor = seenNotificationsInteractor; mShadeController = shadeController; mNotifIconAreaController = notifIconAreaController; mFeatureFlags = featureFlags; @@ -2006,7 +2006,7 @@ public class NotificationStackScrollLayoutController { public void setNotifStats(@NonNull NotifStats notifStats) { mNotifStats = notifStats; mView.setHasFilteredOutSeenNotifications( - mNotificationListInteractor.getHasFilteredOutSeenNotifications().getValue()); + mSeenNotificationsInteractor.getHasFilteredOutSeenNotifications().getValue()); updateFooter(); updateShowEmptyShadeView(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt deleted file mode 100644 index f6ed8c884816a..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2023 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.statusbar.notification.stack.data.repository - -import com.android.systemui.dagger.SysUISingleton -import javax.inject.Inject -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow - -/** Repository for information about the current notification list. */ -@SysUISingleton -class NotificationListRepository @Inject constructor() { - private val _hasFilteredOutSeenNotifications = MutableStateFlow(false) - val hasFilteredOutSeenNotifications: StateFlow<Boolean> = - _hasFilteredOutSeenNotifications.asStateFlow() - - fun setHasFilteredOutSeenNotifications(value: Boolean) { - _hasFilteredOutSeenNotifications.value = value - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index a5cd062f6f37b..07e2571bcb382 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -52,7 +52,7 @@ import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; -import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor; +import com.android.systemui.statusbar.notification.domain.interactor.NotificationAlertsInteractor; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -80,7 +80,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu private final HeadsUpManager mHeadsUpManager; private final AboveShelfObserver mAboveShelfObserver; private final DozeScrimController mDozeScrimController; - private final NotificationsInteractor mNotificationsInteractor; + private final NotificationAlertsInteractor mNotificationAlertsInteractor; private final NotificationStackScrollLayoutController mNsslController; private final LockscreenShadeTransitionController mShadeTransitionController; private final PowerInteractor mPowerInteractor; @@ -107,7 +107,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu NotificationShadeWindowController notificationShadeWindowController, DynamicPrivacyController dynamicPrivacyController, KeyguardStateController keyguardStateController, - NotificationsInteractor notificationsInteractor, + NotificationAlertsInteractor notificationAlertsInteractor, LockscreenShadeTransitionController shadeTransitionController, PowerInteractor powerInteractor, CommandQueue commandQueue, @@ -127,7 +127,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu mQsController = quickSettingsController; mHeadsUpManager = headsUp; mDynamicPrivacyController = dynamicPrivacyController; - mNotificationsInteractor = notificationsInteractor; + mNotificationAlertsInteractor = notificationAlertsInteractor; mNsslController = stackScrollerController; mShadeTransitionController = shadeTransitionController; mPowerInteractor = powerInteractor; @@ -303,7 +303,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu @Override public boolean suppressInterruptions(NotificationEntry entry) { - return !mNotificationsInteractor.areNotificationAlertsEnabled(); + return !mNotificationAlertsInteractor.areNotificationAlertsEnabled(); } }; } diff --git a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt index ed0541ada77b7..c4b43e1cbe772 100644 --- a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt +++ b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt @@ -26,7 +26,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.broadcast.FakeBroadcastDispatcher import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepositoryModule import dagger.Binds import dagger.Module import dagger.Provides diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt index 546abd4ec79a4..6c1f537e754f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt @@ -39,10 +39,10 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository +import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository -import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener import com.android.systemui.util.mockito.any @@ -246,7 +246,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { unseenFilter.onCleanup() // THEN: The SeenNotificationProvider has been updated to reflect the suppression - assertThat(notificationListInteractor.hasFilteredOutSeenNotifications.value).isTrue() + assertThat(seenNotificationsInteractor.hasFilteredOutSeenNotifications.value).isTrue() } } @@ -597,7 +597,8 @@ class KeyguardCoordinatorTest : SysuiTestCase() { FakeSettings().apply { putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1) } - val notificationListInteractor = NotificationListInteractor(NotificationListRepository()) + val seenNotificationsInteractor = + SeenNotificationsInteractor(ActiveNotificationListRepository()) val keyguardCoordinator = KeyguardCoordinator( testDispatcher, @@ -610,7 +611,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { testScope.backgroundScope, sectionHeaderVisibilityProvider, fakeSettings, - notificationListInteractor, + seenNotificationsInteractor, statusBarStateController, ) keyguardCoordinator.attach(notifPipeline) @@ -618,7 +619,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { KeyguardCoordinatorTestScope( keyguardCoordinator, testScope, - notificationListInteractor, + seenNotificationsInteractor, fakeSettings, ) .testBlock() @@ -628,7 +629,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { private inner class KeyguardCoordinatorTestScope( private val keyguardCoordinator: KeyguardCoordinator, private val scope: TestScope, - val notificationListInteractor: NotificationListInteractor, + val seenNotificationsInteractor: SeenNotificationsInteractor, private val fakeSettings: FakeSettings, ) : CoroutineScope by scope { val testScheduler: TestCoroutineScheduler diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt similarity index 92% rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt index 6bf9e350cd503..683d0aa33d4ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt @@ -27,12 +27,12 @@ import dagger.Component import org.junit.Test @SmallTest -class NotificationsInteractorTest : SysuiTestCase() { +class NotificationAlertsInteractorTest : SysuiTestCase() { @Component(modules = [SysUITestModule::class]) @SysUISingleton interface TestComponent { - val underTest: NotificationsInteractor + val underTest: NotificationAlertsInteractor val disableFlags: FakeDisableFlagsRepository @Component.Factory @@ -42,7 +42,7 @@ class NotificationsInteractorTest : SysuiTestCase() { } private val testComponent: TestComponent = - DaggerNotificationsInteractorTest_TestComponent.factory().create(test = this) + DaggerNotificationAlertsInteractorTest_TestComponent.factory().create(test = this) @Test fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt new file mode 100644 index 0000000000000..8c5c43986f8ae --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 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.statusbar.notification.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.statusbar.notification.collection.ListEntry +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository +import com.android.systemui.statusbar.notification.shared.byKey +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test + +@SmallTest +class RenderNotificationsListInteractorTest : SysuiTestCase() { + + private val notifsRepository = ActiveNotificationListRepository() + private val notifsInteractor = ActiveNotificationsInteractor(notifsRepository) + private val underTest = + RenderNotificationListInteractor( + notifsRepository, + ) + + @Test + fun setRenderedList_preservesOrdering() = runTest { + val notifs by collectLastValue(notifsInteractor.notifications) + val keys = (1..50).shuffled().map { "$it" } + val entries = keys.map { mock<ListEntry> { whenever(key).thenReturn(it) } } + underTest.setRenderedList(entries) + assertThat(notifs).comparingElementsUsing(byKey).containsExactlyElementsIn(keys).inOrder() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt new file mode 100644 index 0000000000000..2a3c1a53559ed --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 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.statusbar.notification.domain.interactor + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class SeenNotificationsInteractorTest : SysuiTestCase() { + + private val repository = ActiveNotificationListRepository() + private val underTest = SeenNotificationsInteractor(repository) + + @Test + fun testNoFilteredOutSeenNotifications() = runTest { + val hasFilteredOutSeenNotifications by + collectLastValue(underTest.hasFilteredOutSeenNotifications) + + underTest.setHasFilteredOutSeenNotifications(false) + + assertThat(hasFilteredOutSeenNotifications).isFalse() + } + + @Test + fun testHasFilteredOutSeenNotifications() = runTest { + val hasFilteredOutSeenNotifications by + collectLastValue(underTest.hasFilteredOutSeenNotifications) + + underTest.setHasFilteredOutSeenNotifications(true) + + assertThat(hasFilteredOutSeenNotifications).isTrue() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt new file mode 100644 index 0000000000000..ed9405814e6aa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2023 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.statusbar.notification.shared + +import com.google.common.truth.Correspondence + +val byKey: Correspondence<ActiveNotificationModel, String> = + Correspondence.transforming({ it?.key }, "has a key of") diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 20197e3ed547d..3dafb23c8a372 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -82,13 +82,13 @@ import com.android.systemui.statusbar.notification.collection.render.GroupExpans import com.android.systemui.statusbar.notification.collection.render.NotifStats; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository; +import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent; import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback; -import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository; -import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor; import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconAreaController; @@ -171,8 +171,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor; - private final NotificationListInteractor mNotificationListInteractor = - new NotificationListInteractor(new NotificationListRepository()); + private final SeenNotificationsInteractor mSeenNotificationsInteractor = + new SeenNotificationsInteractor(new ActiveNotificationListRepository()); private NotificationStackScrollLayoutController mController; @@ -504,7 +504,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Test public void testSetNotifStats_updatesHasFilteredOutSeenNotifications() { initController(/* viewIsAttached= */ true); - mNotificationListInteractor.setHasFilteredOutSeenNotifications(true); + mSeenNotificationsInteractor.setHasFilteredOutSeenNotifications(true); mController.getNotifStackController().setNotifStats(NotifStats.getEmpty()); verify(mNotificationStackScrollLayout).setHasFilteredOutSeenNotifications(true); verify(mNotificationStackScrollLayout).updateFooter(); @@ -704,7 +704,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mUiEventLogger, mRemoteInputManager, mVisibilityLocationProviderDelegator, - mNotificationListInteractor, + mSeenNotificationsInteractor, mShadeController, mJankMonitor, mStackLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index ee4f2089c05c6..53c621d246015 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -53,7 +53,7 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; -import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor; +import com.android.systemui.statusbar.notification.domain.interactor.NotificationAlertsInteractor; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -79,8 +79,8 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { private CommandQueue mCommandQueue; private FakeMetricsLogger mMetricsLogger; private final ShadeController mShadeController = mock(ShadeController.class); - private final NotificationsInteractor mNotificationsInteractor = - mock(NotificationsInteractor.class); + private final NotificationAlertsInteractor mNotificationAlertsInteractor = + mock(NotificationAlertsInteractor.class); private final KeyguardStateController mKeyguardStateController = mock(KeyguardStateController.class); private final InitController mInitController = new InitController(); @@ -116,7 +116,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class), mKeyguardStateController, - mNotificationsInteractor, + mNotificationAlertsInteractor, mock(LockscreenShadeTransitionController.class), mock(PowerInteractor.class), mCommandQueue, @@ -226,7 +226,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { .setTag("a") .setNotification(n) .build(); - when(mNotificationsInteractor.areNotificationAlertsEnabled()).thenReturn(false); + when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false); assertTrue("When alerts aren't enabled, interruptions are suppressed", mInterruptSuppressor.suppressInterruptions(entry)); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt index 465b93a5b1e91..788e3aa9c41a3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt @@ -16,14 +16,7 @@ package com.android.systemui.statusbar.notification.data import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardStateRepositoryModule -import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepositoryModule import dagger.Module -@Module( - includes = - [ - FakeNotificationsKeyguardStateRepositoryModule::class, - NotificationStackRepositoryModule::class, - ] -) +@Module(includes = [FakeNotificationsKeyguardStateRepositoryModule::class]) object FakeStatusBarNotificationsDataLayerModule -- GitLab