Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt +53 −1 Original line number Diff line number Diff line Loading @@ -27,14 +27,29 @@ import android.testing.TestableLooper.RunWithLooper 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.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.buildNotificationEntry import com.android.systemui.statusbar.notification.buildOngoingCallEntry import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry import com.android.systemui.statusbar.notification.collection.buildEntry import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner import com.android.systemui.statusbar.notification.collection.notifPipeline import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.notification.promoted.domain.interactor.promotedNotificationsInteractor import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.testKosmos import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before Loading @@ -59,7 +74,13 @@ class ColorizedFgsCoordinatorTest : SysuiTestCase() { fun setup() { allowTestableLooperAsMainThread() colorizedFgsCoordinator = ColorizedFgsCoordinator() kosmos.statusBarNotificationChipsInteractor.start() colorizedFgsCoordinator = ColorizedFgsCoordinator( kosmos.applicationCoroutineScope, kosmos.promotedNotificationsInteractor, ) colorizedFgsCoordinator.attach(notifPipeline) sectioner = colorizedFgsCoordinator.sectioner } Loading Loading @@ -178,6 +199,37 @@ class ColorizedFgsCoordinatorTest : SysuiTestCase() { verify(notifPipeline, never()).addPromoter(any()) } @Test @EnableFlags( PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME, ) fun comparatorPutsCallBeforeOther() = kosmos.runTest { // GIVEN a call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = false) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") kosmos.renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val orderedChipNotificationKeys by collectLastValue(kosmos.promotedNotificationsInteractor.orderedChipNotificationKeys) // THEN the order of the notification keys should be the call then the RON assertThat(orderedChipNotificationKeys) .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") // VERIFY that the comparator puts the call before the ron assertThat(sectioner.comparator!!.compare(callEntry, ronEntry)).isLessThan(0) // VERIFY that the comparator puts the ron before the other assertThat(sectioner.comparator!!.compare(ronEntry, otherEntry)).isLessThan(0) } private fun makeCallStyle(): Notification.CallStyle { val pendingIntent = PendingIntent.getBroadcast(mContext, 0, Intent("action"), PendingIntent.FLAG_IMMUTABLE) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.notification.promoted.domain.interactor 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.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.buildNotificationEntry import com.android.systemui.statusbar.notification.buildOngoingCallEntry import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @EnableFlags( PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME, ) class PromotedNotificationsInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val Kosmos.underTest by Fixture { promotedNotificationsInteractor } @Before fun setUp() { kosmos.statusBarNotificationChipsInteractor.start() } @Test fun orderedChipNotificationKeys_containsNonPromotedCalls() = kosmos.runTest { // GIVEN a call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = false) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val orderedChipNotificationKeys by collectLastValue(underTest.orderedChipNotificationKeys) // THEN the order of the notification keys should be the call then the RON assertThat(orderedChipNotificationKeys) .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") } @Test fun orderedChipNotificationKeys_containsPromotedCalls() = kosmos.runTest { // GIVEN a call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = true) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val orderedChipNotificationKeys by collectLastValue(underTest.orderedChipNotificationKeys) // THEN the order of the notification keys should be the call then the RON assertThat(orderedChipNotificationKeys) .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") } @Test fun topPromotedNotificationContent_skipsNonPromotedCalls() = kosmos.runTest { // GIVEN a non-promoted call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = false) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val topPromotedNotificationContent by collectLastValue(underTest.topPromotedNotificationContent) // THEN the ron is first because the call has no content assertThat(topPromotedNotificationContent?.identity?.key) .isEqualTo("0|test_pkg|0|ron|0") } @Test fun topPromotedNotificationContent_includesPromotedCalls() = kosmos.runTest { // GIVEN a promoted call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = true) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val topPromotedNotificationContent by collectLastValue(underTest.topPromotedNotificationContent) // THEN the call is the top notification assertThat(topPromotedNotificationContent?.identity?.key) .isEqualTo("0|test_pkg|0|call|0") } @Test fun topPromotedNotificationContent_nullWithNoPromotedNotifications() = kosmos.runTest { // GIVEN a a non-promoted call and no promoted ongoing entry val callEntry = buildOngoingCallEntry(promoted = false) val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList(listOf(callEntry, otherEntry)) val topPromotedNotificationContent by collectLastValue(underTest.topPromotedNotificationContent) // THEN there is no top promoted notification assertThat(topPromotedNotificationContent).isNull() } } packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt +1 −1 Original line number Diff line number Diff line Loading @@ -145,7 +145,7 @@ constructor( * 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. */ private val allNotificationChips: Flow<List<NotificationChipModel>> = val allNotificationChips: Flow<List<NotificationChipModel>> = if (StatusBarNotifChips.isEnabled) { // For all our current interactors... // TODO(b/364653005): When a promoted notification is added or removed, each individual Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java +44 −10 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.app.Notification; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; Loading @@ -31,9 +32,14 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi; import com.android.systemui.statusbar.notification.promoted.domain.interactor.PromotedNotificationsInteractor; import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; import com.android.systemui.util.kotlin.JavaAdapterKt; import com.google.common.primitives.Booleans; import kotlinx.coroutines.CoroutineScope; import java.util.Collections; import java.util.List; import javax.inject.Inject; Loading @@ -45,15 +51,31 @@ import javax.inject.Inject; @CoordinatorScope public class ColorizedFgsCoordinator implements Coordinator { private static final String TAG = "ColorizedCoordinator"; private final PromotedNotificationsInteractor mPromotedNotificationsInteractor; private final CoroutineScope mMainScope; private List<String> mOrderedPromotedNotifKeys = Collections.emptyList(); @Inject public ColorizedFgsCoordinator() { public ColorizedFgsCoordinator( @Application CoroutineScope mainScope, PromotedNotificationsInteractor promotedNotificationsInteractor ) { mPromotedNotificationsInteractor = promotedNotificationsInteractor; mMainScope = mainScope; } @Override public void attach(NotifPipeline pipeline) { public void attach(@NonNull NotifPipeline pipeline) { if (PromotedNotificationUi.isEnabled()) { pipeline.addPromoter(mPromotedOngoingPromoter); JavaAdapterKt.collectFlow(mMainScope, mPromotedNotificationsInteractor.getOrderedChipNotificationKeys(), (List<String> keys) -> { mOrderedPromotedNotifKeys = keys; mNotifSectioner.invalidateList("updated mOrderedPromotedNotifKeys"); }); } } Loading Loading @@ -82,12 +104,24 @@ public class ColorizedFgsCoordinator implements Coordinator { return false; } private NotifComparator mPreferPromoted = new NotifComparator("PreferPromoted") { /** get the sort key for any entry in the ongoing section */ private int getSortKey(@Nullable NotificationEntry entry) { if (entry == null) return Integer.MAX_VALUE; // Order all promoted notif keys first, using their order in the list final int index = mOrderedPromotedNotifKeys.indexOf(entry.getKey()); if (index >= 0) return index; // Next, prioritize promoted ongoing over other notifications return isPromotedOngoing(entry) ? Integer.MAX_VALUE - 1 : Integer.MAX_VALUE; } private final NotifComparator mOngoingComparator = new NotifComparator( "OngoingComparator") { @Override public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) { return -1 * Booleans.compare( isPromotedOngoing(o1.getRepresentativeEntry()), isPromotedOngoing(o2.getRepresentativeEntry())); return Integer.compare( getSortKey(o1.getRepresentativeEntry()), getSortKey(o2.getRepresentativeEntry()) ); } }; Loading @@ -95,7 +129,7 @@ public class ColorizedFgsCoordinator implements Coordinator { @Override public NotifComparator getComparator() { if (PromotedNotificationUi.isEnabled()) { return mPreferPromoted; return mOngoingComparator; } else { return null; } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt +3 −5 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.promoted.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style import com.android.systemui.util.kotlin.FlowDumperImpl Loading @@ -30,13 +29,12 @@ import kotlinx.coroutines.flow.map class AODPromotedNotificationInteractor @Inject constructor( activeNotificationsInteractor: ActiveNotificationsInteractor, promotedNotificationsInteractor: PromotedNotificationsInteractor, dumpManager: DumpManager, ) : FlowDumperImpl(dumpManager) { /** The content to show as the promoted notification on AOD */ val content: Flow<PromotedNotificationContentModel?> = activeNotificationsInteractor.topLevelRepresentativeNotifications.map { notifs -> notifs.firstNotNullOfOrNull { it.promotedContent } } promotedNotificationsInteractor.topPromotedNotificationContent val isPresent: Flow<Boolean> = content Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt +53 −1 Original line number Diff line number Diff line Loading @@ -27,14 +27,29 @@ import android.testing.TestableLooper.RunWithLooper 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.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.buildNotificationEntry import com.android.systemui.statusbar.notification.buildOngoingCallEntry import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry import com.android.systemui.statusbar.notification.collection.buildEntry import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner import com.android.systemui.statusbar.notification.collection.notifPipeline import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.notification.promoted.domain.interactor.promotedNotificationsInteractor import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.testKosmos import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before Loading @@ -59,7 +74,13 @@ class ColorizedFgsCoordinatorTest : SysuiTestCase() { fun setup() { allowTestableLooperAsMainThread() colorizedFgsCoordinator = ColorizedFgsCoordinator() kosmos.statusBarNotificationChipsInteractor.start() colorizedFgsCoordinator = ColorizedFgsCoordinator( kosmos.applicationCoroutineScope, kosmos.promotedNotificationsInteractor, ) colorizedFgsCoordinator.attach(notifPipeline) sectioner = colorizedFgsCoordinator.sectioner } Loading Loading @@ -178,6 +199,37 @@ class ColorizedFgsCoordinatorTest : SysuiTestCase() { verify(notifPipeline, never()).addPromoter(any()) } @Test @EnableFlags( PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME, ) fun comparatorPutsCallBeforeOther() = kosmos.runTest { // GIVEN a call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = false) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") kosmos.renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val orderedChipNotificationKeys by collectLastValue(kosmos.promotedNotificationsInteractor.orderedChipNotificationKeys) // THEN the order of the notification keys should be the call then the RON assertThat(orderedChipNotificationKeys) .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") // VERIFY that the comparator puts the call before the ron assertThat(sectioner.comparator!!.compare(callEntry, ronEntry)).isLessThan(0) // VERIFY that the comparator puts the ron before the other assertThat(sectioner.comparator!!.compare(ronEntry, otherEntry)).isLessThan(0) } private fun makeCallStyle(): Notification.CallStyle { val pendingIntent = PendingIntent.getBroadcast(mContext, 0, Intent("action"), PendingIntent.FLAG_IMMUTABLE) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.notification.promoted.domain.interactor 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.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.buildNotificationEntry import com.android.systemui.statusbar.notification.buildOngoingCallEntry import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @EnableFlags( PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME, ) class PromotedNotificationsInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val Kosmos.underTest by Fixture { promotedNotificationsInteractor } @Before fun setUp() { kosmos.statusBarNotificationChipsInteractor.start() } @Test fun orderedChipNotificationKeys_containsNonPromotedCalls() = kosmos.runTest { // GIVEN a call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = false) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val orderedChipNotificationKeys by collectLastValue(underTest.orderedChipNotificationKeys) // THEN the order of the notification keys should be the call then the RON assertThat(orderedChipNotificationKeys) .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") } @Test fun orderedChipNotificationKeys_containsPromotedCalls() = kosmos.runTest { // GIVEN a call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = true) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val orderedChipNotificationKeys by collectLastValue(underTest.orderedChipNotificationKeys) // THEN the order of the notification keys should be the call then the RON assertThat(orderedChipNotificationKeys) .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") } @Test fun topPromotedNotificationContent_skipsNonPromotedCalls() = kosmos.runTest { // GIVEN a non-promoted call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = false) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val topPromotedNotificationContent by collectLastValue(underTest.topPromotedNotificationContent) // THEN the ron is first because the call has no content assertThat(topPromotedNotificationContent?.identity?.key) .isEqualTo("0|test_pkg|0|ron|0") } @Test fun topPromotedNotificationContent_includesPromotedCalls() = kosmos.runTest { // GIVEN a promoted call and a promoted ongoing notification val callEntry = buildOngoingCallEntry(promoted = true) val ronEntry = buildPromotedOngoingEntry() val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList( listOf(callEntry, ronEntry, otherEntry) ) val topPromotedNotificationContent by collectLastValue(underTest.topPromotedNotificationContent) // THEN the call is the top notification assertThat(topPromotedNotificationContent?.identity?.key) .isEqualTo("0|test_pkg|0|call|0") } @Test fun topPromotedNotificationContent_nullWithNoPromotedNotifications() = kosmos.runTest { // GIVEN a a non-promoted call and no promoted ongoing entry val callEntry = buildOngoingCallEntry(promoted = false) val otherEntry = buildNotificationEntry(tag = "other") renderNotificationListInteractor.setRenderedList(listOf(callEntry, otherEntry)) val topPromotedNotificationContent by collectLastValue(underTest.topPromotedNotificationContent) // THEN there is no top promoted notification assertThat(topPromotedNotificationContent).isNull() } }
packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt +1 −1 Original line number Diff line number Diff line Loading @@ -145,7 +145,7 @@ constructor( * 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. */ private val allNotificationChips: Flow<List<NotificationChipModel>> = val allNotificationChips: Flow<List<NotificationChipModel>> = if (StatusBarNotifChips.isEnabled) { // For all our current interactors... // TODO(b/364653005): When a promoted notification is added or removed, each individual Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java +44 −10 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.app.Notification; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; Loading @@ -31,9 +32,14 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi; import com.android.systemui.statusbar.notification.promoted.domain.interactor.PromotedNotificationsInteractor; import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; import com.android.systemui.util.kotlin.JavaAdapterKt; import com.google.common.primitives.Booleans; import kotlinx.coroutines.CoroutineScope; import java.util.Collections; import java.util.List; import javax.inject.Inject; Loading @@ -45,15 +51,31 @@ import javax.inject.Inject; @CoordinatorScope public class ColorizedFgsCoordinator implements Coordinator { private static final String TAG = "ColorizedCoordinator"; private final PromotedNotificationsInteractor mPromotedNotificationsInteractor; private final CoroutineScope mMainScope; private List<String> mOrderedPromotedNotifKeys = Collections.emptyList(); @Inject public ColorizedFgsCoordinator() { public ColorizedFgsCoordinator( @Application CoroutineScope mainScope, PromotedNotificationsInteractor promotedNotificationsInteractor ) { mPromotedNotificationsInteractor = promotedNotificationsInteractor; mMainScope = mainScope; } @Override public void attach(NotifPipeline pipeline) { public void attach(@NonNull NotifPipeline pipeline) { if (PromotedNotificationUi.isEnabled()) { pipeline.addPromoter(mPromotedOngoingPromoter); JavaAdapterKt.collectFlow(mMainScope, mPromotedNotificationsInteractor.getOrderedChipNotificationKeys(), (List<String> keys) -> { mOrderedPromotedNotifKeys = keys; mNotifSectioner.invalidateList("updated mOrderedPromotedNotifKeys"); }); } } Loading Loading @@ -82,12 +104,24 @@ public class ColorizedFgsCoordinator implements Coordinator { return false; } private NotifComparator mPreferPromoted = new NotifComparator("PreferPromoted") { /** get the sort key for any entry in the ongoing section */ private int getSortKey(@Nullable NotificationEntry entry) { if (entry == null) return Integer.MAX_VALUE; // Order all promoted notif keys first, using their order in the list final int index = mOrderedPromotedNotifKeys.indexOf(entry.getKey()); if (index >= 0) return index; // Next, prioritize promoted ongoing over other notifications return isPromotedOngoing(entry) ? Integer.MAX_VALUE - 1 : Integer.MAX_VALUE; } private final NotifComparator mOngoingComparator = new NotifComparator( "OngoingComparator") { @Override public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) { return -1 * Booleans.compare( isPromotedOngoing(o1.getRepresentativeEntry()), isPromotedOngoing(o2.getRepresentativeEntry())); return Integer.compare( getSortKey(o1.getRepresentativeEntry()), getSortKey(o2.getRepresentativeEntry()) ); } }; Loading @@ -95,7 +129,7 @@ public class ColorizedFgsCoordinator implements Coordinator { @Override public NotifComparator getComparator() { if (PromotedNotificationUi.isEnabled()) { return mPreferPromoted; return mOngoingComparator; } else { return null; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt +3 −5 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.promoted.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style import com.android.systemui.util.kotlin.FlowDumperImpl Loading @@ -30,13 +29,12 @@ import kotlinx.coroutines.flow.map class AODPromotedNotificationInteractor @Inject constructor( activeNotificationsInteractor: ActiveNotificationsInteractor, promotedNotificationsInteractor: PromotedNotificationsInteractor, dumpManager: DumpManager, ) : FlowDumperImpl(dumpManager) { /** The content to show as the promoted notification on AOD */ val content: Flow<PromotedNotificationContentModel?> = activeNotificationsInteractor.topLevelRepresentativeNotifications.map { notifs -> notifs.firstNotNullOfOrNull { it.promotedContent } } promotedNotificationsInteractor.topPromotedNotificationContent val isPresent: Flow<Boolean> = content Loading