• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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
14  * limitations under the License
15  */
16 
17 package com.android.systemui.statusbar.notification.collection;
18 
19 import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
20 import static android.app.AppOpsManager.OP_CAMERA;
21 import static android.app.Notification.CATEGORY_ALARM;
22 import static android.app.Notification.CATEGORY_CALL;
23 import static android.app.Notification.CATEGORY_EVENT;
24 import static android.app.Notification.CATEGORY_MESSAGE;
25 import static android.app.Notification.CATEGORY_REMINDER;
26 import static android.app.NotificationManager.IMPORTANCE_LOW;
27 import static android.app.NotificationManager.IMPORTANCE_MIN;
28 
29 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
30 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
31 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK;
32 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
33 
34 import static junit.framework.Assert.assertEquals;
35 
36 import static org.junit.Assert.assertFalse;
37 import static org.junit.Assert.assertTrue;
38 import static org.mockito.ArgumentMatchers.any;
39 import static org.mockito.Matchers.eq;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.when;
42 
43 import android.Manifest;
44 import android.app.Notification;
45 import android.app.NotificationChannel;
46 import android.app.NotificationManager;
47 import android.app.PendingIntent;
48 import android.app.Person;
49 import android.content.Intent;
50 import android.content.pm.IPackageManager;
51 import android.content.pm.PackageManager;
52 import android.graphics.drawable.Icon;
53 import android.media.session.MediaSession;
54 import android.os.Bundle;
55 import android.os.Process;
56 import android.service.notification.NotificationListenerService;
57 import android.service.notification.NotificationListenerService.Ranking;
58 import android.service.notification.SnoozeCriterion;
59 import android.service.notification.StatusBarNotification;
60 import android.testing.AndroidTestingRunner;
61 import android.testing.TestableLooper;
62 import android.testing.TestableLooper.RunWithLooper;
63 import android.util.ArraySet;
64 
65 import com.android.systemui.Dependency;
66 import com.android.systemui.ForegroundServiceController;
67 import com.android.systemui.InitController;
68 import com.android.systemui.SysuiTestCase;
69 import com.android.systemui.statusbar.NotificationTestHelper;
70 import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
71 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
72 import com.android.systemui.statusbar.phone.NotificationGroupManager;
73 import com.android.systemui.statusbar.phone.ShadeController;
74 
75 import org.junit.Before;
76 import org.junit.Test;
77 import org.junit.runner.RunWith;
78 import org.mockito.Mock;
79 import org.mockito.MockitoAnnotations;
80 
81 import java.util.ArrayList;
82 import java.util.Collections;
83 import java.util.HashMap;
84 import java.util.List;
85 import java.util.Map;
86 
87 import androidx.test.filters.SmallTest;
88 
89 @SmallTest
90 @RunWith(AndroidTestingRunner.class)
91 @RunWithLooper
92 public class NotificationDataTest extends SysuiTestCase {
93 
94     private static final int UID_NORMAL = 123;
95     private static final int UID_ALLOW_DURING_SETUP = 456;
96     private static final NotificationChannel NOTIFICATION_CHANNEL =
97             new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
98 
99     private final StatusBarNotification mMockStatusBarNotification =
100             mock(StatusBarNotification.class);
101     @Mock
102     ForegroundServiceController mFsc;
103     @Mock
104     NotificationData.KeyguardEnvironment mEnvironment;
105 
106     private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
107     private TestableNotificationData mNotificationData;
108     private ExpandableNotificationRow mRow;
109 
110     @Before
setUp()111     public void setUp() throws Exception {
112         com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
113         MockitoAnnotations.initMocks(this);
114         when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
115         when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
116 
117         when(mMockPackageManager.checkUidPermission(
118                 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
119                 eq(UID_NORMAL)))
120                 .thenReturn(PackageManager.PERMISSION_DENIED);
121         when(mMockPackageManager.checkUidPermission(
122                 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
123                 eq(UID_ALLOW_DURING_SETUP)))
124                 .thenReturn(PackageManager.PERMISSION_GRANTED);
125 
126         mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
127         mDependency.injectTestDependency(NotificationGroupManager.class,
128                 new NotificationGroupManager());
129         mDependency.injectMockDependency(ShadeController.class);
130         mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
131         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
132         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
133         mNotificationData = new TestableNotificationData();
134         mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
135         mRow = new NotificationTestHelper(getContext()).createRow();
136         Dependency.get(InitController.class).executePostInitTasks();
137     }
138 
139     @Test
testChannelSetWhenAdded()140     public void testChannelSetWhenAdded() {
141         Bundle override = new Bundle();
142         override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
143         mNotificationData.rankingOverrides.put(mRow.getEntry().key, override);
144         mNotificationData.add(mRow.getEntry());
145         assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
146     }
147 
148     @Test
testAllRelevantNotisTaggedWithAppOps()149     public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
150         mNotificationData.add(mRow.getEntry());
151         ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
152         mNotificationData.add(row2.getEntry());
153         ExpandableNotificationRow diffPkg =
154                 new NotificationTestHelper(getContext()).createRow("pkg", 4000,
155                         Process.myUserHandle());
156         mNotificationData.add(diffPkg.getEntry());
157 
158         ArraySet<Integer> expectedOps = new ArraySet<>();
159         expectedOps.add(OP_CAMERA);
160         expectedOps.add(OP_ACCEPT_HANDOVER);
161 
162         for (int op : expectedOps) {
163             mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
164                     NotificationTestHelper.PKG, mRow.getEntry().key, true);
165             mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
166                     NotificationTestHelper.PKG, row2.getEntry().key, true);
167         }
168         for (int op : expectedOps) {
169             assertTrue(mRow.getEntry().key + " doesn't have op " + op,
170                     mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
171             assertTrue(row2.getEntry().key + " doesn't have op " + op,
172                     mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
173             assertFalse(diffPkg.getEntry().key + " has op " + op,
174                     mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
175         }
176     }
177 
178     @Test
testAppOpsRemoval()179     public void testAppOpsRemoval() throws Exception {
180         mNotificationData.add(mRow.getEntry());
181         ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
182         mNotificationData.add(row2.getEntry());
183 
184         ArraySet<Integer> expectedOps = new ArraySet<>();
185         expectedOps.add(OP_CAMERA);
186         expectedOps.add(OP_ACCEPT_HANDOVER);
187 
188         for (int op : expectedOps) {
189             mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
190                     NotificationTestHelper.PKG, row2.getEntry().key, true);
191         }
192 
193         expectedOps.remove(OP_ACCEPT_HANDOVER);
194         mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
195                 NotificationTestHelper.PKG, row2.getEntry().key, false);
196 
197         assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
198                 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
199         assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
200                 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
201         assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
202                 mNotificationData.get(mRow.getEntry().key)
203                         .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
204         assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
205                 mNotificationData.get(row2.getEntry().key)
206                         .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
207     }
208 
209     @Test
testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()210     public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
211             throws Exception {
212         mNotificationData.add(mRow.getEntry());
213         ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
214         mNotificationData.add(row2.getEntry());
215 
216         when(mEnvironment.isNotificationForCurrentProfiles(
217                 mRow.getEntry().notification)).thenReturn(false);
218         when(mEnvironment.isNotificationForCurrentProfiles(
219                 row2.getEntry().notification)).thenReturn(true);
220         ArrayList<NotificationEntry> result =
221                 mNotificationData.getNotificationsForCurrentUser();
222 
223         assertEquals(result.size(), 1);
224         junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
225     }
226 
227     @Test
testIsExemptFromDndVisualSuppression_foreground()228     public void testIsExemptFromDndVisualSuppression_foreground() {
229         initStatusBarNotification(false);
230 
231         Notification n = mMockStatusBarNotification.getNotification();
232         n.flags = Notification.FLAG_FOREGROUND_SERVICE;
233         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
234         mNotificationData.add(entry);
235         Bundle override = new Bundle();
236         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
237         mNotificationData.rankingOverrides.put(entry.key, override);
238 
239         assertTrue(entry.isExemptFromDndVisualSuppression());
240         assertFalse(entry.shouldSuppressAmbient());
241     }
242 
243     @Test
testIsExemptFromDndVisualSuppression_media()244     public void testIsExemptFromDndVisualSuppression_media() {
245         initStatusBarNotification(false);
246         Notification n = mMockStatusBarNotification.getNotification();
247         Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
248         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
249         n = nb.build();
250         when(mMockStatusBarNotification.getNotification()).thenReturn(n);
251         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
252         mNotificationData.add(entry);
253         Bundle override = new Bundle();
254         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
255         mNotificationData.rankingOverrides.put(entry.key, override);
256 
257         assertTrue(entry.isExemptFromDndVisualSuppression());
258         assertFalse(entry.shouldSuppressAmbient());
259     }
260 
261     @Test
testIsExemptFromDndVisualSuppression_system()262     public void testIsExemptFromDndVisualSuppression_system() {
263         initStatusBarNotification(false);
264         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
265         entry.mIsSystemNotification = true;
266         mNotificationData.add(entry);
267         Bundle override = new Bundle();
268         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
269         mNotificationData.rankingOverrides.put(entry.key, override);
270 
271         assertTrue(entry.isExemptFromDndVisualSuppression());
272         assertFalse(entry.shouldSuppressAmbient());
273     }
274 
275     @Test
testIsNotExemptFromDndVisualSuppression_hiddenCategories()276     public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
277         initStatusBarNotification(false);
278         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
279         entry.mIsSystemNotification = true;
280         Bundle override = new Bundle();
281         override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
282         mNotificationData.rankingOverrides.put(entry.key, override);
283         mNotificationData.add(entry);
284 
285         when(mMockStatusBarNotification.getNotification()).thenReturn(
286                 new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build());
287 
288         assertFalse(entry.isExemptFromDndVisualSuppression());
289         assertTrue(entry.shouldSuppressAmbient());
290 
291         when(mMockStatusBarNotification.getNotification()).thenReturn(
292                 new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build());
293 
294         assertFalse(entry.isExemptFromDndVisualSuppression());
295 
296         when(mMockStatusBarNotification.getNotification()).thenReturn(
297                 new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build());
298 
299         assertFalse(entry.isExemptFromDndVisualSuppression());
300 
301         when(mMockStatusBarNotification.getNotification()).thenReturn(
302                 new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build());
303 
304         assertFalse(entry.isExemptFromDndVisualSuppression());
305 
306         when(mMockStatusBarNotification.getNotification()).thenReturn(
307                 new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build());
308 
309         assertFalse(entry.isExemptFromDndVisualSuppression());
310     }
311 
312     @Test
testCreateNotificationDataEntry_RankingUpdate()313     public void testCreateNotificationDataEntry_RankingUpdate() {
314         Ranking ranking = mock(Ranking.class);
315         initStatusBarNotification(false);
316 
317         List<Notification.Action> appGeneratedSmartActions =
318                 Collections.singletonList(createContextualAction("appGeneratedAction"));
319         mMockStatusBarNotification.getNotification().actions =
320                 appGeneratedSmartActions.toArray(new Notification.Action[0]);
321 
322         List<Notification.Action> systemGeneratedSmartActions =
323                 Collections.singletonList(createAction("systemGeneratedAction"));
324         when(ranking.getSmartActions()).thenReturn(systemGeneratedSmartActions);
325 
326         when(ranking.getChannel()).thenReturn(NOTIFICATION_CHANNEL);
327 
328         when(ranking.getUserSentiment()).thenReturn(Ranking.USER_SENTIMENT_NEGATIVE);
329 
330         SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
331         ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
332         snoozeCriterions.add(snoozeCriterion);
333         when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
334 
335         NotificationEntry entry =
336                 new NotificationEntry(mMockStatusBarNotification, ranking);
337 
338         assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
339         assertEquals(NOTIFICATION_CHANNEL, entry.channel);
340         assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment);
341         assertEquals(snoozeCriterions, entry.snoozeCriteria);
342     }
343 
344     @Test
notificationDataEntry_testIsLastMessageFromReply()345     public void notificationDataEntry_testIsLastMessageFromReply() {
346         Person.Builder person = new Person.Builder()
347                 .setName("name")
348                 .setKey("abc")
349                 .setUri("uri")
350                 .setBot(true);
351 
352         // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
353         Bundle bundle = new Bundle();
354         bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
355         Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
356                 "text", 0, person.build()).toBundle() };
357         bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
358 
359         Notification notification = new Notification.Builder(mContext, "test")
360                 .addExtras(bundle)
361                 .build();
362         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
363                 notification, mContext.getUser(), "", 0);
364 
365         NotificationEntry entry = new NotificationEntry(sbn);
366         entry.setHasSentReply();
367 
368         assertTrue(entry.isLastMessageFromReply());
369     }
370 
371     @Test
personHighPriority()372     public void personHighPriority() {
373         Person person = new Person.Builder()
374                 .setName("name")
375                 .setKey("abc")
376                 .setUri("uri")
377                 .setBot(true)
378                 .build();
379 
380         Notification notification = new Notification.Builder(mContext, "test")
381                 .addPerson(person)
382                 .build();
383 
384         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
385                 notification, mContext.getUser(), "", 0);
386 
387         assertTrue(mNotificationData.isHighPriority(sbn));
388     }
389 
390     @Test
messagingStyleHighPriority()391     public void messagingStyleHighPriority() {
392 
393         Notification notification = new Notification.Builder(mContext, "test")
394                 .setStyle(new Notification.MessagingStyle(""))
395                 .build();
396 
397         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
398                 notification, mContext.getUser(), "", 0);
399 
400         assertTrue(mNotificationData.isHighPriority(sbn));
401     }
402 
403     @Test
minForegroundNotHighPriority()404     public void minForegroundNotHighPriority() {
405         Notification notification = mock(Notification.class);
406         when(notification.isForegroundService()).thenReturn(true);
407 
408         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
409                 notification, mContext.getUser(), "", 0);
410 
411         Bundle override = new Bundle();
412         override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
413         mNotificationData.rankingOverrides.put(sbn.getKey(), override);
414 
415         assertFalse(mNotificationData.isHighPriority(sbn));
416     }
417 
418     @Test
lowForegroundHighPriority()419     public void lowForegroundHighPriority() {
420         Notification notification = mock(Notification.class);
421         when(notification.isForegroundService()).thenReturn(true);
422 
423         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
424                 notification, mContext.getUser(), "", 0);
425 
426         Bundle override = new Bundle();
427         override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
428         mNotificationData.rankingOverrides.put(sbn.getKey(), override);
429 
430         assertTrue(mNotificationData.isHighPriority(sbn));
431     }
432 
433     @Test
userChangeTrumpsHighPriorityCharacteristics()434     public void userChangeTrumpsHighPriorityCharacteristics() {
435         Person person = new Person.Builder()
436                 .setName("name")
437                 .setKey("abc")
438                 .setUri("uri")
439                 .setBot(true)
440                 .build();
441 
442         Notification notification = new Notification.Builder(mContext, "test")
443                 .addPerson(person)
444                 .setStyle(new Notification.MessagingStyle(""))
445                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
446                 .build();
447 
448         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
449                 notification, mContext.getUser(), "", 0);
450 
451         NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
452         channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
453 
454         Bundle override = new Bundle();
455         override.putParcelable(OVERRIDE_CHANNEL, channel);
456         mNotificationData.rankingOverrides.put(sbn.getKey(), override);
457 
458         assertFalse(mNotificationData.isHighPriority(sbn));
459     }
460 
461     @Test
testSort_highPriorityTrumpsNMSRank()462     public void testSort_highPriorityTrumpsNMSRank() {
463         // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
464         // front
465         Notification aN = new Notification.Builder(mContext, "test")
466                 .setStyle(new Notification.MessagingStyle(""))
467                 .build();
468         StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
469                 aN, mContext.getUser(), "", 0);
470         NotificationEntry a = new NotificationEntry(aSbn);
471         a.setRow(mock(ExpandableNotificationRow.class));
472         a.setIsHighPriority(false);
473 
474         Bundle override = new Bundle();
475         override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
476         override.putInt(OVERRIDE_RANK, 1);
477         mNotificationData.rankingOverrides.put(a.key, override);
478 
479         Notification bN = new Notification.Builder(mContext, "test")
480                 .setStyle(new Notification.MessagingStyle(""))
481                 .build();
482         StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
483                 bN, mContext.getUser(), "", 0);
484         NotificationEntry b = new NotificationEntry(bSbn);
485         b.setIsHighPriority(true);
486         b.setRow(mock(ExpandableNotificationRow.class));
487 
488         Bundle bOverride = new Bundle();
489         bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
490         bOverride.putInt(OVERRIDE_RANK, 2);
491         mNotificationData.rankingOverrides.put(b.key, bOverride);
492 
493         assertEquals(1, mNotificationData.mRankingComparator.compare(a, b));
494     }
495 
496     @Test
testSort_samePriorityUsesNMSRank()497     public void testSort_samePriorityUsesNMSRank() {
498         // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
499         // front
500         Notification aN = new Notification.Builder(mContext, "test")
501                 .setStyle(new Notification.MessagingStyle(""))
502                 .build();
503         StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
504                 aN, mContext.getUser(), "", 0);
505         NotificationEntry a = new NotificationEntry(aSbn);
506         a.setRow(mock(ExpandableNotificationRow.class));
507         a.setIsHighPriority(false);
508 
509         Bundle override = new Bundle();
510         override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
511         override.putInt(OVERRIDE_RANK, 1);
512         mNotificationData.rankingOverrides.put(a.key, override);
513 
514         Notification bN = new Notification.Builder(mContext, "test")
515                 .setStyle(new Notification.MessagingStyle(""))
516                 .build();
517         StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
518                 bN, mContext.getUser(), "", 0);
519         NotificationEntry b = new NotificationEntry(bSbn);
520         b.setRow(mock(ExpandableNotificationRow.class));
521         b.setIsHighPriority(false);
522 
523         Bundle bOverride = new Bundle();
524         bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
525         bOverride.putInt(OVERRIDE_RANK, 2);
526         mNotificationData.rankingOverrides.put(b.key, bOverride);
527 
528         assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
529     }
530 
initStatusBarNotification(boolean allowDuringSetup)531     private void initStatusBarNotification(boolean allowDuringSetup) {
532         Bundle bundle = new Bundle();
533         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
534         Notification notification = new Notification.Builder(mContext, "test")
535                 .addExtras(bundle)
536                 .build();
537         when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
538     }
539 
540     public static class TestableNotificationData extends NotificationData {
TestableNotificationData()541         public TestableNotificationData() {
542             super();
543         }
544 
545         public static final String OVERRIDE_RANK = "r";
546         public static final String OVERRIDE_DND = "dnd";
547         public static final String OVERRIDE_VIS_OVERRIDE = "vo";
548         public static final String OVERRIDE_VIS_EFFECTS = "ve";
549         public static final String OVERRIDE_IMPORTANCE = "i";
550         public static final String OVERRIDE_IMP_EXP = "ie";
551         public static final String OVERRIDE_GROUP = "g";
552         public static final String OVERRIDE_CHANNEL = "c";
553         public static final String OVERRIDE_PEOPLE = "p";
554         public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
555         public static final String OVERRIDE_BADGE = "b";
556         public static final String OVERRIDE_USER_SENTIMENT = "us";
557         public static final String OVERRIDE_HIDDEN = "h";
558         public static final String OVERRIDE_LAST_ALERTED = "la";
559         public static final String OVERRIDE_NOISY = "n";
560         public static final String OVERRIDE_SMART_ACTIONS = "sa";
561         public static final String OVERRIDE_SMART_REPLIES = "sr";
562         public static final String OVERRIDE_BUBBLE = "cb";
563 
564         public Map<String, Bundle> rankingOverrides = new HashMap<>();
565 
566         @Override
getRanking(String key, Ranking outRanking)567         protected boolean getRanking(String key, Ranking outRanking) {
568             super.getRanking(key, outRanking);
569 
570             ArrayList<String> currentAdditionalPeople = new ArrayList<>();
571             if (outRanking.getAdditionalPeople() != null) {
572                 currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
573             }
574 
575             ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
576             if (outRanking.getSnoozeCriteria() != null) {
577                 currentSnooze.addAll(outRanking.getSnoozeCriteria());
578             }
579 
580             ArrayList<Notification.Action> currentActions = new ArrayList<>();
581             if (outRanking.getSmartActions() != null) {
582                 currentActions.addAll(outRanking.getSmartActions());
583             }
584 
585             ArrayList<CharSequence> currentReplies = new ArrayList<>();
586             if (outRanking.getSmartReplies() != null) {
587                 currentReplies.addAll(outRanking.getSmartReplies());
588             }
589 
590             if (rankingOverrides.get(key) != null) {
591                 Bundle overrides = rankingOverrides.get(key);
592                 outRanking.populate(key,
593                         overrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
594                         overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()),
595                         overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()),
596                         overrides.getInt(OVERRIDE_VIS_EFFECTS,
597                                 outRanking.getSuppressedVisualEffects()),
598                         overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
599                         overrides.getCharSequence(OVERRIDE_IMP_EXP,
600                                 outRanking.getImportanceExplanation()),
601                         overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
602                         overrides.containsKey(OVERRIDE_CHANNEL)
603                                 ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL)
604                                 : outRanking.getChannel(),
605                         overrides.containsKey(OVERRIDE_PEOPLE)
606                                 ? overrides.getStringArrayList(OVERRIDE_PEOPLE)
607                                 : currentAdditionalPeople,
608                         overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
609                                 ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
610                                 : currentSnooze,
611                         overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
612                         overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
613                         overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
614                         overrides.getLong(OVERRIDE_LAST_ALERTED,
615                                 outRanking.getLastAudiblyAlertedMillis()),
616                         overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
617                         overrides.containsKey(OVERRIDE_SMART_ACTIONS)
618                                 ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
619                                 : currentActions,
620                         overrides.containsKey(OVERRIDE_SMART_REPLIES)
621                                 ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
622                                 : currentReplies,
623                         overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()));
624             }
625             return true;
626         }
627     }
628 
createContextualAction(String title)629     private Notification.Action createContextualAction(String title) {
630         return new Notification.Action.Builder(
631                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
632                 title,
633                 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
634                         .setContextual(true)
635                         .build();
636     }
637 
createAction(String title)638     private Notification.Action createAction(String title) {
639         return new Notification.Action.Builder(
640                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
641                 title,
642                 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
643     }
644 }
645