Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt +13 −10 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ import com.android.systemui.statusbar.notification.NotificationFilter import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE Loading Loading @@ -72,11 +75,14 @@ open class NotificationRankingManager @Inject constructor( val aRank = a.ranking.rank val bRank = b.ranking.rank val aIsPeople = a.isPeopleNotification() val bIsPeople = b.isPeopleNotification() val aPersonType = a.getPeopleNotificationType() val bPersonType = b.getPeopleNotificationType() val aIsImportantPeople = a.isImportantPeopleNotification() val bIsImportantPeople = b.isImportantPeopleNotification() val aIsPeople = aPersonType == TYPE_PERSON val bIsPeople = bPersonType == TYPE_PERSON val aIsImportantPeople = aPersonType == TYPE_IMPORTANT_PERSON val bIsImportantPeople = bPersonType == TYPE_IMPORTANT_PERSON val aMedia = isImportantMedia(a) val bMedia = isImportantMedia(b) Loading Loading @@ -165,7 +171,7 @@ open class NotificationRankingManager @Inject constructor( ) { if (usePeopleFiltering && isHeadsUp) { entry.bucket = BUCKET_HEADS_UP } else if (usePeopleFiltering && entry.isPeopleNotification()) { } else if (usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON) { entry.bucket = BUCKET_PEOPLE } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) { entry.bucket = BUCKET_ALERTING Loading Loading @@ -198,11 +204,8 @@ open class NotificationRankingManager @Inject constructor( } } private fun NotificationEntry.isPeopleNotification() = peopleNotificationIdentifier.isPeopleNotification(sbn, ranking) private fun NotificationEntry.isImportantPeopleNotification() = peopleNotificationIdentifier.isImportantPeopleNotification(sbn, ranking) private fun NotificationEntry.getPeopleNotificationType() = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) private fun NotificationEntry.isHighPriority() = highPriorityProvider.isHighPriority(this) Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +2 −2 Original line number Diff line number Diff line Loading @@ -103,8 +103,8 @@ public class HighPriorityProvider { } private boolean isPeopleNotification(NotificationEntry entry) { return mPeopleNotificationIdentifier.isPeopleNotification( entry.getSbn(), entry.getRanking()); return mPeopleNotificationIdentifier.getPeopleNotificationType( entry.getSbn(), entry.getRanking()) != PeopleNotificationIdentifier.TYPE_NON_PERSON; } private boolean hasUserSetImportance(NotificationEntry entry) { Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt +3 −3 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.people import android.app.PendingIntent import android.graphics.drawable.Drawable /** Loading Loading @@ -45,10 +44,11 @@ data class PeopleHubModel(val people: Collection<PersonModel>) /** `Model` for a single "Person" in PeopleHub. */ data class PersonModel( val key: PersonKey, val userId: Int, // TODO: these should live in the ViewModel val name: CharSequence, val avatar: Drawable, val clickRunnable: Runnable, val userId: Int val clickRunnable: Runnable ) /** Unique identifier for a Person in PeopleHub. */ Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt +54 −35 Original line number Diff line number Diff line Loading @@ -20,9 +20,7 @@ import android.app.Notification import android.content.Context import android.content.pm.LauncherApps import android.content.pm.PackageManager import android.content.pm.ShortcutInfo import android.content.pm.UserInfo import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.os.UserManager import android.service.notification.NotificationListenerService Loading @@ -45,6 +43,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.notification.NotificationEntryListener import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.policy.ExtensionController import java.util.ArrayDeque import java.util.concurrent.Executor Loading Loading @@ -79,7 +78,7 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor( override fun extractPerson(sbn: StatusBarNotification) = plugin?.extractPerson(sbn)?.run { PersonModel(key, name, avatar, clickRunnable, sbn.user.identifier) PersonModel(key, sbn.user.identifier, name, avatar, clickRunnable) } override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn) Loading @@ -93,9 +92,9 @@ class PeopleHubDataSourceImpl @Inject constructor( private val notificationEntryManager: NotificationEntryManager, private val extractor: NotificationPersonExtractor, private val userManager: UserManager, private val launcherApps: LauncherApps, private val packageManager: PackageManager, private val c: Context, launcherApps: LauncherApps, packageManager: PackageManager, context: Context, private val notificationListener: NotificationListener, @Background private val bgExecutor: Executor, @Main private val mainExecutor: Executor, Loading @@ -106,10 +105,19 @@ class PeopleHubDataSourceImpl @Inject constructor( private var userChangeSubscription: Subscription? = null private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>() private val peopleHubManagerForUser = SparseArray<PeopleHubManager>() val context: Context = c.applicationContext val iconFactory = ConversationIconFactory(context, launcherApps, packageManager, IconDrawableFactory.newInstance(context), context.resources.getDimensionPixelSize( R.dimen.notification_guts_conversation_icon_size)) private val iconFactory = run { val appContext = context.applicationContext ConversationIconFactory( appContext, launcherApps, packageManager, IconDrawableFactory.newInstance(appContext), appContext.resources.getDimensionPixelSize( R.dimen.notification_guts_conversation_icon_size ) ) } private val notificationEntryListener = object : NotificationEntryListener { override fun onEntryInflated(entry: NotificationEntry) = addVisibleEntry(entry) Loading Loading @@ -206,7 +214,8 @@ class PeopleHubDataSourceImpl @Inject constructor( } private fun NotificationEntry.extractPerson(): PersonModel? { if (!peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) { val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) if (type == TYPE_NON_PERSON) { return null } val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) } Loading @@ -215,23 +224,34 @@ class PeopleHubDataSourceImpl @Inject constructor( ?: extras.getString(Notification.EXTRA_CONVERSATION_TITLE) ?: extras.getString(Notification.EXTRA_TITLE) ?: return null val drawable = ranking.shortcutInfo?.getIcon(iconFactory, sbn, ranking) ?: iconFactory.getConversationDrawable(extractAvatarFromRow(this), sbn.packageName, sbn.uid, ranking.channel.isImportantConversation) return PersonModel(key, name, drawable, clickRunnable, sbn.user.identifier) } private fun ShortcutInfo.getIcon(iconFactory: ConversationIconFactory, sbn: StatusBarNotification, ranking: NotificationListenerService.Ranking): Drawable? { return iconFactory.getConversationDrawable(ranking.shortcutInfo, sbn.packageName, sbn.uid, ranking.channel.isImportantConversation) } private fun NotificationEntry.extractPersonKey(): PersonKey? = val drawable = ranking.getIcon(iconFactory, sbn) ?: iconFactory.getConversationDrawable( extractAvatarFromRow(this), sbn.packageName, sbn.uid, ranking.channel.isImportantConversation ) return PersonModel(key, sbn.user.identifier, name, drawable, clickRunnable) } private fun NotificationListenerService.Ranking.getIcon( iconFactory: ConversationIconFactory, sbn: StatusBarNotification ): Drawable? = shortcutInfo?.let { shortcutInfo -> iconFactory.getConversationDrawable( shortcutInfo, sbn.packageName, sbn.uid, channel.isImportantConversation ) } private fun NotificationEntry.extractPersonKey(): PersonKey? { // TODO migrate to shortcut id when snoozing is conversation wide if (peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) key else null val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) return if (type != TYPE_NON_PERSON) key else null } } private fun NotificationLockscreenUserManager.registerListener( Loading Loading @@ -303,4 +323,3 @@ fun extractAvatarFromRow(entry: NotificationEntry): Drawable? = ?.drawable } ?.firstOrNull() packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +81 −8 Original line number Diff line number Diff line Loading @@ -16,24 +16,97 @@ package com.android.systemui.statusbar.notification.people import android.annotation.IntDef import android.service.notification.NotificationListenerService.Ranking import android.service.notification.StatusBarNotification import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON import com.android.systemui.statusbar.phone.NotificationGroupManager import javax.inject.Inject import javax.inject.Singleton import kotlin.math.max interface PeopleNotificationIdentifier { fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean /** * Identifies if the given notification can be classified as a "People" notification. * * @return [TYPE_NON_PERSON] if not a people notification, [TYPE_PERSON] if a standard people * notification, and [TYPE_IMPORTANT_PERSON] if an "important" people notification. */ @PeopleNotificationType fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int companion object { @Retention(AnnotationRetention.SOURCE) @IntDef(prefix = ["TYPE_"], value = [TYPE_NON_PERSON, TYPE_PERSON, TYPE_IMPORTANT_PERSON]) annotation class PeopleNotificationType const val TYPE_NON_PERSON = 0 const val TYPE_PERSON = 1 const val TYPE_IMPORTANT_PERSON = 2 } } @Singleton class PeopleNotificationIdentifierImpl @Inject constructor( private val personExtractor: NotificationPersonExtractor private val personExtractor: NotificationPersonExtractor, private val groupManager: NotificationGroupManager ) : PeopleNotificationIdentifier { override fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) = ranking.isConversation || personExtractor.isPersonNotification(sbn) @PeopleNotificationType override fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int = when (val type = ranking.personTypeInfo) { TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON else -> { when (val type = upperBound(type, extractPersonTypeInfo(sbn))) { TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON else -> upperBound(type, getPeopleTypeOfSummary(sbn)) } } } /** * Given two [PeopleNotificationType]s, determine the upper bound. Used to constrain a * notification to a type given multiple signals, i.e. notification groups, where each child * has a [PeopleNotificationType] that is used to constrain the summary. */ @PeopleNotificationType private fun upperBound( @PeopleNotificationType type: Int, @PeopleNotificationType other: Int ): Int = max(type, other) private val Ranking.personTypeInfo get() = when { channel.isImportantConversation -> TYPE_IMPORTANT_PERSON isConversation -> TYPE_PERSON else -> TYPE_NON_PERSON } private fun extractPersonTypeInfo(sbn: StatusBarNotification) = if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON override fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) = isPeopleNotification(sbn, ranking) && ranking.channel.isImportantConversation private fun getPeopleTypeOfSummary(statusBarNotification: StatusBarNotification): Int { if (!groupManager.isSummaryOfGroup(statusBarNotification)) { return TYPE_NON_PERSON } val childTypes = groupManager.getLogicalChildren(statusBarNotification) ?.asSequence() ?.map { getPeopleNotificationType(it.sbn, it.ranking) } ?: return TYPE_NON_PERSON var groupType = TYPE_NON_PERSON for (childType in childTypes) { groupType = upperBound(groupType, childType) if (groupType == TYPE_IMPORTANT_PERSON) break } return groupType } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt +13 −10 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ import com.android.systemui.statusbar.notification.NotificationFilter import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE Loading Loading @@ -72,11 +75,14 @@ open class NotificationRankingManager @Inject constructor( val aRank = a.ranking.rank val bRank = b.ranking.rank val aIsPeople = a.isPeopleNotification() val bIsPeople = b.isPeopleNotification() val aPersonType = a.getPeopleNotificationType() val bPersonType = b.getPeopleNotificationType() val aIsImportantPeople = a.isImportantPeopleNotification() val bIsImportantPeople = b.isImportantPeopleNotification() val aIsPeople = aPersonType == TYPE_PERSON val bIsPeople = bPersonType == TYPE_PERSON val aIsImportantPeople = aPersonType == TYPE_IMPORTANT_PERSON val bIsImportantPeople = bPersonType == TYPE_IMPORTANT_PERSON val aMedia = isImportantMedia(a) val bMedia = isImportantMedia(b) Loading Loading @@ -165,7 +171,7 @@ open class NotificationRankingManager @Inject constructor( ) { if (usePeopleFiltering && isHeadsUp) { entry.bucket = BUCKET_HEADS_UP } else if (usePeopleFiltering && entry.isPeopleNotification()) { } else if (usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON) { entry.bucket = BUCKET_PEOPLE } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) { entry.bucket = BUCKET_ALERTING Loading Loading @@ -198,11 +204,8 @@ open class NotificationRankingManager @Inject constructor( } } private fun NotificationEntry.isPeopleNotification() = peopleNotificationIdentifier.isPeopleNotification(sbn, ranking) private fun NotificationEntry.isImportantPeopleNotification() = peopleNotificationIdentifier.isImportantPeopleNotification(sbn, ranking) private fun NotificationEntry.getPeopleNotificationType() = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) private fun NotificationEntry.isHighPriority() = highPriorityProvider.isHighPriority(this) Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +2 −2 Original line number Diff line number Diff line Loading @@ -103,8 +103,8 @@ public class HighPriorityProvider { } private boolean isPeopleNotification(NotificationEntry entry) { return mPeopleNotificationIdentifier.isPeopleNotification( entry.getSbn(), entry.getRanking()); return mPeopleNotificationIdentifier.getPeopleNotificationType( entry.getSbn(), entry.getRanking()) != PeopleNotificationIdentifier.TYPE_NON_PERSON; } private boolean hasUserSetImportance(NotificationEntry entry) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt +3 −3 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.people import android.app.PendingIntent import android.graphics.drawable.Drawable /** Loading Loading @@ -45,10 +44,11 @@ data class PeopleHubModel(val people: Collection<PersonModel>) /** `Model` for a single "Person" in PeopleHub. */ data class PersonModel( val key: PersonKey, val userId: Int, // TODO: these should live in the ViewModel val name: CharSequence, val avatar: Drawable, val clickRunnable: Runnable, val userId: Int val clickRunnable: Runnable ) /** Unique identifier for a Person in PeopleHub. */ Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt +54 −35 Original line number Diff line number Diff line Loading @@ -20,9 +20,7 @@ import android.app.Notification import android.content.Context import android.content.pm.LauncherApps import android.content.pm.PackageManager import android.content.pm.ShortcutInfo import android.content.pm.UserInfo import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.os.UserManager import android.service.notification.NotificationListenerService Loading @@ -45,6 +43,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.notification.NotificationEntryListener import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.policy.ExtensionController import java.util.ArrayDeque import java.util.concurrent.Executor Loading Loading @@ -79,7 +78,7 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor( override fun extractPerson(sbn: StatusBarNotification) = plugin?.extractPerson(sbn)?.run { PersonModel(key, name, avatar, clickRunnable, sbn.user.identifier) PersonModel(key, sbn.user.identifier, name, avatar, clickRunnable) } override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn) Loading @@ -93,9 +92,9 @@ class PeopleHubDataSourceImpl @Inject constructor( private val notificationEntryManager: NotificationEntryManager, private val extractor: NotificationPersonExtractor, private val userManager: UserManager, private val launcherApps: LauncherApps, private val packageManager: PackageManager, private val c: Context, launcherApps: LauncherApps, packageManager: PackageManager, context: Context, private val notificationListener: NotificationListener, @Background private val bgExecutor: Executor, @Main private val mainExecutor: Executor, Loading @@ -106,10 +105,19 @@ class PeopleHubDataSourceImpl @Inject constructor( private var userChangeSubscription: Subscription? = null private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>() private val peopleHubManagerForUser = SparseArray<PeopleHubManager>() val context: Context = c.applicationContext val iconFactory = ConversationIconFactory(context, launcherApps, packageManager, IconDrawableFactory.newInstance(context), context.resources.getDimensionPixelSize( R.dimen.notification_guts_conversation_icon_size)) private val iconFactory = run { val appContext = context.applicationContext ConversationIconFactory( appContext, launcherApps, packageManager, IconDrawableFactory.newInstance(appContext), appContext.resources.getDimensionPixelSize( R.dimen.notification_guts_conversation_icon_size ) ) } private val notificationEntryListener = object : NotificationEntryListener { override fun onEntryInflated(entry: NotificationEntry) = addVisibleEntry(entry) Loading Loading @@ -206,7 +214,8 @@ class PeopleHubDataSourceImpl @Inject constructor( } private fun NotificationEntry.extractPerson(): PersonModel? { if (!peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) { val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) if (type == TYPE_NON_PERSON) { return null } val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) } Loading @@ -215,23 +224,34 @@ class PeopleHubDataSourceImpl @Inject constructor( ?: extras.getString(Notification.EXTRA_CONVERSATION_TITLE) ?: extras.getString(Notification.EXTRA_TITLE) ?: return null val drawable = ranking.shortcutInfo?.getIcon(iconFactory, sbn, ranking) ?: iconFactory.getConversationDrawable(extractAvatarFromRow(this), sbn.packageName, sbn.uid, ranking.channel.isImportantConversation) return PersonModel(key, name, drawable, clickRunnable, sbn.user.identifier) } private fun ShortcutInfo.getIcon(iconFactory: ConversationIconFactory, sbn: StatusBarNotification, ranking: NotificationListenerService.Ranking): Drawable? { return iconFactory.getConversationDrawable(ranking.shortcutInfo, sbn.packageName, sbn.uid, ranking.channel.isImportantConversation) } private fun NotificationEntry.extractPersonKey(): PersonKey? = val drawable = ranking.getIcon(iconFactory, sbn) ?: iconFactory.getConversationDrawable( extractAvatarFromRow(this), sbn.packageName, sbn.uid, ranking.channel.isImportantConversation ) return PersonModel(key, sbn.user.identifier, name, drawable, clickRunnable) } private fun NotificationListenerService.Ranking.getIcon( iconFactory: ConversationIconFactory, sbn: StatusBarNotification ): Drawable? = shortcutInfo?.let { shortcutInfo -> iconFactory.getConversationDrawable( shortcutInfo, sbn.packageName, sbn.uid, channel.isImportantConversation ) } private fun NotificationEntry.extractPersonKey(): PersonKey? { // TODO migrate to shortcut id when snoozing is conversation wide if (peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) key else null val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) return if (type != TYPE_NON_PERSON) key else null } } private fun NotificationLockscreenUserManager.registerListener( Loading Loading @@ -303,4 +323,3 @@ fun extractAvatarFromRow(entry: NotificationEntry): Drawable? = ?.drawable } ?.firstOrNull()
packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +81 −8 Original line number Diff line number Diff line Loading @@ -16,24 +16,97 @@ package com.android.systemui.statusbar.notification.people import android.annotation.IntDef import android.service.notification.NotificationListenerService.Ranking import android.service.notification.StatusBarNotification import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON import com.android.systemui.statusbar.phone.NotificationGroupManager import javax.inject.Inject import javax.inject.Singleton import kotlin.math.max interface PeopleNotificationIdentifier { fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean /** * Identifies if the given notification can be classified as a "People" notification. * * @return [TYPE_NON_PERSON] if not a people notification, [TYPE_PERSON] if a standard people * notification, and [TYPE_IMPORTANT_PERSON] if an "important" people notification. */ @PeopleNotificationType fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int companion object { @Retention(AnnotationRetention.SOURCE) @IntDef(prefix = ["TYPE_"], value = [TYPE_NON_PERSON, TYPE_PERSON, TYPE_IMPORTANT_PERSON]) annotation class PeopleNotificationType const val TYPE_NON_PERSON = 0 const val TYPE_PERSON = 1 const val TYPE_IMPORTANT_PERSON = 2 } } @Singleton class PeopleNotificationIdentifierImpl @Inject constructor( private val personExtractor: NotificationPersonExtractor private val personExtractor: NotificationPersonExtractor, private val groupManager: NotificationGroupManager ) : PeopleNotificationIdentifier { override fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) = ranking.isConversation || personExtractor.isPersonNotification(sbn) @PeopleNotificationType override fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int = when (val type = ranking.personTypeInfo) { TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON else -> { when (val type = upperBound(type, extractPersonTypeInfo(sbn))) { TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON else -> upperBound(type, getPeopleTypeOfSummary(sbn)) } } } /** * Given two [PeopleNotificationType]s, determine the upper bound. Used to constrain a * notification to a type given multiple signals, i.e. notification groups, where each child * has a [PeopleNotificationType] that is used to constrain the summary. */ @PeopleNotificationType private fun upperBound( @PeopleNotificationType type: Int, @PeopleNotificationType other: Int ): Int = max(type, other) private val Ranking.personTypeInfo get() = when { channel.isImportantConversation -> TYPE_IMPORTANT_PERSON isConversation -> TYPE_PERSON else -> TYPE_NON_PERSON } private fun extractPersonTypeInfo(sbn: StatusBarNotification) = if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON override fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) = isPeopleNotification(sbn, ranking) && ranking.channel.isImportantConversation private fun getPeopleTypeOfSummary(statusBarNotification: StatusBarNotification): Int { if (!groupManager.isSummaryOfGroup(statusBarNotification)) { return TYPE_NON_PERSON } val childTypes = groupManager.getLogicalChildren(statusBarNotification) ?.asSequence() ?.map { getPeopleNotificationType(it.sbn, it.ranking) } ?: return TYPE_NON_PERSON var groupType = TYPE_NON_PERSON for (childType in childTypes) { groupType = upperBound(groupType, childType) if (groupType == TYPE_IMPORTANT_PERSON) break } return groupType } }