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