Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e75b1f5 authored by Steve Elliott's avatar Steve Elliott Committed by Android (Google) Code Review
Browse files

Merge "Treat groups of conversations as a conversation" into rvc-dev

parents 47af8f93 307d3854
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -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
@@ -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)
@@ -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
@@ -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)
+2 −2
Original line number Diff line number Diff line
@@ -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) {
+3 −3
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.statusbar.notification.people

import android.app.PendingIntent
import android.graphics.drawable.Drawable

/**
@@ -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. */
+54 −35
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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)
@@ -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,
@@ -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)
@@ -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) }
@@ -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(
@@ -303,4 +323,3 @@ fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
                            ?.drawable
                }
                ?.firstOrNull()
+81 −8
Original line number Diff line number Diff line
@@ -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