• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.notification.people
18 
19 import android.annotation.IntDef
20 import android.service.notification.NotificationListenerService.Ranking
21 import android.service.notification.StatusBarNotification
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.statusbar.notification.collection.NotificationEntry
24 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
25 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
26 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
27 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
28 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
29 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
30 import javax.inject.Inject
31 import kotlin.math.max
32 
33 interface PeopleNotificationIdentifier {
34 
35     /**
36      * Identifies if the given notification can be classified as a "People" notification.
37      *
38      * @return [TYPE_NON_PERSON] if not a people notification, [TYPE_PERSON] if it is a people
39      *  notification that doesn't use shortcuts, [TYPE_FULL_PERSON] if it is a person notification
40      *  that users shortcuts, and [TYPE_IMPORTANT_PERSON] if an "important" people notification
41      *  that users shortcuts.
42      */
43     @PeopleNotificationType
getPeopleNotificationTypenull44     fun getPeopleNotificationType(entry: NotificationEntry): Int
45 
46     fun compareTo(
47         @PeopleNotificationType a: Int,
48         @PeopleNotificationType b: Int
49     ): Int
50 
51     companion object {
52 
53         @Retention(AnnotationRetention.SOURCE)
54         @IntDef(prefix = ["TYPE_"], value = [TYPE_NON_PERSON, TYPE_PERSON, TYPE_FULL_PERSON,
55             TYPE_IMPORTANT_PERSON])
56         annotation class PeopleNotificationType
57 
58         const val TYPE_NON_PERSON = 0
59         const val TYPE_PERSON = 1
60         const val TYPE_FULL_PERSON = 2
61         const val TYPE_IMPORTANT_PERSON = 3
62     }
63 }
64 
65 @SysUISingleton
66 class PeopleNotificationIdentifierImpl @Inject constructor(
67     private val personExtractor: NotificationPersonExtractor,
68     private val groupManager: GroupMembershipManager
69 ) : PeopleNotificationIdentifier {
70 
71     @PeopleNotificationType
getPeopleNotificationTypenull72     override fun getPeopleNotificationType(entry: NotificationEntry): Int =
73             when (val type = entry.ranking.personTypeInfo) {
74                 TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
75                 else -> {
76                     when (val type = upperBound(type, extractPersonTypeInfo(entry.sbn))) {
77                         TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
78                         else -> upperBound(type, getPeopleTypeOfSummary(entry))
79                     }
80                 }
81             }
82 
compareTonull83     override fun compareTo(
84         @PeopleNotificationType a: Int,
85         @PeopleNotificationType b: Int
86     ): Int
87     {
88         return b.compareTo(a)
89     }
90 
91     /**
92      * Given two [PeopleNotificationType]s, determine the upper bound. Used to constrain a
93      * notification to a type given multiple signals, i.e. notification groups, where each child
94      * has a [PeopleNotificationType] that is used to constrain the summary.
95      */
96     @PeopleNotificationType
upperBoundnull97     private fun upperBound(
98         @PeopleNotificationType type: Int,
99         @PeopleNotificationType other: Int
100     ): Int =
101             max(type, other)
102 
103     private val Ranking.personTypeInfo
104         get() = when {
105             !isConversation -> TYPE_NON_PERSON
106             conversationShortcutInfo == null -> TYPE_PERSON
107             channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
108             else -> TYPE_FULL_PERSON
109         }
110 
extractPersonTypeInfonull111     private fun extractPersonTypeInfo(sbn: StatusBarNotification) =
112             if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON
113 
114     private fun getPeopleTypeOfSummary(entry: NotificationEntry): Int {
115         if (!groupManager.isGroupSummary(entry)) {
116             return TYPE_NON_PERSON
117         }
118 
119         val childTypes = groupManager.getChildren(entry)
120                 ?.asSequence()
121                 ?.map { getPeopleNotificationType(it) }
122                 ?: return TYPE_NON_PERSON
123 
124         var groupType = TYPE_NON_PERSON
125         for (childType in childTypes) {
126             groupType = upperBound(groupType, childType)
127             if (groupType == TYPE_IMPORTANT_PERSON)
128                 break
129         }
130         return groupType
131     }
132 }
133