blob: f629757e4c6838ff7b9d450d58c6c99a622206c9 [file] [log] [blame]
Maurice Lam132710e2017-03-03 19:13:42 -08001/*
2 * Copyright (C) 2017 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
Rohan Shah20790b82018-07-02 17:21:04 -070014 * limitations under the License
Maurice Lam132710e2017-03-03 19:13:42 -080015 */
16
Ned Burnsf81c4c42019-01-07 14:10:43 -050017package com.android.systemui.statusbar.notification.collection;
Maurice Lam132710e2017-03-03 19:13:42 -080018
Julia Reynoldsfc640012018-02-21 12:25:27 -050019import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
20import static android.app.AppOpsManager.OP_CAMERA;
Julia Reynolds25926af2018-05-01 17:05:33 -040021import static android.app.Notification.CATEGORY_ALARM;
22import static android.app.Notification.CATEGORY_CALL;
23import static android.app.Notification.CATEGORY_EVENT;
24import static android.app.Notification.CATEGORY_MESSAGE;
25import static android.app.Notification.CATEGORY_REMINDER;
Ned Burns5c388cd2019-08-08 13:43:57 -040026import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -050027import static android.app.NotificationManager.IMPORTANCE_LOW;
28import static android.app.NotificationManager.IMPORTANCE_MIN;
29
30import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
31import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040032import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK;
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -050033import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
Julia Reynoldsfc640012018-02-21 12:25:27 -050034
35import static junit.framework.Assert.assertEquals;
36
Maurice Lam132710e2017-03-03 19:13:42 -080037import static org.junit.Assert.assertFalse;
38import static org.junit.Assert.assertTrue;
Julia Reynoldsfc640012018-02-21 12:25:27 -050039import static org.mockito.ArgumentMatchers.any;
Maurice Lam132710e2017-03-03 19:13:42 -080040import static org.mockito.Matchers.eq;
41import static org.mockito.Mockito.mock;
42import static org.mockito.Mockito.when;
43
44import android.Manifest;
45import android.app.Notification;
Selim Cinek608a57a2017-04-28 16:50:41 -070046import android.app.NotificationChannel;
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -050047import android.app.NotificationManager;
Tony Mak628cb932018-06-19 18:30:41 +010048import android.app.PendingIntent;
Beverlye98937a2018-11-15 10:18:57 -050049import android.app.Person;
Tony Mak628cb932018-06-19 18:30:41 +010050import android.content.Intent;
Maurice Lam132710e2017-03-03 19:13:42 -080051import android.content.pm.IPackageManager;
52import android.content.pm.PackageManager;
Tony Mak628cb932018-06-19 18:30:41 +010053import android.graphics.drawable.Icon;
Julia Reynolds5bbb6da2018-03-28 10:48:37 -040054import android.media.session.MediaSession;
Maurice Lam132710e2017-03-03 19:13:42 -080055import android.os.Bundle;
Yohei Yukawa72769462019-01-20 09:28:08 -080056import android.os.Process;
Selim Cinek608a57a2017-04-28 16:50:41 -070057import android.service.notification.NotificationListenerService;
Tony Mak628cb932018-06-19 18:30:41 +010058import android.service.notification.NotificationListenerService.Ranking;
59import android.service.notification.SnoozeCriterion;
Maurice Lam132710e2017-03-03 19:13:42 -080060import android.service.notification.StatusBarNotification;
Jason Monk6dceace2018-05-15 20:24:07 -040061import android.testing.AndroidTestingRunner;
Jason Monka716bac2018-12-05 15:48:21 -050062import android.testing.TestableLooper;
Jason Monk6dceace2018-05-15 20:24:07 -040063import android.testing.TestableLooper.RunWithLooper;
Julia Reynoldsfc640012018-02-21 12:25:27 -050064import android.util.ArraySet;
Maurice Lam132710e2017-03-03 19:13:42 -080065
Ned Burns5c388cd2019-08-08 13:43:57 -040066import androidx.test.filters.SmallTest;
67
Jason Monk297c04e2018-08-23 17:16:59 -040068import com.android.systemui.Dependency;
Julia Reynoldsfc640012018-02-21 12:25:27 -050069import com.android.systemui.ForegroundServiceController;
Jason Monk297c04e2018-08-23 17:16:59 -040070import com.android.systemui.InitController;
Maurice Lam132710e2017-03-03 19:13:42 -080071import com.android.systemui.SysuiTestCase;
Rohan Shah20790b82018-07-02 17:21:04 -070072import com.android.systemui.statusbar.NotificationTestHelper;
Ned Burnsf81c4c42019-01-07 14:10:43 -050073import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
Rohan Shah20790b82018-07-02 17:21:04 -070074import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Selim Cinek608a57a2017-04-28 16:50:41 -070075import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk297c04e2018-08-23 17:16:59 -040076import com.android.systemui.statusbar.phone.ShadeController;
Maurice Lam132710e2017-03-03 19:13:42 -080077
78import org.junit.Before;
79import org.junit.Test;
80import org.junit.runner.RunWith;
Julia Reynoldsfc640012018-02-21 12:25:27 -050081import org.mockito.Mock;
82import org.mockito.MockitoAnnotations;
Maurice Lam132710e2017-03-03 19:13:42 -080083
Dieter Hsu36e1ebc2018-06-06 15:41:46 +080084import java.util.ArrayList;
Gustav Sennton1463d832018-11-06 16:12:48 +000085import java.util.Collections;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040086import java.util.HashMap;
Gustav Sennton1463d832018-11-06 16:12:48 +000087import java.util.List;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040088import java.util.Map;
89
Maurice Lam132710e2017-03-03 19:13:42 -080090@SmallTest
Jason Monk6dceace2018-05-15 20:24:07 -040091@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050092@RunWithLooper
Maurice Lam132710e2017-03-03 19:13:42 -080093public class NotificationDataTest extends SysuiTestCase {
94
95 private static final int UID_NORMAL = 123;
96 private static final int UID_ALLOW_DURING_SETUP = 456;
Tony Mak628cb932018-06-19 18:30:41 +010097 private static final NotificationChannel NOTIFICATION_CHANNEL =
98 new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
Maurice Lam132710e2017-03-03 19:13:42 -080099
100 private final StatusBarNotification mMockStatusBarNotification =
101 mock(StatusBarNotification.class);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500102 @Mock
103 ForegroundServiceController mFsc;
104 @Mock
Jason Monk297c04e2018-08-23 17:16:59 -0400105 NotificationData.KeyguardEnvironment mEnvironment;
Maurice Lam132710e2017-03-03 19:13:42 -0800106
107 private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500108 private TestableNotificationData mNotificationData;
Selim Cinek608a57a2017-04-28 16:50:41 -0700109 private ExpandableNotificationRow mRow;
Maurice Lam132710e2017-03-03 19:13:42 -0800110
111 @Before
112 public void setUp() throws Exception {
Jason Monka716bac2018-12-05 15:48:21 -0500113 com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
Julia Reynoldsfc640012018-02-21 12:25:27 -0500114 MockitoAnnotations.initMocks(this);
Maurice Lam132710e2017-03-03 19:13:42 -0800115 when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500116 when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
Ned Burns5c388cd2019-08-08 13:43:57 -0400117 when(mMockStatusBarNotification.getKey()).thenReturn("mock_key");
Maurice Lam132710e2017-03-03 19:13:42 -0800118
119 when(mMockPackageManager.checkUidPermission(
120 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
121 eq(UID_NORMAL)))
122 .thenReturn(PackageManager.PERMISSION_DENIED);
123 when(mMockPackageManager.checkUidPermission(
124 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
125 eq(UID_ALLOW_DURING_SETUP)))
126 .thenReturn(PackageManager.PERMISSION_GRANTED);
Selim Cinek608a57a2017-04-28 16:50:41 -0700127
Julia Reynoldsfc640012018-02-21 12:25:27 -0500128 mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
Jason Monk297c04e2018-08-23 17:16:59 -0400129 mDependency.injectTestDependency(NotificationGroupManager.class,
130 new NotificationGroupManager());
131 mDependency.injectMockDependency(ShadeController.class);
132 mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500133 when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
134 when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
Jason Monk297c04e2018-08-23 17:16:59 -0400135 mNotificationData = new TestableNotificationData();
Selim Cinek608a57a2017-04-28 16:50:41 -0700136 mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
137 mRow = new NotificationTestHelper(getContext()).createRow();
Tony Mak7d4b3a52018-11-27 17:29:36 +0000138 Dependency.get(InitController.class).executePostInitTasks();
Maurice Lam132710e2017-03-03 19:13:42 -0800139 }
140
141 @Test
Selim Cinek608a57a2017-04-28 16:50:41 -0700142 public void testChannelSetWhenAdded() {
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400143 Bundle override = new Bundle();
144 override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
145 mNotificationData.rankingOverrides.put(mRow.getEntry().key, override);
Selim Cinek608a57a2017-04-28 16:50:41 -0700146 mNotificationData.add(mRow.getEntry());
Tony Mak628cb932018-06-19 18:30:41 +0100147 assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
Selim Cinek608a57a2017-04-28 16:50:41 -0700148 }
149
Julia Reynoldsfc640012018-02-21 12:25:27 -0500150 @Test
151 public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
152 mNotificationData.add(mRow.getEntry());
153 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
154 mNotificationData.add(row2.getEntry());
155 ExpandableNotificationRow diffPkg =
Yohei Yukawa72769462019-01-20 09:28:08 -0800156 new NotificationTestHelper(getContext()).createRow("pkg", 4000,
157 Process.myUserHandle());
Julia Reynoldsfc640012018-02-21 12:25:27 -0500158 mNotificationData.add(diffPkg.getEntry());
159
160 ArraySet<Integer> expectedOps = new ArraySet<>();
161 expectedOps.add(OP_CAMERA);
162 expectedOps.add(OP_ACCEPT_HANDOVER);
163
164 for (int op : expectedOps) {
165 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400166 NotificationTestHelper.PKG, mRow.getEntry().key, true);
167 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
168 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500169 }
170 for (int op : expectedOps) {
171 assertTrue(mRow.getEntry().key + " doesn't have op " + op,
172 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
173 assertTrue(row2.getEntry().key + " doesn't have op " + op,
174 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
175 assertFalse(diffPkg.getEntry().key + " has op " + op,
176 mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
177 }
178 }
179
180 @Test
181 public void testAppOpsRemoval() throws Exception {
182 mNotificationData.add(mRow.getEntry());
183 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
184 mNotificationData.add(row2.getEntry());
185
186 ArraySet<Integer> expectedOps = new ArraySet<>();
187 expectedOps.add(OP_CAMERA);
188 expectedOps.add(OP_ACCEPT_HANDOVER);
189
190 for (int op : expectedOps) {
191 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400192 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500193 }
194
195 expectedOps.remove(OP_ACCEPT_HANDOVER);
196 mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400197 NotificationTestHelper.PKG, row2.getEntry().key, false);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500198
199 assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
200 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
201 assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
202 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
203 assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
204 mNotificationData.get(mRow.getEntry().key)
205 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
206 assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
207 mNotificationData.get(row2.getEntry().key)
208 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
209 }
210
211 @Test
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800212 public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
213 throws Exception {
214 mNotificationData.add(mRow.getEntry());
215 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
216 mNotificationData.add(row2.getEntry());
217
218 when(mEnvironment.isNotificationForCurrentProfiles(
219 mRow.getEntry().notification)).thenReturn(false);
220 when(mEnvironment.isNotificationForCurrentProfiles(
221 row2.getEntry().notification)).thenReturn(true);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500222 ArrayList<NotificationEntry> result =
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800223 mNotificationData.getNotificationsForCurrentUser();
224
Jason Monk297c04e2018-08-23 17:16:59 -0400225 assertEquals(result.size(), 1);
226 junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800227 }
228
229 @Test
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400230 public void testIsExemptFromDndVisualSuppression_foreground() {
231 initStatusBarNotification(false);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500232
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400233 Notification n = mMockStatusBarNotification.getNotification();
234 n.flags = Notification.FLAG_FOREGROUND_SERVICE;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500235 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Ned Burns5c388cd2019-08-08 13:43:57 -0400236 entry.setRow(mRow);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500237 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400238 Bundle override = new Bundle();
239 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
240 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400241
Gus Prevasec9e1f02018-12-18 15:28:12 -0500242 assertTrue(entry.isExemptFromDndVisualSuppression());
243 assertFalse(entry.shouldSuppressAmbient());
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400244 }
245
246 @Test
247 public void testIsExemptFromDndVisualSuppression_media() {
248 initStatusBarNotification(false);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400249 Notification n = mMockStatusBarNotification.getNotification();
250 Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
251 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
252 n = nb.build();
253 when(mMockStatusBarNotification.getNotification()).thenReturn(n);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500254 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Ned Burns5c388cd2019-08-08 13:43:57 -0400255 entry.setRow(mRow);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500256 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400257 Bundle override = new Bundle();
258 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
259 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400260
Gus Prevasec9e1f02018-12-18 15:28:12 -0500261 assertTrue(entry.isExemptFromDndVisualSuppression());
262 assertFalse(entry.shouldSuppressAmbient());
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400263 }
264
265 @Test
266 public void testIsExemptFromDndVisualSuppression_system() {
267 initStatusBarNotification(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500268 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Ned Burns5c388cd2019-08-08 13:43:57 -0400269 entry.setRow(mRow);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400270 entry.mIsSystemNotification = true;
Gus Prevasec9e1f02018-12-18 15:28:12 -0500271 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400272 Bundle override = new Bundle();
273 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
274 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400275
Gus Prevasec9e1f02018-12-18 15:28:12 -0500276 assertTrue(entry.isExemptFromDndVisualSuppression());
277 assertFalse(entry.shouldSuppressAmbient());
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400278 }
279
Julia Reynolds25926af2018-05-01 17:05:33 -0400280 @Test
281 public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
282 initStatusBarNotification(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500283 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Ned Burns5c388cd2019-08-08 13:43:57 -0400284 entry.setRow(mRow);
Julia Reynolds25926af2018-05-01 17:05:33 -0400285 entry.mIsSystemNotification = true;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400286 Bundle override = new Bundle();
287 override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
288 mNotificationData.rankingOverrides.put(entry.key, override);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500289 mNotificationData.add(entry);
290
Julia Reynolds25926af2018-05-01 17:05:33 -0400291 when(mMockStatusBarNotification.getNotification()).thenReturn(
292 new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build());
293
Gus Prevasec9e1f02018-12-18 15:28:12 -0500294 assertFalse(entry.isExemptFromDndVisualSuppression());
295 assertTrue(entry.shouldSuppressAmbient());
Julia Reynolds25926af2018-05-01 17:05:33 -0400296
297 when(mMockStatusBarNotification.getNotification()).thenReturn(
298 new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build());
299
Gus Prevasec9e1f02018-12-18 15:28:12 -0500300 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400301
302 when(mMockStatusBarNotification.getNotification()).thenReturn(
303 new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build());
304
Gus Prevasec9e1f02018-12-18 15:28:12 -0500305 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400306
307 when(mMockStatusBarNotification.getNotification()).thenReturn(
308 new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build());
309
Gus Prevasec9e1f02018-12-18 15:28:12 -0500310 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400311
312 when(mMockStatusBarNotification.getNotification()).thenReturn(
313 new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build());
314
Gus Prevasec9e1f02018-12-18 15:28:12 -0500315 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400316 }
317
Tony Mak628cb932018-06-19 18:30:41 +0100318 @Test
319 public void testCreateNotificationDataEntry_RankingUpdate() {
320 Ranking ranking = mock(Ranking.class);
Gustav Sennton1463d832018-11-06 16:12:48 +0000321 initStatusBarNotification(false);
Tony Mak628cb932018-06-19 18:30:41 +0100322
Gustav Sennton1463d832018-11-06 16:12:48 +0000323 List<Notification.Action> appGeneratedSmartActions =
324 Collections.singletonList(createContextualAction("appGeneratedAction"));
325 mMockStatusBarNotification.getNotification().actions =
326 appGeneratedSmartActions.toArray(new Notification.Action[0]);
327
328 List<Notification.Action> systemGeneratedSmartActions =
329 Collections.singletonList(createAction("systemGeneratedAction"));
330 when(ranking.getSmartActions()).thenReturn(systemGeneratedSmartActions);
Tony Mak628cb932018-06-19 18:30:41 +0100331
332 when(ranking.getChannel()).thenReturn(NOTIFICATION_CHANNEL);
333
334 when(ranking.getUserSentiment()).thenReturn(Ranking.USER_SENTIMENT_NEGATIVE);
335
336 SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
337 ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
338 snoozeCriterions.add(snoozeCriterion);
339 when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
340
Ned Burnsf81c4c42019-01-07 14:10:43 -0500341 NotificationEntry entry =
342 new NotificationEntry(mMockStatusBarNotification, ranking);
Tony Mak628cb932018-06-19 18:30:41 +0100343
Gustav Sennton1463d832018-11-06 16:12:48 +0000344 assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
Tony Mak628cb932018-06-19 18:30:41 +0100345 assertEquals(NOTIFICATION_CHANNEL, entry.channel);
346 assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment);
347 assertEquals(snoozeCriterions, entry.snoozeCriteria);
348 }
349
Beverlye98937a2018-11-15 10:18:57 -0500350 @Test
351 public void notificationDataEntry_testIsLastMessageFromReply() {
352 Person.Builder person = new Person.Builder()
353 .setName("name")
354 .setKey("abc")
355 .setUri("uri")
356 .setBot(true);
357
358 // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
359 Bundle bundle = new Bundle();
360 bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
361 Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
362 "text", 0, person.build()).toBundle() };
363 bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
364
365 Notification notification = new Notification.Builder(mContext, "test")
366 .addExtras(bundle)
367 .build();
368 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
369 notification, mContext.getUser(), "", 0);
370
Ned Burnsf81c4c42019-01-07 14:10:43 -0500371 NotificationEntry entry = new NotificationEntry(sbn);
Beverlye98937a2018-11-15 10:18:57 -0500372 entry.setHasSentReply();
373
374 assertTrue(entry.isLastMessageFromReply());
375 }
376
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500377 @Test
378 public void personHighPriority() {
379 Person person = new Person.Builder()
380 .setName("name")
381 .setKey("abc")
382 .setUri("uri")
383 .setBot(true)
384 .build();
385
386 Notification notification = new Notification.Builder(mContext, "test")
387 .addPerson(person)
388 .build();
389
390 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
391 notification, mContext.getUser(), "", 0);
392
393 assertTrue(mNotificationData.isHighPriority(sbn));
394 }
395
396 @Test
397 public void messagingStyleHighPriority() {
398
399 Notification notification = new Notification.Builder(mContext, "test")
400 .setStyle(new Notification.MessagingStyle(""))
401 .build();
402
403 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
404 notification, mContext.getUser(), "", 0);
405
406 assertTrue(mNotificationData.isHighPriority(sbn));
407 }
408
409 @Test
410 public void minForegroundNotHighPriority() {
411 Notification notification = mock(Notification.class);
412 when(notification.isForegroundService()).thenReturn(true);
413
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500414 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
415 notification, mContext.getUser(), "", 0);
416
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400417 Bundle override = new Bundle();
418 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
419 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
420
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500421 assertFalse(mNotificationData.isHighPriority(sbn));
422 }
423
424 @Test
425 public void lowForegroundHighPriority() {
426 Notification notification = mock(Notification.class);
427 when(notification.isForegroundService()).thenReturn(true);
428
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400429 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
430 notification, mContext.getUser(), "", 0);
431
432 Bundle override = new Bundle();
433 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
434 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
435
436 assertTrue(mNotificationData.isHighPriority(sbn));
437 }
438
439 @Test
440 public void userChangeTrumpsHighPriorityCharacteristics() {
441 Person person = new Person.Builder()
442 .setName("name")
443 .setKey("abc")
444 .setUri("uri")
445 .setBot(true)
446 .build();
447
448 Notification notification = new Notification.Builder(mContext, "test")
449 .addPerson(person)
450 .setStyle(new Notification.MessagingStyle(""))
451 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
452 .build();
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500453
454 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
455 notification, mContext.getUser(), "", 0);
456
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400457 NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
458 channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
459
460 Bundle override = new Bundle();
461 override.putParcelable(OVERRIDE_CHANNEL, channel);
462 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
463
464 assertFalse(mNotificationData.isHighPriority(sbn));
465 }
466
467 @Test
468 public void testSort_highPriorityTrumpsNMSRank() {
469 // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
470 // front
471 Notification aN = new Notification.Builder(mContext, "test")
472 .setStyle(new Notification.MessagingStyle(""))
473 .build();
474 StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
475 aN, mContext.getUser(), "", 0);
476 NotificationEntry a = new NotificationEntry(aSbn);
477 a.setRow(mock(ExpandableNotificationRow.class));
478 a.setIsHighPriority(false);
479
480 Bundle override = new Bundle();
481 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
482 override.putInt(OVERRIDE_RANK, 1);
483 mNotificationData.rankingOverrides.put(a.key, override);
484
485 Notification bN = new Notification.Builder(mContext, "test")
486 .setStyle(new Notification.MessagingStyle(""))
487 .build();
488 StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
489 bN, mContext.getUser(), "", 0);
490 NotificationEntry b = new NotificationEntry(bSbn);
491 b.setIsHighPriority(true);
492 b.setRow(mock(ExpandableNotificationRow.class));
493
494 Bundle bOverride = new Bundle();
495 bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
496 bOverride.putInt(OVERRIDE_RANK, 2);
497 mNotificationData.rankingOverrides.put(b.key, bOverride);
498
499 assertEquals(1, mNotificationData.mRankingComparator.compare(a, b));
500 }
501
502 @Test
503 public void testSort_samePriorityUsesNMSRank() {
504 // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
505 // front
506 Notification aN = new Notification.Builder(mContext, "test")
507 .setStyle(new Notification.MessagingStyle(""))
508 .build();
509 StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
510 aN, mContext.getUser(), "", 0);
511 NotificationEntry a = new NotificationEntry(aSbn);
512 a.setRow(mock(ExpandableNotificationRow.class));
513 a.setIsHighPriority(false);
514
515 Bundle override = new Bundle();
516 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
517 override.putInt(OVERRIDE_RANK, 1);
518 mNotificationData.rankingOverrides.put(a.key, override);
519
520 Notification bN = new Notification.Builder(mContext, "test")
521 .setStyle(new Notification.MessagingStyle(""))
522 .build();
523 StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
524 bN, mContext.getUser(), "", 0);
525 NotificationEntry b = new NotificationEntry(bSbn);
526 b.setRow(mock(ExpandableNotificationRow.class));
527 b.setIsHighPriority(false);
528
529 Bundle bOverride = new Bundle();
530 bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
531 bOverride.putInt(OVERRIDE_RANK, 2);
532 mNotificationData.rankingOverrides.put(b.key, bOverride);
533
534 assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500535 }
536
Ned Burns5c388cd2019-08-08 13:43:57 -0400537 @Test
538 public void testSort_properlySetsIsTopBucket() {
539
540 Notification notification = new Notification.Builder(mContext, "test")
541 .build();
542 StatusBarNotification sbn = new StatusBarNotification(
543 "pkg",
544 "pkg",
545 0,
546 "tag",
547 0,
548 0,
549 notification,
550 mContext.getUser(),
551 "",
552 0);
553
554 Bundle override = new Bundle();
555 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
556 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
557
558 NotificationEntry entry = new NotificationEntry(sbn);
559 entry.setRow(mRow);
560 mNotificationData.add(entry);
561
562 assertTrue(entry.isTopBucket());
563 }
564
565 @Test
566 public void testSort_properlySetsIsNotTopBucket() {
567 Notification notification = new Notification.Builder(mContext, "test")
568 .build();
569 StatusBarNotification sbn = new StatusBarNotification(
570 "pkg",
571 "pkg",
572 0,
573 "tag",
574 0,
575 0,
576 notification,
577 mContext.getUser(),
578 "",
579 0);
580
581 Bundle override = new Bundle();
582 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
583 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
584
585 NotificationEntry entry = new NotificationEntry(sbn);
586 entry.setRow(mRow);
587
588 mNotificationData.add(entry);
589
590 assertFalse(entry.isTopBucket());
591 }
592
Maurice Lam132710e2017-03-03 19:13:42 -0800593 private void initStatusBarNotification(boolean allowDuringSetup) {
594 Bundle bundle = new Bundle();
595 bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
596 Notification notification = new Notification.Builder(mContext, "test")
597 .addExtras(bundle)
598 .build();
599 when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
600 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700601
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500602 public static class TestableNotificationData extends NotificationData {
Jason Monk297c04e2018-08-23 17:16:59 -0400603 public TestableNotificationData() {
604 super();
Selim Cinek608a57a2017-04-28 16:50:41 -0700605 }
606
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500607 public static final String OVERRIDE_RANK = "r";
608 public static final String OVERRIDE_DND = "dnd";
609 public static final String OVERRIDE_VIS_OVERRIDE = "vo";
610 public static final String OVERRIDE_VIS_EFFECTS = "ve";
611 public static final String OVERRIDE_IMPORTANCE = "i";
612 public static final String OVERRIDE_IMP_EXP = "ie";
613 public static final String OVERRIDE_GROUP = "g";
614 public static final String OVERRIDE_CHANNEL = "c";
615 public static final String OVERRIDE_PEOPLE = "p";
616 public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
617 public static final String OVERRIDE_BADGE = "b";
618 public static final String OVERRIDE_USER_SENTIMENT = "us";
619 public static final String OVERRIDE_HIDDEN = "h";
620 public static final String OVERRIDE_LAST_ALERTED = "la";
621 public static final String OVERRIDE_NOISY = "n";
622 public static final String OVERRIDE_SMART_ACTIONS = "sa";
623 public static final String OVERRIDE_SMART_REPLIES = "sr";
624 public static final String OVERRIDE_BUBBLE = "cb";
625
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400626 public Map<String, Bundle> rankingOverrides = new HashMap<>();
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500627
Selim Cinek608a57a2017-04-28 16:50:41 -0700628 @Override
Tony Mak628cb932018-06-19 18:30:41 +0100629 protected boolean getRanking(String key, Ranking outRanking) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900630 super.getRanking(key, outRanking);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500631
632 ArrayList<String> currentAdditionalPeople = new ArrayList<>();
633 if (outRanking.getAdditionalPeople() != null) {
634 currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
Beverly5a20a5e2018-03-06 15:02:44 -0500635 }
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500636
637 ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
638 if (outRanking.getSnoozeCriteria() != null) {
639 currentSnooze.addAll(outRanking.getSnoozeCriteria());
640 }
641
642 ArrayList<Notification.Action> currentActions = new ArrayList<>();
643 if (outRanking.getSmartActions() != null) {
644 currentActions.addAll(outRanking.getSmartActions());
645 }
646
647 ArrayList<CharSequence> currentReplies = new ArrayList<>();
648 if (outRanking.getSmartReplies() != null) {
649 currentReplies.addAll(outRanking.getSmartReplies());
650 }
651
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400652 if (rankingOverrides.get(key) != null) {
653 Bundle overrides = rankingOverrides.get(key);
654 outRanking.populate(key,
655 overrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
656 overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()),
657 overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()),
658 overrides.getInt(OVERRIDE_VIS_EFFECTS,
659 outRanking.getSuppressedVisualEffects()),
660 overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
661 overrides.getCharSequence(OVERRIDE_IMP_EXP,
662 outRanking.getImportanceExplanation()),
663 overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
664 overrides.containsKey(OVERRIDE_CHANNEL)
665 ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL)
666 : outRanking.getChannel(),
667 overrides.containsKey(OVERRIDE_PEOPLE)
668 ? overrides.getStringArrayList(OVERRIDE_PEOPLE)
669 : currentAdditionalPeople,
670 overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
671 ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
672 : currentSnooze,
673 overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
674 overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
675 overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
676 overrides.getLong(OVERRIDE_LAST_ALERTED,
677 outRanking.getLastAudiblyAlertedMillis()),
678 overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
679 overrides.containsKey(OVERRIDE_SMART_ACTIONS)
680 ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
681 : currentActions,
682 overrides.containsKey(OVERRIDE_SMART_REPLIES)
683 ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
684 : currentReplies,
685 overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()));
686 }
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900687 return true;
688 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700689 }
Tony Mak628cb932018-06-19 18:30:41 +0100690
Gustav Sennton1463d832018-11-06 16:12:48 +0000691 private Notification.Action createContextualAction(String title) {
Tony Mak628cb932018-06-19 18:30:41 +0100692 return new Notification.Action.Builder(
693 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
Gustav Sennton1463d832018-11-06 16:12:48 +0000694 title,
695 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
Gustav Sennton005d7a02019-01-04 13:41:32 +0000696 .setContextual(true)
Gustav Sennton1463d832018-11-06 16:12:48 +0000697 .build();
698 }
699
700 private Notification.Action createAction(String title) {
701 return new Notification.Action.Builder(
702 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
703 title,
Tony Mak628cb932018-06-19 18:30:41 +0100704 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
705 }
Maurice Lam132710e2017-03-03 19:13:42 -0800706}