diff options
6 files changed, 93 insertions, 50 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt index 05f2585cfaa5..cabe4afdea60 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt @@ -306,7 +306,7 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { } @Test - fun notificationChip_appIsVisibleOnCreation_emitsNull() = + fun notificationChip_appIsVisibleOnCreation_emitsIsAppVisibleTrue() = kosmos.runTest { activityManagerRepository.fake.startingIsAppVisibleValue = true @@ -323,11 +323,12 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val latest by collectLastValue(underTest.notificationChip) - assertThat(latest).isNull() + assertThat(latest).isNotNull() + assertThat(latest!!.isAppVisible).isTrue() } @Test - fun notificationChip_appNotVisibleOnCreation_emitsValue() = + fun notificationChip_appNotVisibleOnCreation_emitsIsAppVisibleFalse() = kosmos.runTest { activityManagerRepository.fake.startingIsAppVisibleValue = false @@ -345,10 +346,11 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val latest by collectLastValue(underTest.notificationChip) assertThat(latest).isNotNull() + assertThat(latest!!.isAppVisible).isFalse() } @Test - fun notificationChip_hidesWhenAppIsVisible() = + fun notificationChip_updatesWhenAppIsVisible() = kosmos.runTest { val underTest = factory.create( @@ -364,13 +366,13 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val latest by collectLastValue(underTest.notificationChip) activityManagerRepository.fake.setIsAppVisible(UID, false) - assertThat(latest).isNotNull() + assertThat(latest!!.isAppVisible).isFalse() activityManagerRepository.fake.setIsAppVisible(UID, true) - assertThat(latest).isNull() + assertThat(latest!!.isAppVisible).isTrue() activityManagerRepository.fake.setIsAppVisible(UID, false) - assertThat(latest).isNotNull() + assertThat(latest!!.isAppVisible).isFalse() } // Note: This test is theoretically impossible because the notification key should contain the @@ -396,6 +398,7 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { ) val latest by collectLastValue(underTest.notificationChip) assertThat(latest).isNotNull() + assertThat(latest!!.isAppVisible).isFalse() // WHEN the notif gets a new UID that starts as visible activityManagerRepository.fake.startingIsAppVisibleValue = true @@ -408,9 +411,8 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { ) ) - // THEN we re-fetch the app visibility state with the new UID, and since that UID is - // visible, we hide the chip - assertThat(latest).isNull() + // THEN we re-fetch the app visibility state with the new UID + assertThat(latest!!.isAppVisible).isTrue() } companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt index e89c929a5827..d8e4cd927bec 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt @@ -21,8 +21,8 @@ import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.coroutines.collectValues +import com.android.systemui.activity.data.repository.activityManagerRepository +import com.android.systemui.activity.data.repository.fake import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.collectValues @@ -41,7 +41,6 @@ import com.android.systemui.testKosmos import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat import kotlin.test.Test -import kotlinx.coroutines.test.runTest import org.junit.runner.RunWith import org.mockito.kotlin.mock @@ -55,9 +54,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @DisableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_flagOff_noNotifs() = + fun shownNotificationChips_flagOff_noNotifs() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) setNotifs( listOf( @@ -74,9 +73,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_noNotifs_empty() = + fun shownNotificationChips_noNotifs_empty() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) setNotifs(emptyList()) @@ -86,9 +85,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME) - fun notificationChips_notifMissingStatusBarChipIconView_cdFlagOff_empty() = + fun shownNotificationChips_notifMissingStatusBarChipIconView_cdFlagOff_empty() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) setNotifs( listOf( @@ -105,9 +104,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME) - fun notificationChips_notifMissingStatusBarChipIconView_cdFlagOn_notEmpty() = + fun shownNotificationChips_notifMissingStatusBarChipIconView_cdFlagOn_notEmpty() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) setNotifs( listOf( @@ -124,9 +123,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_onePromotedNotif_statusBarIconViewMatches() = + fun shownNotificationChips_onePromotedNotif_statusBarIconViewMatches() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) val icon = mock<StatusBarIconView>() setNotifs( @@ -146,9 +145,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_onlyForPromotedNotifs() = + fun shownNotificationChips_onlyForPromotedNotifs() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) val firstIcon = mock<StatusBarIconView>() val secondIcon = mock<StatusBarIconView>() @@ -179,12 +178,42 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { assertThat(latest!![1].statusBarChipIconView).isEqualTo(secondIcon) } + @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + fun shownNotificationChips_onlyForNotVisibleApps() = + kosmos.runTest { + activityManagerRepository.fake.startingIsAppVisibleValue = false + + val latest by collectLastValue(underTest.shownNotificationChips) + + val uid = 433 + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + uid = uid, + statusBarChipIcon = mock<StatusBarIconView>(), + promotedContent = PromotedNotificationContentModel.Builder("notif1").build(), + ) + ) + ) + + activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false) + assertThat(latest).hasSize(1) + + activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = true) + assertThat(latest).isEmpty() + + activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false) + assertThat(latest).hasSize(1) + } + /** Regression test for b/388521980. */ @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_callNotifIsAlsoPromoted_callNotifExcluded() = + fun shownNotificationChips_callNotifIsAlsoPromoted_callNotifExcluded() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) setNotifs( listOf( @@ -212,9 +241,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_notifUpdatesGoThrough() = + fun shownNotificationChips_notifUpdatesGoThrough() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) val firstIcon = mock<StatusBarIconView>() val secondIcon = mock<StatusBarIconView>() @@ -262,9 +291,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_promotedNotifDisappearsThenReappears() = + fun shownNotificationChips_promotedNotifDisappearsThenReappears() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) setNotifs( listOf( @@ -304,9 +333,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_sortedBasedOnFirstAppearanceTime() = + fun shownNotificationChips_sortedBasedOnFirstAppearanceTime() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) val firstIcon = mock<StatusBarIconView>() val secondIcon = mock<StatusBarIconView>() @@ -391,9 +420,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) - fun notificationChips_notifChangesKey() = + fun shownNotificationChips_notifChangesKey() = kosmos.runTest { - val latest by collectLastValue(underTest.notificationChips) + val latest by collectLastValue(underTest.shownNotificationChips) val firstIcon = mock<StatusBarIconView>() val secondIcon = mock<StatusBarIconView>() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt index a9338885d4c2..b1af811178e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt @@ -105,17 +105,12 @@ constructor( */ val notificationChip: Flow<NotificationChipModel?> = combine(_notificationModel, isAppVisible) { notif, isAppVisible -> - if (isAppVisible) { - // If the app that posted this notification is visible, we want to hide the chip - // because information between the status bar chip and the app itself could be - // out-of-sync (like a timer that's slightly off) - null - } else { - notif.toNotificationChipModel() - } + notif.toNotificationChipModel(isAppVisible) } - private fun ActiveNotificationModel.toNotificationChipModel(): NotificationChipModel? { + private fun ActiveNotificationModel.toNotificationChipModel( + isVisible: Boolean + ): NotificationChipModel? { val promotedContent = this.promotedContent if (promotedContent == null) { logger.w({ @@ -138,7 +133,13 @@ constructor( } } - return NotificationChipModel(key, appName, statusBarChipIconView, promotedContent) + return NotificationChipModel( + key, + appName, + statusBarChipIconView, + promotedContent, + isVisible, + ) } @AssistedFactory diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt index 9463db57585b..c26d10311f1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt @@ -142,10 +142,10 @@ constructor( } /** - * A flow modeling the notifications that should be shown as chips in the status bar. Emits an - * empty list if there are no notifications that should show a status bar chip. + * Emits all notifications that are eligible to show as chips in the status bar. This is + * different from which chips will *actually* show, see [shownNotificationChips] for that. */ - val notificationChips: Flow<List<NotificationChipModel>> = + private val allNotificationChips: Flow<List<NotificationChipModel>> = if (StatusBarNotifChips.isEnabled) { // For all our current interactors... promotedNotificationInteractors.flatMapLatest { intrs -> @@ -172,4 +172,13 @@ constructor( } else { flowOf(emptyList()) } + + /** Emits the notifications that should actually be *shown* as chips in the status bar. */ + val shownNotificationChips: Flow<List<NotificationChipModel>> = + allNotificationChips.map { chipsList -> + // If the app that posted this notification is visible, we want to hide the chip + // because information between the status bar chip and the app itself could be + // out-of-sync (like a timer that's slightly off) + chipsList.filter { !it.isAppVisible } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt index e7a90804a768..97c37628f2e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt @@ -22,8 +22,10 @@ import com.android.systemui.statusbar.notification.promoted.shared.model.Promote /** Modeling all the data needed to render a status bar notification chip. */ data class NotificationChipModel( val key: String, - /** The user-readable name of the app that posted the call notification. */ + /** The user-readable name of the app that posted this notification. */ val appName: String, val statusBarChipIconView: StatusBarIconView?, val promotedContent: PromotedNotificationContentModel, + /** True if the app managing this notification is currently visible to the user. */ + val isAppVisible: Boolean, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt index 2d6102e310f2..3ecbdf82f2cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt @@ -58,7 +58,7 @@ constructor( */ val chips: Flow<List<OngoingActivityChipModel.Active>> = combine( - notifChipsInteractor.notificationChips, + notifChipsInteractor.shownNotificationChips, headsUpNotificationInteractor.statusBarHeadsUpState, ) { notifications, headsUpState -> notifications.map { it.toActivityChipModel(headsUpState) } |