1 /**
2  * Copyright (C) 2018 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 package android.ext.services.notification;
17 
18 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
19 import static android.app.NotificationManager.IMPORTANCE_HIGH;
20 import static android.app.NotificationManager.IMPORTANCE_MIN;
21 
22 import android.app.Notification;
23 import android.media.AudioAttributes;
24 import android.os.Process;
25 
26 import androidx.annotation.IntDef;
27 import androidx.annotation.VisibleForTesting;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 /**
33  * Default categorizer for incoming notifications; used to determine what notifications
34  * should be silenced.
35  */
36 public class NotificationCategorizer {
37 
38     protected static final int CATEGORY_MIN = -3;
39     protected static final int CATEGORY_EVERYTHING_ELSE = -2;
40     protected static final int CATEGORY_ONGOING = -1;
41     protected static final int CATEGORY_SYSTEM_LOW = 0;
42     protected static final int CATEGORY_EVENT = 1;
43     protected static final int CATEGORY_REMINDER = 2;
44     protected static final int CATEGORY_SYSTEM = 3;
45     protected static final int CATEGORY_PEOPLE = 4;
46     protected static final int CATEGORY_ALARM = 5;
47     protected static final int CATEGORY_CALL = 6;
48     protected static final int CATEGORY_HIGH = 7;
49 
50     /** @hide */
51     @IntDef({
52             CATEGORY_MIN, CATEGORY_EVERYTHING_ELSE, CATEGORY_ONGOING, CATEGORY_CALL,
53             CATEGORY_SYSTEM_LOW, CATEGORY_EVENT, CATEGORY_REMINDER, CATEGORY_SYSTEM,
54             CATEGORY_PEOPLE, CATEGORY_ALARM, CATEGORY_HIGH
55     })
56     @Retention(RetentionPolicy.SOURCE)
57     public @interface Category {}
58 
shouldSilence(NotificationEntry entry)59     public boolean shouldSilence(NotificationEntry entry) {
60         return shouldSilence(getCategory(entry));
61     }
62 
63     @VisibleForTesting
shouldSilence(int category)64     boolean shouldSilence(int category) {
65         return category < CATEGORY_EVENT;
66     }
67 
getCategory(NotificationEntry entry)68     public int getCategory(NotificationEntry entry) {
69         if (entry.getChannel() == null) {
70             return CATEGORY_EVERYTHING_ELSE;
71         }
72         if (entry.getChannel().getImportance() == IMPORTANCE_MIN) {
73             return CATEGORY_MIN;
74         }
75         if (entry.isCategory(Notification.CATEGORY_REMINDER)) {
76             return CATEGORY_REMINDER;
77         }
78         if (entry.isCategory(Notification.CATEGORY_EVENT)) {
79             return CATEGORY_EVENT;
80         }
81         if (entry.isCategory(Notification.CATEGORY_ALARM)
82                 || entry.isAudioAttributesUsage(AudioAttributes.USAGE_ALARM)) {
83             return CATEGORY_ALARM;
84         }
85         // TODO: check for default phone app
86         if (entry.isCategory(Notification.CATEGORY_CALL)) {
87             return CATEGORY_CALL;
88         }
89         if (entry.involvesPeople()) {
90             return CATEGORY_PEOPLE;
91         }
92         // TODO: is from signature app
93         if (entry.getSbn().getUid() < Process.FIRST_APPLICATION_UID) {
94             if (entry.getImportance() >= IMPORTANCE_DEFAULT) {
95                 return CATEGORY_SYSTEM;
96             } else {
97                 return CATEGORY_SYSTEM_LOW;
98             }
99         }
100         if (entry.getChannel().getImportance() == IMPORTANCE_HIGH) {
101             return CATEGORY_HIGH;
102         }
103         if (entry.isOngoing()) {
104             return CATEGORY_ONGOING;
105         }
106         return CATEGORY_EVERYTHING_ELSE;
107     }
108 }
109