blob: 4c0092144da921f4a9ddd5d2ebda75728da706af [file] [log] [blame]
Chris Wrenf9536642014-04-17 10:01:54 -04001/*
2 * Copyright (C) 2014 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 */
16package com.android.server.notification;
17
Julia Reynolds4a02afb2016-12-13 13:39:52 -050018import android.app.Notification;
19import android.app.NotificationManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
Julia Reynolds4a02afb2016-12-13 13:39:52 -050024import android.telecom.TelecomManager;
Julia Reynolds4a02afb2016-12-13 13:39:52 -050025
Selim Cinek7d1009b2017-01-25 15:28:28 -080026import com.android.internal.util.NotificationMessagingUtil;
27
Chris Wrenf9536642014-04-17 10:01:54 -040028import java.util.Comparator;
Julia Reynolds4a02afb2016-12-13 13:39:52 -050029import java.util.Objects;
Chris Wrenf9536642014-04-17 10:01:54 -040030
31/**
Julia Reynolds0421e6d2016-01-08 09:51:24 -050032 * Sorts notifications individually into attention-relevant order.
Chris Wrenf9536642014-04-17 10:01:54 -040033 */
34public class NotificationComparator
Chris Wren333a61c2014-05-28 16:40:57 -040035 implements Comparator<NotificationRecord> {
Chris Wrenf9536642014-04-17 10:01:54 -040036
Julia Reynolds4a02afb2016-12-13 13:39:52 -050037 private final Context mContext;
Selim Cinek7d1009b2017-01-25 15:28:28 -080038 private final NotificationMessagingUtil mMessagingUtil;
Julia Reynolds4a02afb2016-12-13 13:39:52 -050039 private String mDefaultPhoneApp;
Julia Reynolds4a02afb2016-12-13 13:39:52 -050040
41 public NotificationComparator(Context context) {
42 mContext = context;
43 mContext.registerReceiver(mPhoneAppBroadcastReceiver,
44 new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED));
Selim Cinek7d1009b2017-01-25 15:28:28 -080045 mMessagingUtil = new NotificationMessagingUtil(mContext);
Julia Reynolds4a02afb2016-12-13 13:39:52 -050046 }
47
Chris Wrenf9536642014-04-17 10:01:54 -040048 @Override
Chris Wren1031c972014-07-23 13:11:45 +000049 public int compare(NotificationRecord left, NotificationRecord right) {
Selim Cinek7b9605b2017-01-19 17:36:00 -080050 // first all colorized notifications
Selim Cinekc6c639cb2017-05-05 19:49:22 -070051 boolean leftImportantColorized = isImportantColorized(left);
52 boolean rightImportantColorized = isImportantColorized(right);
Selim Cinek7b9605b2017-01-19 17:36:00 -080053
54 if (leftImportantColorized != rightImportantColorized) {
55 return -1 * Boolean.compare(leftImportantColorized, rightImportantColorized);
56 }
57
58 // sufficiently important ongoing notifications of certain categories
Julia Reynolds4a02afb2016-12-13 13:39:52 -050059 boolean leftImportantOngoing = isImportantOngoing(left);
60 boolean rightImportantOngoing = isImportantOngoing(right);
61
62 if (leftImportantOngoing != rightImportantOngoing) {
63 // by ongoing, ongoing higher than non-ongoing
64 return -1 * Boolean.compare(leftImportantOngoing, rightImportantOngoing);
65 }
66
Selim Cinek7d1009b2017-01-25 15:28:28 -080067 boolean leftMessaging = isImportantMessaging(left);
68 boolean rightMessaging = isImportantMessaging(right);
69 if (leftMessaging != rightMessaging) {
70 return -1 * Boolean.compare(leftMessaging, rightMessaging);
71 }
72
Julia Reynolds4a02afb2016-12-13 13:39:52 -050073 // Next: sufficiently import person to person communication
Selim Cinek7d1009b2017-01-25 15:28:28 -080074 boolean leftPeople = isImportantPeople(left);
75 boolean rightPeople = isImportantPeople(right);
Julia Reynolds24450372017-05-02 15:04:34 -040076 final int contactAffinityComparison =
77 Float.compare(left.getContactAffinity(), right.getContactAffinity());
Julia Reynolds4a02afb2016-12-13 13:39:52 -050078
79 if (leftPeople && rightPeople){
80 // by contact proximity, close to far. if same proximity, check further fields.
Julia Reynolds24450372017-05-02 15:04:34 -040081 if (contactAffinityComparison != 0) {
82 return -1 * contactAffinityComparison;
Julia Reynolds4a02afb2016-12-13 13:39:52 -050083 }
84 } else if (leftPeople != rightPeople) {
85 // People, messaging higher than non-messaging
86 return -1 * Boolean.compare(leftPeople, rightPeople);
87 }
88
Chris Wrenbdf33762015-12-04 15:50:51 -050089 final int leftImportance = left.getImportance();
90 final int rightImportance = right.getImportance();
91 if (leftImportance != rightImportance) {
Julia Reynoldsdbc114f2016-03-03 11:22:12 -050092 // by importance, high to low
Chris Wrenbdf33762015-12-04 15:50:51 -050093 return -1 * Integer.compare(leftImportance, rightImportance);
Chris Wrenf9536642014-04-17 10:01:54 -040094 }
Chris Wren1031c972014-07-23 13:11:45 +000095
Julia Reynolds24450372017-05-02 15:04:34 -040096 // by contact proximity, close to far. if same proximity, check further fields.
97 if (contactAffinityComparison != 0) {
98 return -1 * contactAffinityComparison;
99 }
100
Julia Reynoldsdbc114f2016-03-03 11:22:12 -0500101 // Whether or not the notification can bypass DND.
Julia Reynolds0421e6d2016-01-08 09:51:24 -0500102 final int leftPackagePriority = left.getPackagePriority();
103 final int rightPackagePriority = right.getPackagePriority();
104 if (leftPackagePriority != rightPackagePriority) {
105 // by priority, high to low
106 return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
107 }
108
Julia Reynoldsdbc114f2016-03-03 11:22:12 -0500109 final int leftPriority = left.sbn.getNotification().priority;
110 final int rightPriority = right.sbn.getNotification().priority;
111 if (leftPriority != rightPriority) {
112 // by priority, high to low
113 return -1 * Integer.compare(leftPriority, rightPriority);
114 }
115
Chris Wrenf9536642014-04-17 10:01:54 -0400116 // then break ties by time, most recent first
Chris Wren1031c972014-07-23 13:11:45 +0000117 return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs());
Chris Wrenf9536642014-04-17 10:01:54 -0400118 }
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500119
Selim Cinekc6c639cb2017-05-05 19:49:22 -0700120 private boolean isImportantColorized(NotificationRecord record) {
Selim Cinek7b9605b2017-01-19 17:36:00 -0800121 if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
122 return false;
123 }
124 return record.getNotification().isColorized();
125 }
126
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500127 private boolean isImportantOngoing(NotificationRecord record) {
128 if (!isOngoing(record)) {
129 return false;
130 }
131
132 if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
133 return false;
134 }
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500135
136 return isCall(record) || isMediaNotification(record);
137 }
138
Selim Cinek7d1009b2017-01-25 15:28:28 -0800139 protected boolean isImportantPeople(NotificationRecord record) {
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500140 if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
141 return false;
142 }
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500143 if (record.getContactAffinity() > ValidateNotificationPeople.NONE) {
144 return true;
145 }
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500146 return false;
147 }
148
Selim Cinek7d1009b2017-01-25 15:28:28 -0800149 protected boolean isImportantMessaging(NotificationRecord record) {
150 return mMessagingUtil.isImportantMessaging(record.sbn, record.getImportance());
151 }
152
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500153 private boolean isOngoing(NotificationRecord record) {
Julia Reynolds889280c2017-04-12 12:27:00 -0400154 final int ongoingFlags = Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500155 return (record.getNotification().flags & ongoingFlags) != 0;
156 }
157
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500158 private boolean isMediaNotification(NotificationRecord record) {
Selim Cinek99104832017-01-25 14:47:33 -0800159 return record.getNotification().hasMediaSession();
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500160 }
161
162 private boolean isCall(NotificationRecord record) {
163 return record.getNotification().category == Notification.CATEGORY_CALL
164 && isDefaultPhoneApp(record.sbn.getPackageName());
165 }
166
167 private boolean isDefaultPhoneApp(String pkg) {
168 if (mDefaultPhoneApp == null) {
169 final TelecomManager telecomm =
170 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
171 mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultDialerPackage() : null;
172 }
173 return Objects.equals(pkg, mDefaultPhoneApp);
174 }
175
Julia Reynolds4a02afb2016-12-13 13:39:52 -0500176 private final BroadcastReceiver mPhoneAppBroadcastReceiver = new BroadcastReceiver() {
177 @Override
178 public void onReceive(Context context, Intent intent) {
179 mDefaultPhoneApp =
180 intent.getStringExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
181 }
182 };
Chris Wrenf9536642014-04-17 10:01:54 -0400183}