Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt +35 −28 Original line number Original line Diff line number Diff line Loading @@ -18,33 +18,29 @@ package com.android.systemui.statusbar.notification import android.content.Context import android.content.Context import android.provider.DeviceConfig import android.provider.DeviceConfig import com.android.internal.annotations.VisibleForTesting import com.android.internal.annotations.VisibleForTesting import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.notification.stack.PriorityBucket import com.android.systemui.util.DeviceConfigProxy import com.android.systemui.util.DeviceConfigProxy import com.android.systemui.util.Utils import com.android.systemui.util.Utils import javax.inject.Inject import javax.inject.Inject private var sUsePeopleFiltering: Boolean? = null private var sUsePeopleFiltering: Boolean? = null /** /** Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */ * Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */ @SysUISingleton @SysUISingleton class NotificationSectionsFeatureManager @Inject constructor( class NotificationSectionsFeatureManager val proxy: DeviceConfigProxy, @Inject val context: Context constructor(val proxy: DeviceConfigProxy, val context: Context) { ) { fun isFilteringEnabled(): Boolean { fun isFilteringEnabled(): Boolean { return usePeopleFiltering(proxy) return usePeopleFiltering(proxy) Loading @@ -55,30 +51,37 @@ class NotificationSectionsFeatureManager @Inject constructor( } } fun getNotificationBuckets(): IntArray { fun getNotificationBuckets(): IntArray { if (PriorityPeopleSection.isEnabled) { if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled) { // We don't need this list to be adaptive, it can be the superset of all features. // We don't need this list to be adaptive, it can be the superset of all features. return intArrayOf( return PriorityBucket.getAllInOrder() BUCKET_MEDIA_CONTROLS, } return when { isFilteringEnabled() && isMediaControlsEnabled() -> intArrayOf( BUCKET_HEADS_UP, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_FOREGROUND_SERVICE, BUCKET_PRIORITY_PEOPLE, BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_ALERTING, BUCKET_SILENT, BUCKET_SILENT ) ) } return when { isFilteringEnabled() && isMediaControlsEnabled() -> intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT) !isFilteringEnabled() && isMediaControlsEnabled() -> !isFilteringEnabled() && isMediaControlsEnabled() -> intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, intArrayOf( BUCKET_ALERTING, BUCKET_SILENT) BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, BUCKET_ALERTING, BUCKET_SILENT ) isFilteringEnabled() && !isMediaControlsEnabled() -> isFilteringEnabled() && !isMediaControlsEnabled() -> intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_PEOPLE, intArrayOf( BUCKET_ALERTING, BUCKET_SILENT) BUCKET_HEADS_UP, else -> BUCKET_FOREGROUND_SERVICE, intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT ) else -> intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) } } } } Loading @@ -94,8 +97,12 @@ class NotificationSectionsFeatureManager @Inject constructor( private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean { private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean { if (sUsePeopleFiltering == null) { if (sUsePeopleFiltering == null) { sUsePeopleFiltering = proxy.getBoolean( sUsePeopleFiltering = DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, true) proxy.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, true ) } } return sUsePeopleFiltering!! return sUsePeopleFiltering!! Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java +18 −13 Original line number Original line Diff line number Diff line Loading @@ -60,22 +60,27 @@ public class ColorizedFgsCoordinator implements Coordinator { public boolean isInSection(ListEntry entry) { public boolean isInSection(ListEntry entry) { NotificationEntry notificationEntry = entry.getRepresentativeEntry(); NotificationEntry notificationEntry = entry.getRepresentativeEntry(); if (notificationEntry != null) { if (notificationEntry != null) { return isColorizedForegroundService(notificationEntry) || isCall(notificationEntry); return isRichOngoing(notificationEntry); } } return false; return false; } } }; /** Determines if the given notification is a colorized or call notification */ public static boolean isRichOngoing(NotificationEntry entry) { return isColorizedForegroundService(entry) || isCall(entry); } private boolean isColorizedForegroundService(NotificationEntry entry) { private static boolean isColorizedForegroundService(NotificationEntry entry) { Notification notification = entry.getSbn().getNotification(); Notification notification = entry.getSbn().getNotification(); return notification.isForegroundService() return notification.isForegroundService() && notification.isColorized() && notification.isColorized() && entry.getImportance() > IMPORTANCE_MIN; && entry.getImportance() > IMPORTANCE_MIN; } } private boolean isCall(NotificationEntry entry) { private static boolean isCall(NotificationEntry entry) { Notification notification = entry.getSbn().getNotification(); Notification notification = entry.getSbn().getNotification(); return entry.getImportance() > IMPORTANCE_MIN return entry.getImportance() > IMPORTANCE_MIN && notification.isStyle(Notification.CallStyle.class); && notification.isStyle(Notification.CallStyle.class); } } }; } } packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +39 −18 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator package com.android.systemui.statusbar.notification.collection.coordinator import android.app.NotificationManager import android.os.UserHandle import android.os.UserHandle import android.provider.Settings import android.provider.Settings import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting Loading @@ -44,7 +45,8 @@ import com.android.systemui.statusbar.notification.collection.provider.SectionHe import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_ONGOING import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_UNSEEN import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.asIndenting import com.android.systemui.util.asIndenting Loading Loading @@ -113,7 +115,7 @@ constructor( private fun attachUnseenFilter(pipeline: NotifPipeline) { private fun attachUnseenFilter(pipeline: NotifPipeline) { if (NotificationMinimalismPrototype.V2.isEnabled) { if (NotificationMinimalismPrototype.V2.isEnabled) { pipeline.addPromoter(unseenNotifPromoter) pipeline.addPromoter(unseenNotifPromoter) pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotif) pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotifs) } } pipeline.addFinalizeFilter(unseenNotifFilter) pipeline.addFinalizeFilter(unseenNotifFilter) pipeline.addCollectionListener(collectionListener) pipeline.addCollectionListener(collectionListener) Loading Loading @@ -347,15 +349,16 @@ constructor( } } } } private fun pickOutTopUnseenNotif(list: List<ListEntry>) { private fun pickOutTopUnseenNotifs(list: List<ListEntry>) { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return // Only ever elevate a top unseen notification on keyguard, not even locked shade // Only ever elevate a top unseen notification on keyguard, not even locked shade if (statusBarStateController.state != StatusBarState.KEYGUARD) { if (statusBarStateController.state != StatusBarState.KEYGUARD) { seenNotificationsInteractor.setTopOngoingNotification(null) seenNotificationsInteractor.setTopUnseenNotification(null) seenNotificationsInteractor.setTopUnseenNotification(null) return return } } // On keyguard pick the top-ranked unseen or ongoing notification to elevate // On keyguard pick the top-ranked unseen or ongoing notification to elevate seenNotificationsInteractor.setTopUnseenNotification( val nonSummaryEntries: Sequence<NotificationEntry> = list list .asSequence() .asSequence() .flatMap { .flatMap { Loading @@ -365,7 +368,15 @@ constructor( else -> error("unhandled type of $it") else -> error("unhandled type of $it") } } } } .filter { shouldIgnoreUnseenCheck(it) || it in unseenNotifications } .filter { it.importance >= NotificationManager.IMPORTANCE_DEFAULT } seenNotificationsInteractor.setTopOngoingNotification( nonSummaryEntries .filter { ColorizedFgsCoordinator.isRichOngoing(it) } .minByOrNull { it.ranking.rank } ) seenNotificationsInteractor.setTopUnseenNotification( nonSummaryEntries .filter { !ColorizedFgsCoordinator.isRichOngoing(it) && it in unseenNotifications } .minByOrNull { it.ranking.rank } .minByOrNull { it.ranking.rank } ) ) } } Loading @@ -375,29 +386,39 @@ constructor( object : NotifPromoter("$TAG-unseen") { object : NotifPromoter("$TAG-unseen") { override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean = override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean = if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false else if (!NotificationMinimalismPrototype.V2.ungroupTopUnseen) false else else seenNotificationsInteractor.isTopUnseenNotification(child) && seenNotificationsInteractor.isTopOngoingNotification(child) || NotificationMinimalismPrototype.V2.ungroupTopUnseen seenNotificationsInteractor.isTopUnseenNotification(child) } } val unseenNotifSectioner = val topOngoingSectioner = object : NotifSectioner("Unseen", BUCKET_FOREGROUND_SERVICE) { object : NotifSectioner("TopOngoing", BUCKET_TOP_ONGOING) { override fun isInSection(entry: ListEntry): Boolean { override fun isInSection(entry: ListEntry): Boolean { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false if ( return entry.anyEntry { notificationEntry -> seenNotificationsInteractor.isTopUnseenNotification(entry.representativeEntry) seenNotificationsInteractor.isTopOngoingNotification(notificationEntry) ) { return true } } if (entry !is GroupEntry) { return false } } return entry.children.any { } seenNotificationsInteractor.isTopUnseenNotification(it) val topUnseenSectioner = object : NotifSectioner("TopUnseen", BUCKET_TOP_UNSEEN) { override fun isInSection(entry: ListEntry): Boolean { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false return entry.anyEntry { notificationEntry -> seenNotificationsInteractor.isTopUnseenNotification(notificationEntry) } } } } } } private fun ListEntry.anyEntry(predicate: (NotificationEntry?) -> Boolean) = when { predicate(representativeEntry) -> true this !is GroupEntry -> false else -> children.any(predicate) } @VisibleForTesting @VisibleForTesting internal val unseenNotifFilter = internal val unseenNotifFilter = object : NotifFilter("$TAG-unseen") { object : NotifFilter("$TAG-unseen") { Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +5 −2 Original line number Original line Diff line number Diff line Loading @@ -116,11 +116,14 @@ constructor( } } // Manually add Ordered Sections // Manually add Ordered Sections if (NotificationMinimalismPrototype.V2.isEnabled) { mOrderedSections.add(keyguardCoordinator.topOngoingSectioner) // Top Ongoing } mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService if (NotificationMinimalismPrototype.V2.isEnabled) { if (NotificationMinimalismPrototype.V2.isEnabled) { mOrderedSections.add(keyguardCoordinator.unseenNotifSectioner) // Unseen (FGS) mOrderedSections.add(keyguardCoordinator.topUnseenSectioner) // Top Unseen } } mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService if (PriorityPeopleSection.isEnabled) { if (PriorityPeopleSection.isEnabled) { mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People } } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,9 @@ class ActiveNotificationListRepository @Inject constructor() { /** Stats about the list of notifications attached to the shade */ /** Stats about the list of notifications attached to the shade */ val notifStats = MutableStateFlow(NotifStats.empty) val notifStats = MutableStateFlow(NotifStats.empty) /** The key of the top ongoing notification */ val topOngoingNotificationKey = MutableStateFlow<String?>(null) /** The key of the top unseen notification */ /** The key of the top unseen notification */ val topUnseenNotificationKey = MutableStateFlow<String?>(null) val topUnseenNotificationKey = MutableStateFlow<String?>(null) } } Loading Loading @@ -75,6 +78,7 @@ data class ActiveNotificationsStore( /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ sealed class Key { sealed class Key { data class Individual(val key: String) : Key() data class Individual(val key: String) : Key() data class Group(val key: String) : Key() data class Group(val key: String) : Key() } } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt +35 −28 Original line number Original line Diff line number Diff line Loading @@ -18,33 +18,29 @@ package com.android.systemui.statusbar.notification import android.content.Context import android.content.Context import android.provider.DeviceConfig import android.provider.DeviceConfig import com.android.internal.annotations.VisibleForTesting import com.android.internal.annotations.VisibleForTesting import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.notification.stack.PriorityBucket import com.android.systemui.util.DeviceConfigProxy import com.android.systemui.util.DeviceConfigProxy import com.android.systemui.util.Utils import com.android.systemui.util.Utils import javax.inject.Inject import javax.inject.Inject private var sUsePeopleFiltering: Boolean? = null private var sUsePeopleFiltering: Boolean? = null /** /** Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */ * Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */ @SysUISingleton @SysUISingleton class NotificationSectionsFeatureManager @Inject constructor( class NotificationSectionsFeatureManager val proxy: DeviceConfigProxy, @Inject val context: Context constructor(val proxy: DeviceConfigProxy, val context: Context) { ) { fun isFilteringEnabled(): Boolean { fun isFilteringEnabled(): Boolean { return usePeopleFiltering(proxy) return usePeopleFiltering(proxy) Loading @@ -55,30 +51,37 @@ class NotificationSectionsFeatureManager @Inject constructor( } } fun getNotificationBuckets(): IntArray { fun getNotificationBuckets(): IntArray { if (PriorityPeopleSection.isEnabled) { if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled) { // We don't need this list to be adaptive, it can be the superset of all features. // We don't need this list to be adaptive, it can be the superset of all features. return intArrayOf( return PriorityBucket.getAllInOrder() BUCKET_MEDIA_CONTROLS, } return when { isFilteringEnabled() && isMediaControlsEnabled() -> intArrayOf( BUCKET_HEADS_UP, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_FOREGROUND_SERVICE, BUCKET_PRIORITY_PEOPLE, BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_ALERTING, BUCKET_SILENT, BUCKET_SILENT ) ) } return when { isFilteringEnabled() && isMediaControlsEnabled() -> intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT) !isFilteringEnabled() && isMediaControlsEnabled() -> !isFilteringEnabled() && isMediaControlsEnabled() -> intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, intArrayOf( BUCKET_ALERTING, BUCKET_SILENT) BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, BUCKET_ALERTING, BUCKET_SILENT ) isFilteringEnabled() && !isMediaControlsEnabled() -> isFilteringEnabled() && !isMediaControlsEnabled() -> intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_PEOPLE, intArrayOf( BUCKET_ALERTING, BUCKET_SILENT) BUCKET_HEADS_UP, else -> BUCKET_FOREGROUND_SERVICE, intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT ) else -> intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) } } } } Loading @@ -94,8 +97,12 @@ class NotificationSectionsFeatureManager @Inject constructor( private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean { private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean { if (sUsePeopleFiltering == null) { if (sUsePeopleFiltering == null) { sUsePeopleFiltering = proxy.getBoolean( sUsePeopleFiltering = DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, true) proxy.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, true ) } } return sUsePeopleFiltering!! return sUsePeopleFiltering!! Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java +18 −13 Original line number Original line Diff line number Diff line Loading @@ -60,22 +60,27 @@ public class ColorizedFgsCoordinator implements Coordinator { public boolean isInSection(ListEntry entry) { public boolean isInSection(ListEntry entry) { NotificationEntry notificationEntry = entry.getRepresentativeEntry(); NotificationEntry notificationEntry = entry.getRepresentativeEntry(); if (notificationEntry != null) { if (notificationEntry != null) { return isColorizedForegroundService(notificationEntry) || isCall(notificationEntry); return isRichOngoing(notificationEntry); } } return false; return false; } } }; /** Determines if the given notification is a colorized or call notification */ public static boolean isRichOngoing(NotificationEntry entry) { return isColorizedForegroundService(entry) || isCall(entry); } private boolean isColorizedForegroundService(NotificationEntry entry) { private static boolean isColorizedForegroundService(NotificationEntry entry) { Notification notification = entry.getSbn().getNotification(); Notification notification = entry.getSbn().getNotification(); return notification.isForegroundService() return notification.isForegroundService() && notification.isColorized() && notification.isColorized() && entry.getImportance() > IMPORTANCE_MIN; && entry.getImportance() > IMPORTANCE_MIN; } } private boolean isCall(NotificationEntry entry) { private static boolean isCall(NotificationEntry entry) { Notification notification = entry.getSbn().getNotification(); Notification notification = entry.getSbn().getNotification(); return entry.getImportance() > IMPORTANCE_MIN return entry.getImportance() > IMPORTANCE_MIN && notification.isStyle(Notification.CallStyle.class); && notification.isStyle(Notification.CallStyle.class); } } }; } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +39 −18 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator package com.android.systemui.statusbar.notification.collection.coordinator import android.app.NotificationManager import android.os.UserHandle import android.os.UserHandle import android.provider.Settings import android.provider.Settings import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting Loading @@ -44,7 +45,8 @@ import com.android.systemui.statusbar.notification.collection.provider.SectionHe import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_ONGOING import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_UNSEEN import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.asIndenting import com.android.systemui.util.asIndenting Loading Loading @@ -113,7 +115,7 @@ constructor( private fun attachUnseenFilter(pipeline: NotifPipeline) { private fun attachUnseenFilter(pipeline: NotifPipeline) { if (NotificationMinimalismPrototype.V2.isEnabled) { if (NotificationMinimalismPrototype.V2.isEnabled) { pipeline.addPromoter(unseenNotifPromoter) pipeline.addPromoter(unseenNotifPromoter) pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotif) pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotifs) } } pipeline.addFinalizeFilter(unseenNotifFilter) pipeline.addFinalizeFilter(unseenNotifFilter) pipeline.addCollectionListener(collectionListener) pipeline.addCollectionListener(collectionListener) Loading Loading @@ -347,15 +349,16 @@ constructor( } } } } private fun pickOutTopUnseenNotif(list: List<ListEntry>) { private fun pickOutTopUnseenNotifs(list: List<ListEntry>) { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return // Only ever elevate a top unseen notification on keyguard, not even locked shade // Only ever elevate a top unseen notification on keyguard, not even locked shade if (statusBarStateController.state != StatusBarState.KEYGUARD) { if (statusBarStateController.state != StatusBarState.KEYGUARD) { seenNotificationsInteractor.setTopOngoingNotification(null) seenNotificationsInteractor.setTopUnseenNotification(null) seenNotificationsInteractor.setTopUnseenNotification(null) return return } } // On keyguard pick the top-ranked unseen or ongoing notification to elevate // On keyguard pick the top-ranked unseen or ongoing notification to elevate seenNotificationsInteractor.setTopUnseenNotification( val nonSummaryEntries: Sequence<NotificationEntry> = list list .asSequence() .asSequence() .flatMap { .flatMap { Loading @@ -365,7 +368,15 @@ constructor( else -> error("unhandled type of $it") else -> error("unhandled type of $it") } } } } .filter { shouldIgnoreUnseenCheck(it) || it in unseenNotifications } .filter { it.importance >= NotificationManager.IMPORTANCE_DEFAULT } seenNotificationsInteractor.setTopOngoingNotification( nonSummaryEntries .filter { ColorizedFgsCoordinator.isRichOngoing(it) } .minByOrNull { it.ranking.rank } ) seenNotificationsInteractor.setTopUnseenNotification( nonSummaryEntries .filter { !ColorizedFgsCoordinator.isRichOngoing(it) && it in unseenNotifications } .minByOrNull { it.ranking.rank } .minByOrNull { it.ranking.rank } ) ) } } Loading @@ -375,29 +386,39 @@ constructor( object : NotifPromoter("$TAG-unseen") { object : NotifPromoter("$TAG-unseen") { override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean = override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean = if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false else if (!NotificationMinimalismPrototype.V2.ungroupTopUnseen) false else else seenNotificationsInteractor.isTopUnseenNotification(child) && seenNotificationsInteractor.isTopOngoingNotification(child) || NotificationMinimalismPrototype.V2.ungroupTopUnseen seenNotificationsInteractor.isTopUnseenNotification(child) } } val unseenNotifSectioner = val topOngoingSectioner = object : NotifSectioner("Unseen", BUCKET_FOREGROUND_SERVICE) { object : NotifSectioner("TopOngoing", BUCKET_TOP_ONGOING) { override fun isInSection(entry: ListEntry): Boolean { override fun isInSection(entry: ListEntry): Boolean { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false if ( return entry.anyEntry { notificationEntry -> seenNotificationsInteractor.isTopUnseenNotification(entry.representativeEntry) seenNotificationsInteractor.isTopOngoingNotification(notificationEntry) ) { return true } } if (entry !is GroupEntry) { return false } } return entry.children.any { } seenNotificationsInteractor.isTopUnseenNotification(it) val topUnseenSectioner = object : NotifSectioner("TopUnseen", BUCKET_TOP_UNSEEN) { override fun isInSection(entry: ListEntry): Boolean { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false return entry.anyEntry { notificationEntry -> seenNotificationsInteractor.isTopUnseenNotification(notificationEntry) } } } } } } private fun ListEntry.anyEntry(predicate: (NotificationEntry?) -> Boolean) = when { predicate(representativeEntry) -> true this !is GroupEntry -> false else -> children.any(predicate) } @VisibleForTesting @VisibleForTesting internal val unseenNotifFilter = internal val unseenNotifFilter = object : NotifFilter("$TAG-unseen") { object : NotifFilter("$TAG-unseen") { Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +5 −2 Original line number Original line Diff line number Diff line Loading @@ -116,11 +116,14 @@ constructor( } } // Manually add Ordered Sections // Manually add Ordered Sections if (NotificationMinimalismPrototype.V2.isEnabled) { mOrderedSections.add(keyguardCoordinator.topOngoingSectioner) // Top Ongoing } mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService if (NotificationMinimalismPrototype.V2.isEnabled) { if (NotificationMinimalismPrototype.V2.isEnabled) { mOrderedSections.add(keyguardCoordinator.unseenNotifSectioner) // Unseen (FGS) mOrderedSections.add(keyguardCoordinator.topUnseenSectioner) // Top Unseen } } mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService if (PriorityPeopleSection.isEnabled) { if (PriorityPeopleSection.isEnabled) { mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,9 @@ class ActiveNotificationListRepository @Inject constructor() { /** Stats about the list of notifications attached to the shade */ /** Stats about the list of notifications attached to the shade */ val notifStats = MutableStateFlow(NotifStats.empty) val notifStats = MutableStateFlow(NotifStats.empty) /** The key of the top ongoing notification */ val topOngoingNotificationKey = MutableStateFlow<String?>(null) /** The key of the top unseen notification */ /** The key of the top unseen notification */ val topUnseenNotificationKey = MutableStateFlow<String?>(null) val topUnseenNotificationKey = MutableStateFlow<String?>(null) } } Loading Loading @@ -75,6 +78,7 @@ data class ActiveNotificationsStore( /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ sealed class Key { sealed class Key { data class Individual(val key: String) : Key() data class Individual(val key: String) : Key() data class Group(val key: String) : Key() data class Group(val key: String) : Key() } } Loading