1 /* 2 * Copyright (C) 2020 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.collection.provider; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.Notification; 22 import android.app.NotificationManager; 23 24 import com.android.systemui.dagger.SysUISingleton; 25 import com.android.systemui.statusbar.notification.collection.GroupEntry; 26 import com.android.systemui.statusbar.notification.collection.PipelineEntry; 27 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 28 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; 29 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; 30 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; 31 32 import java.util.List; 33 34 import javax.inject.Inject; 35 36 /** 37 * Determines whether a notification is considered 'high priority'. 38 * 39 * Notifications that are high priority are visible on the lock screen/status bar and in the top 40 * section in the shade. 41 */ 42 @SysUISingleton 43 public class HighPriorityProvider { 44 private final PeopleNotificationIdentifier mPeopleNotificationIdentifier; 45 private final GroupMembershipManager mGroupMembershipManager; 46 47 @Inject HighPriorityProvider( PeopleNotificationIdentifier peopleNotificationIdentifier, GroupMembershipManager groupManager)48 public HighPriorityProvider( 49 PeopleNotificationIdentifier peopleNotificationIdentifier, 50 GroupMembershipManager groupManager) { 51 mPeopleNotificationIdentifier = peopleNotificationIdentifier; 52 mGroupMembershipManager = groupManager; 53 } 54 55 /** 56 * @return true if the PipelineEntry is high priority, else false 57 * 58 * A NotificationEntry is considered high priority if it: 59 * - has importance greater than or equal to IMPORTANCE_DEFAULT 60 * OR 61 * - their importance has NOT been set to a low priority option by the user AND the 62 * notification fulfills one of the following: 63 * - has a person associated with it 64 * - has a media session associated with it 65 * - has messaging style 66 * 67 * A GroupEntry is considered high priority if its representativeEntry (summary) or any of its 68 * children are high priority. 69 */ isHighPriority(@ullable PipelineEntry entry)70 public boolean isHighPriority(@Nullable PipelineEntry entry) { 71 return isHighPriority(entry, /* allowImplicit = */ true); 72 } 73 74 /** 75 * @return true if the PipelineEntry is explicitly high priority, else false 76 * 77 * A NotificationEntry is considered explicitly high priority if has importance greater than or 78 * equal to IMPORTANCE_DEFAULT. 79 * 80 * A GroupEntry is considered explicitly high priority if its representativeEntry (summary) or 81 * any of its children are explicitly high priority. 82 */ isExplicitlyHighPriority(@ullable PipelineEntry entry)83 public boolean isExplicitlyHighPriority(@Nullable PipelineEntry entry) { 84 return isHighPriority(entry, /* allowImplicit= */ false); 85 } 86 isHighPriority(@ullable PipelineEntry entry, boolean allowImplicit)87 private boolean isHighPriority(@Nullable PipelineEntry entry, boolean allowImplicit) { 88 if (entry == null) { 89 return false; 90 } 91 92 final NotificationEntry notifEntry = entry.getRepresentativeEntry(); 93 if (notifEntry == null) { 94 return false; 95 } 96 97 return notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT 98 || (allowImplicit && hasHighPriorityCharacteristics(notifEntry)) 99 || hasHighPriorityChild(entry, allowImplicit); 100 } 101 102 /** 103 * @return true if the PipelineEntry is high priority conversation, else false 104 */ isHighPriorityConversation(@onNull PipelineEntry entry)105 public boolean isHighPriorityConversation(@NonNull PipelineEntry entry) { 106 final NotificationEntry notifEntry = entry.getRepresentativeEntry(); 107 if (notifEntry == null) { 108 return false; 109 } 110 111 if (!isPeopleNotification(notifEntry)) { 112 return false; 113 } 114 115 if (notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT) { 116 return true; 117 } 118 119 return isNotificationEntryWithAtLeastOneImportantChild(entry); 120 } 121 isNotificationEntryWithAtLeastOneImportantChild(@onNull PipelineEntry entry)122 private boolean isNotificationEntryWithAtLeastOneImportantChild(@NonNull PipelineEntry entry) { 123 if (!(entry instanceof GroupEntry)) { 124 return false; 125 } 126 final GroupEntry groupEntry = (GroupEntry) entry; 127 return groupEntry.getChildren().stream().anyMatch( 128 childEntry -> 129 childEntry.getRanking().getImportance() 130 >= NotificationManager.IMPORTANCE_DEFAULT); 131 } 132 133 /** 134 * Returns whether the given ListEntry has a high priority child or is in a group with a child 135 * that's high priority 136 */ hasHighPriorityChild(PipelineEntry entry, boolean allowImplicit)137 private boolean hasHighPriorityChild(PipelineEntry entry, boolean allowImplicit) { 138 if (NotificationBundleUi.isEnabled()) { 139 GroupEntry representativeGroupEntry = null; 140 if (entry instanceof GroupEntry) { 141 representativeGroupEntry = (GroupEntry) entry; 142 } else if (entry instanceof NotificationEntry){ 143 final NotificationEntry notificationEntry = entry.getRepresentativeEntry(); 144 if (notificationEntry.getParent() != null 145 && notificationEntry.getParent() instanceof GroupEntry parent 146 && parent.getSummary() != null 147 && parent.getSummary() == notificationEntry) { 148 representativeGroupEntry = parent; 149 } 150 } 151 return representativeGroupEntry != null && 152 representativeGroupEntry.getChildren().stream().anyMatch( 153 childEntry -> isHighPriority(childEntry, allowImplicit)); 154 155 } else { 156 if (entry instanceof NotificationEntry 157 && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) { 158 return false; 159 } 160 List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry); 161 if (children != null) { 162 for (NotificationEntry child : children) { 163 if (child != entry && isHighPriority(child, allowImplicit)) { 164 return true; 165 } 166 } 167 } 168 return false; 169 } 170 } 171 hasHighPriorityCharacteristics(NotificationEntry entry)172 private boolean hasHighPriorityCharacteristics(NotificationEntry entry) { 173 return !hasUserSetImportance(entry) 174 && (entry.getSbn().getNotification().isMediaNotification() 175 || isPeopleNotification(entry) 176 || isMessagingStyle(entry)); 177 } 178 isMessagingStyle(NotificationEntry entry)179 private boolean isMessagingStyle(NotificationEntry entry) { 180 return entry.getSbn().getNotification().isStyle(Notification.MessagingStyle.class); 181 } 182 isPeopleNotification(NotificationEntry entry)183 private boolean isPeopleNotification(NotificationEntry entry) { 184 return mPeopleNotificationIdentifier.getPeopleNotificationType(entry) 185 != PeopleNotificationIdentifier.TYPE_NON_PERSON; 186 } 187 hasUserSetImportance(NotificationEntry entry)188 private boolean hasUserSetImportance(NotificationEntry entry) { 189 return entry.getRanking().getChannel() != null 190 && entry.getRanking().getChannel().hasUserSetImportance(); 191 } 192 } 193