blob: 52c199a34f670e39babb307b04cb71bf54707aea [file] [log] [blame]
Julia Reynolds22f02b32016-12-01 15:05:13 -05001/*
2 * Copyright (C) 2016 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
17package com.android.server.notification;
18
Gus Prevas7306b902018-12-11 10:57:06 -050019import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
20import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
21import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
Julia Reynolds503ed942017-10-04 16:04:56 -040022
Julia Reynolds22f02b32016-12-01 15:05:13 -050023import static org.junit.Assert.assertEquals;
Julia Reynolds94a38b32018-04-20 13:33:36 -040024import static org.junit.Assert.assertNotNull;
25import static org.mockito.ArgumentMatchers.any;
26import static org.mockito.ArgumentMatchers.anyInt;
27import static org.mockito.Mockito.mock;
28import static org.mockito.Mockito.when;
Julia Reynolds22f02b32016-12-01 15:05:13 -050029
Julia Reynolds94a38b32018-04-20 13:33:36 -040030import android.app.INotificationManager;
Tony Mak628cb932018-06-19 18:30:41 +010031import android.app.Notification;
Julia Reynolds22f02b32016-12-01 15:05:13 -050032import android.app.NotificationChannel;
Tony Mak628cb932018-06-19 18:30:41 +010033import android.app.PendingIntent;
Julia Reynolds22f02b32016-12-01 15:05:13 -050034import android.content.Intent;
35import android.os.Binder;
36import android.os.Bundle;
37import android.os.IBinder;
38import android.service.notification.NotificationListenerService;
39import android.service.notification.NotificationListenerService.Ranking;
40import android.service.notification.NotificationRankingUpdate;
41import android.service.notification.SnoozeCriterion;
Julia Reynolds22f02b32016-12-01 15:05:13 -050042import android.test.suitebuilder.annotation.SmallTest;
43
Brett Chabot84151d92019-02-27 15:37:59 -080044import androidx.test.runner.AndroidJUnit4;
45
Jason Monk74f5e362017-12-06 08:56:33 -050046import com.android.server.UiServiceTestCase;
47
Julia Reynolds22f02b32016-12-01 15:05:13 -050048import org.junit.Test;
49import org.junit.runner.RunWith;
50
51import java.util.ArrayList;
52import java.util.List;
53
54@SmallTest
55@RunWith(AndroidJUnit4.class)
Jason Monk74f5e362017-12-06 08:56:33 -050056public class NotificationListenerServiceTest extends UiServiceTestCase {
Julia Reynolds22f02b32016-12-01 15:05:13 -050057
Julia Reynolds4509ce72019-01-31 13:12:43 -050058 private String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};
Julia Reynolds22f02b32016-12-01 15:05:13 -050059
60 @Test
Julia Reynolds94a38b32018-04-20 13:33:36 -040061 public void testGetActiveNotifications_notNull() throws Exception {
62 TestListenerService service = new TestListenerService();
63 INotificationManager noMan = service.getNoMan();
64 when(noMan.getActiveNotificationsFromListener(any(), any(), anyInt())).thenReturn(null);
65
66 assertNotNull(service.getActiveNotifications());
67 assertNotNull(service.getActiveNotifications(NotificationListenerService.TRIM_FULL));
68 assertNotNull(service.getActiveNotifications(new String[0]));
69 assertNotNull(service.getActiveNotifications(
70 new String[0], NotificationListenerService.TRIM_LIGHT));
71 }
72
73 @Test
Julia Reynolds4509ce72019-01-31 13:12:43 -050074 public void testRanking() {
Julia Reynolds22f02b32016-12-01 15:05:13 -050075 TestListenerService service = new TestListenerService();
76 service.applyUpdateLocked(generateUpdate());
77 for (int i = 0; i < mKeys.length; i++) {
78 String key = mKeys[i];
79 Ranking ranking = new Ranking();
80 service.getCurrentRanking().getRanking(key, ranking);
81 assertEquals(getVisibilityOverride(i), ranking.getVisibilityOverride());
82 assertEquals(getOverrideGroupKey(key), ranking.getOverrideGroupKey());
83 assertEquals(!isIntercepted(i), ranking.matchesInterruptionFilter());
84 assertEquals(getSuppressedVisualEffects(i), ranking.getSuppressedVisualEffects());
85 assertEquals(getImportance(i), ranking.getImportance());
86 assertEquals(getExplanation(key), ranking.getImportanceExplanation());
87 assertEquals(getChannel(key, i), ranking.getChannel());
88 assertEquals(getPeople(key, i), ranking.getAdditionalPeople());
89 assertEquals(getSnoozeCriteria(key, i), ranking.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -050090 assertEquals(getShowBadge(i), ranking.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -040091 assertEquals(getUserSentiment(i), ranking.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -050092 assertEquals(getHidden(i), ranking.isSuspended());
Gus Prevas7306b902018-12-11 10:57:06 -050093 assertEquals(lastAudiblyAlerted(i), ranking.getLastAudiblyAlertedMillis());
Tony Mak628cb932018-06-19 18:30:41 +010094 assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +020095 assertEquals(getSmartReplies(key, i), ranking.getSmartReplies());
Julia Reynolds4509ce72019-01-31 13:12:43 -050096 assertEquals(canBubble(i), ranking.canBubble());
Julia Reynolds22f02b32016-12-01 15:05:13 -050097 }
98 }
99
100 private NotificationRankingUpdate generateUpdate() {
101 List<String> interceptedKeys = new ArrayList<>();
102 Bundle visibilityOverrides = new Bundle();
103 Bundle overrideGroupKeys = new Bundle();
104 Bundle suppressedVisualEffects = new Bundle();
105 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -0500106 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -0500107 Bundle overridePeople = new Bundle();
108 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -0500109 Bundle showBadge = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -0500110 int[] importance = new int[mKeys.length];
Julia Reynolds503ed942017-10-04 16:04:56 -0400111 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -0500112 Bundle mHidden = new Bundle();
Tony Mak628cb932018-06-19 18:30:41 +0100113 Bundle smartActions = new Bundle();
Tony Makc9acf672018-07-20 13:58:24 +0200114 Bundle smartReplies = new Bundle();
Gus Prevas7306b902018-12-11 10:57:06 -0500115 Bundle lastAudiblyAlerted = new Bundle();
Gus Prevas9abc5062018-10-31 16:11:04 -0400116 Bundle noisy = new Bundle();
Julia Reynolds4509ce72019-01-31 13:12:43 -0500117 boolean[] canBubble = new boolean[mKeys.length];
Julia Reynolds22f02b32016-12-01 15:05:13 -0500118
119 for (int i = 0; i < mKeys.length; i++) {
120 String key = mKeys[i];
121 visibilityOverrides.putInt(key, getVisibilityOverride(i));
122 overrideGroupKeys.putString(key, getOverrideGroupKey(key));
123 if (isIntercepted(i)) {
124 interceptedKeys.add(key);
125 }
126 suppressedVisualEffects.putInt(key, getSuppressedVisualEffects(i));
127 importance[i] = getImportance(i);
128 explanation.putString(key, getExplanation(key));
Julia Reynolds924eed12017-01-19 09:52:07 -0500129 channels.putParcelable(key, getChannel(key, i));
Julia Reynolds22f02b32016-12-01 15:05:13 -0500130 overridePeople.putStringArrayList(key, getPeople(key, i));
131 snoozeCriteria.putParcelableArrayList(key, getSnoozeCriteria(key, i));
Julia Reynolds924eed12017-01-19 09:52:07 -0500132 showBadge.putBoolean(key, getShowBadge(i));
Julia Reynolds503ed942017-10-04 16:04:56 -0400133 userSentiment.putInt(key, getUserSentiment(i));
Beverly5a20a5e2018-03-06 15:02:44 -0500134 mHidden.putBoolean(key, getHidden(i));
Tony Mak628cb932018-06-19 18:30:41 +0100135 smartActions.putParcelableArrayList(key, getSmartActions(key, i));
Tony Makc9acf672018-07-20 13:58:24 +0200136 smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
Gus Prevas7306b902018-12-11 10:57:06 -0500137 lastAudiblyAlerted.putLong(key, lastAudiblyAlerted(i));
Gus Prevas9abc5062018-10-31 16:11:04 -0400138 noisy.putBoolean(key, getNoisy(i));
Julia Reynolds4509ce72019-01-31 13:12:43 -0500139 canBubble[i] = canBubble(i);
Julia Reynolds22f02b32016-12-01 15:05:13 -0500140 }
141 NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
142 interceptedKeys.toArray(new String[0]), visibilityOverrides,
143 suppressedVisualEffects, importance, explanation, overrideGroupKeys,
Tony Mak628cb932018-06-19 18:30:41 +0100144 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
Julia Reynolds4509ce72019-01-31 13:12:43 -0500145 smartActions, smartReplies, lastAudiblyAlerted, noisy, canBubble);
Julia Reynolds22f02b32016-12-01 15:05:13 -0500146 return update;
147 }
148
149 private int getVisibilityOverride(int index) {
150 return index * 9;
151 }
152
153 private String getOverrideGroupKey(String key) {
154 return key + key;
155 }
156
157 private boolean isIntercepted(int index) {
158 return index % 2 == 0;
159 }
160
161 private int getSuppressedVisualEffects(int index) {
162 return index * 2;
163 }
164
165 private int getImportance(int index) {
166 return index;
167 }
168
169 private String getExplanation(String key) {
170 return key + "explain";
171 }
172
173 private NotificationChannel getChannel(String key, int index) {
174 return new NotificationChannel(key, key, getImportance(index));
175 }
176
Julia Reynolds924eed12017-01-19 09:52:07 -0500177 private boolean getShowBadge(int index) {
178 return index % 3 == 0;
179 }
180
Julia Reynolds503ed942017-10-04 16:04:56 -0400181 private int getUserSentiment(int index) {
182 switch(index % 3) {
183 case 0:
184 return USER_SENTIMENT_NEGATIVE;
185 case 1:
186 return USER_SENTIMENT_NEUTRAL;
187 case 2:
188 return USER_SENTIMENT_POSITIVE;
189 }
190 return USER_SENTIMENT_NEUTRAL;
191 }
192
Beverly5a20a5e2018-03-06 15:02:44 -0500193 private boolean getHidden(int index) {
194 return index % 2 == 0;
195 }
196
Gus Prevas7306b902018-12-11 10:57:06 -0500197 private long lastAudiblyAlerted(int index) {
198 return index * 2000;
Gus Prevasa3226492018-10-23 11:10:09 -0400199 }
200
Gus Prevas9abc5062018-10-31 16:11:04 -0400201 private boolean getNoisy(int index) {
202 return index < 1;
203 }
204
Julia Reynolds22f02b32016-12-01 15:05:13 -0500205 private ArrayList<String> getPeople(String key, int index) {
206 ArrayList<String> people = new ArrayList<>();
207 for (int i = 0; i < index; i++) {
208 people.add(i + key);
209 }
210 return people;
211 }
212
213 private ArrayList<SnoozeCriterion> getSnoozeCriteria(String key, int index) {
214 ArrayList<SnoozeCriterion> snooze = new ArrayList<>();
215 for (int i = 0; i < index; i++) {
216 snooze.add(new SnoozeCriterion(key + i, getExplanation(key), key));
217 }
218 return snooze;
219 }
220
Tony Mak628cb932018-06-19 18:30:41 +0100221 private ArrayList<Notification.Action> getSmartActions(String key, int index) {
222 ArrayList<Notification.Action> actions = new ArrayList<>();
223 for (int i = 0; i < index; i++) {
224 PendingIntent intent = PendingIntent.getBroadcast(
225 getContext(),
226 index /*requestCode*/,
227 new Intent("ACTION_" + key),
228 0 /*flags*/);
229 actions.add(new Notification.Action.Builder(null /*icon*/, key, intent).build());
230 }
231 return actions;
232 }
233
Tony Makc9acf672018-07-20 13:58:24 +0200234 private ArrayList<CharSequence> getSmartReplies(String key, int index) {
235 ArrayList<CharSequence> choices = new ArrayList<>();
236 for (int i = 0; i < index; i++) {
237 choices.add("choice_" + key + "_" + i);
238 }
239 return choices;
240 }
241
Julia Reynolds4509ce72019-01-31 13:12:43 -0500242 private boolean canBubble(int index) {
243 return index % 4 == 0;
244 }
245
Tony Mak628cb932018-06-19 18:30:41 +0100246 private void assertActionsEqual(
247 List<Notification.Action> expecteds, List<Notification.Action> actuals) {
248 assertEquals(expecteds.size(), actuals.size());
249 for (int i = 0; i < expecteds.size(); i++) {
250 Notification.Action expected = expecteds.get(i);
251 Notification.Action actual = actuals.get(i);
252 assertEquals(expected.title, actual.title);
253 }
254 }
255
Julia Reynolds22f02b32016-12-01 15:05:13 -0500256 public static class TestListenerService extends NotificationListenerService {
257 private final IBinder binder = new LocalBinder();
258
259 public TestListenerService() {
Julia Reynolds94a38b32018-04-20 13:33:36 -0400260 mWrapper = mock(NotificationListenerWrapper.class);
261 mNoMan = mock(INotificationManager.class);
262 }
Julia Reynolds22f02b32016-12-01 15:05:13 -0500263
Julia Reynolds94a38b32018-04-20 13:33:36 -0400264 INotificationManager getNoMan() {
265 return mNoMan;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500266 }
267
268 @Override
269 public IBinder onBind(Intent intent) {
270 super.onBind(intent);
271 return binder;
272 }
273
274 public class LocalBinder extends Binder {
275 TestListenerService getService() {
276 return TestListenerService.this;
277 }
278 }
279 }
280}