1 /* 2 * Copyright (C) 2008 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 android.app.cts; 18 19 import static android.app.Notification.CATEGORY_CALL; 20 import static android.app.Notification.FLAG_BUBBLE; 21 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; 22 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 23 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 24 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 25 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 26 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 27 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 28 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 29 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 30 import static android.app.stubs.BubblesTestActivity.BUBBLE_NOTIF_ID; 31 import static android.app.stubs.BubblesTestService.EXTRA_TEST_CASE; 32 import static android.app.stubs.BubblesTestService.TEST_NO_BUBBLE_METADATA; 33 import static android.app.stubs.BubblesTestService.TEST_NO_CATEGORY; 34 import static android.app.stubs.BubblesTestService.TEST_NO_PERSON; 35 import static android.app.stubs.BubblesTestService.TEST_SUCCESS; 36 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 37 import static android.content.pm.PackageManager.FEATURE_WATCH; 38 39 import android.app.Activity; 40 import android.app.ActivityManager; 41 import android.app.AutomaticZenRule; 42 import android.app.Instrumentation; 43 import android.app.KeyguardManager; 44 import android.app.Notification; 45 import android.app.NotificationChannel; 46 import android.app.NotificationChannelGroup; 47 import android.app.NotificationManager; 48 import android.app.PendingIntent; 49 import android.app.Person; 50 import android.app.RemoteInput; 51 import android.app.UiAutomation; 52 import android.app.stubs.AutomaticZenRuleActivity; 53 import android.app.stubs.BubblesTestActivity; 54 import android.app.stubs.BubblesTestNotDocumentLaunchModeActivity; 55 import android.app.stubs.BubblesTestNotEmbeddableActivity; 56 import android.app.stubs.BubblesTestService; 57 import android.app.stubs.R; 58 import android.app.stubs.TestNotificationListener; 59 import android.content.BroadcastReceiver; 60 import android.content.ComponentName; 61 import android.content.ContentProviderOperation; 62 import android.content.Context; 63 import android.content.Intent; 64 import android.content.IntentFilter; 65 import android.content.OperationApplicationException; 66 import android.content.pm.PackageManager; 67 import android.database.Cursor; 68 import android.graphics.Bitmap; 69 import android.graphics.drawable.Icon; 70 import android.media.AudioAttributes; 71 import android.media.session.MediaSession; 72 import android.net.Uri; 73 import android.os.Build; 74 import android.os.Bundle; 75 import android.os.ParcelFileDescriptor; 76 import android.os.RemoteException; 77 import android.os.SystemClock; 78 import android.os.UserHandle; 79 import android.provider.ContactsContract; 80 import android.provider.ContactsContract.CommonDataKinds.Email; 81 import android.provider.ContactsContract.CommonDataKinds.Phone; 82 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 83 import android.provider.ContactsContract.Data; 84 import android.provider.Settings; 85 import android.provider.Telephony.Threads; 86 import android.server.wm.ActivityManagerTestBase; 87 import android.service.notification.Condition; 88 import android.service.notification.NotificationListenerService; 89 import android.service.notification.StatusBarNotification; 90 import android.test.AndroidTestCase; 91 import android.util.Log; 92 import android.widget.RemoteViews; 93 94 import androidx.test.filters.FlakyTest; 95 import androidx.test.InstrumentationRegistry; 96 97 import com.android.compatibility.common.util.SystemUtil; 98 99 import junit.framework.Assert; 100 101 import java.io.FileInputStream; 102 import java.io.IOException; 103 import java.io.InputStream; 104 import java.util.ArrayList; 105 import java.util.Arrays; 106 import java.util.HashMap; 107 import java.util.List; 108 import java.util.Map; 109 import java.util.Objects; 110 import java.util.UUID; 111 import java.util.concurrent.CountDownLatch; 112 import java.util.concurrent.TimeUnit; 113 114 /* This tests NotificationListenerService together with NotificationManager, as you need to have 115 * notifications to manipulate in order to test the listener service. */ 116 public class NotificationManagerTest extends AndroidTestCase { 117 final String TAG = NotificationManagerTest.class.getSimpleName(); 118 final boolean DEBUG = false; 119 final String NOTIFICATION_CHANNEL_ID = "NotificationManagerTest"; 120 121 private static final String DELEGATOR = "com.android.test.notificationdelegator"; 122 private static final String REVOKE_CLASS = DELEGATOR + ".NotificationRevoker"; 123 private static final int WAIT_TIME = 2000; 124 125 private PackageManager mPackageManager; 126 private NotificationManager mNotificationManager; 127 private ActivityManager mActivityManager; 128 private String mId; 129 private TestNotificationListener mListener; 130 private List<String> mRuleIds; 131 132 @Override 133 protected void setUp() throws Exception { 134 super.setUp(); 135 // This will leave a set of channels on the device with each test run. 136 mId = UUID.randomUUID().toString(); 137 mNotificationManager = (NotificationManager) mContext.getSystemService( 138 Context.NOTIFICATION_SERVICE); 139 // clear the deck so that our getActiveNotifications results are predictable 140 mNotificationManager.cancelAll(); 141 mNotificationManager.createNotificationChannel(new NotificationChannel( 142 NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT)); 143 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 144 mPackageManager = mContext.getPackageManager(); 145 mRuleIds = new ArrayList<>(); 146 147 // delay between tests so notifications aren't dropped by the rate limiter 148 try { 149 Thread.sleep(500); 150 } catch(InterruptedException e) {} 151 } 152 153 @Override 154 protected void tearDown() throws Exception { 155 super.tearDown(); 156 mNotificationManager.cancelAll(); 157 158 for (String id : mRuleIds) { 159 mNotificationManager.removeAutomaticZenRule(id); 160 } 161 162 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 163 164 List<NotificationChannel> channels = mNotificationManager.getNotificationChannels(); 165 // Delete all channels. 166 for (NotificationChannel nc : channels) { 167 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 168 continue; 169 } 170 mNotificationManager.deleteNotificationChannel(nc.getId()); 171 } 172 173 toggleListenerAccess(TestNotificationListener.getId(), 174 InstrumentationRegistry.getInstrumentation(), false); 175 toggleNotificationPolicyAccess(mContext.getPackageName(), 176 InstrumentationRegistry.getInstrumentation(), false); 177 178 List<NotificationChannelGroup> groups = mNotificationManager.getNotificationChannelGroups(); 179 // Delete all groups. 180 for (NotificationChannelGroup ncg : groups) { 181 mNotificationManager.deleteNotificationChannelGroup(ncg.getId()); 182 } 183 } 184 185 private void toggleBubbleSetting(boolean enabled) throws InterruptedException { 186 SystemUtil.runWithShellPermissionIdentity(() -> 187 Settings.Secure.putInt(mContext.getContentResolver(), 188 Settings.Secure.NOTIFICATION_BUBBLES, enabled ? 1 : 0)); 189 Thread.sleep(500); // wait for ranking update 190 191 } 192 193 private void insertSingleContact(String name, String phone, String email, boolean starred) { 194 final ArrayList<ContentProviderOperation> operationList = 195 new ArrayList<ContentProviderOperation>(); 196 ContentProviderOperation.Builder builder = 197 ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI); 198 builder.withValue(ContactsContract.RawContacts.STARRED, starred ? 1 : 0); 199 operationList.add(builder.build()); 200 201 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); 202 builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0); 203 builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 204 builder.withValue(StructuredName.DISPLAY_NAME, name); 205 operationList.add(builder.build()); 206 207 if (phone != null) { 208 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); 209 builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0); 210 builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 211 builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE); 212 builder.withValue(Phone.NUMBER, phone); 213 builder.withValue(Data.IS_PRIMARY, 1); 214 operationList.add(builder.build()); 215 } 216 if (email != null) { 217 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); 218 builder.withValueBackReference(Email.RAW_CONTACT_ID, 0); 219 builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 220 builder.withValue(Email.TYPE, Email.TYPE_HOME); 221 builder.withValue(Email.DATA, email); 222 operationList.add(builder.build()); 223 } 224 225 try { 226 mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList); 227 } catch (RemoteException e) { 228 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); 229 } catch (OperationApplicationException e) { 230 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); 231 } 232 } 233 234 private Uri lookupContact(String phone) { 235 Cursor c = null; 236 try { 237 Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, 238 Uri.encode(phone)); 239 String[] projection = new String[] { ContactsContract.Contacts._ID, 240 ContactsContract.Contacts.LOOKUP_KEY }; 241 c = mContext.getContentResolver().query(phoneUri, projection, null, null, null); 242 if (c != null && c.getCount() > 0) { 243 c.moveToFirst(); 244 int lookupIdx = c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY); 245 int idIdx = c.getColumnIndex(ContactsContract.Contacts._ID); 246 String lookupKey = c.getString(lookupIdx); 247 long contactId = c.getLong(idIdx); 248 return ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 249 } 250 } catch (Throwable t) { 251 Log.w(TAG, "Problem getting content resolver or performing contacts query.", t); 252 } finally { 253 if (c != null) { 254 c.close(); 255 } 256 } 257 return null; 258 } 259 260 261 private StatusBarNotification findPostedNotification(int id) { 262 // notification is a bit asynchronous so it may take a few ms to appear in 263 // getActiveNotifications() 264 // we will check for it for up to 300ms before giving up 265 StatusBarNotification n = null; 266 for (int tries = 3; tries-- > 0; ) { 267 final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 268 for (StatusBarNotification sbn : sbns) { 269 Log.d(TAG, "Found " + sbn.getKey()); 270 if (sbn.getId() == id) { 271 n = sbn; 272 break; 273 } 274 } 275 if (n != null) break; 276 try { 277 Thread.sleep(100); 278 } catch (InterruptedException ex) { 279 // pass 280 } 281 } 282 return n; 283 } 284 285 private PendingIntent getPendingIntent() { 286 return PendingIntent.getActivity( 287 getContext(), 0, new Intent(getContext(), this.getClass()), 0); 288 } 289 290 private boolean isGroupSummary(Notification n) { 291 return n.getGroup() != null && (n.flags & Notification.FLAG_GROUP_SUMMARY) != 0; 292 } 293 294 private void assertOnlySomeNotificationsAutogrouped(List<Integer> autoGroupedIds) { 295 String expectedGroupKey = null; 296 try { 297 // Posting can take ~100 ms 298 Thread.sleep(150); 299 } catch (InterruptedException e) { 300 e.printStackTrace(); 301 } 302 StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 303 for (StatusBarNotification sbn : sbns) { 304 if (isGroupSummary(sbn.getNotification()) 305 || autoGroupedIds.contains(sbn.getId())) { 306 assertTrue(sbn.getKey() + " is unexpectedly not autogrouped", 307 sbn.getOverrideGroupKey() != null); 308 if (expectedGroupKey == null) { 309 expectedGroupKey = sbn.getGroupKey(); 310 } 311 assertEquals(expectedGroupKey, sbn.getGroupKey()); 312 } else { 313 assertTrue(sbn.isGroup()); 314 assertTrue(sbn.getKey() + " is unexpectedly autogrouped,", 315 sbn.getOverrideGroupKey() == null); 316 assertTrue(sbn.getKey() + " has an unusual group key", 317 sbn.getGroupKey() != expectedGroupKey); 318 } 319 } 320 } 321 322 private void assertAllPostedNotificationsAutogrouped() { 323 String expectedGroupKey = null; 324 try { 325 // Posting can take ~100 ms 326 Thread.sleep(150); 327 } catch (InterruptedException e) { 328 e.printStackTrace(); 329 } 330 StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 331 for (StatusBarNotification sbn : sbns) { 332 // all notis should be in a group determined by autogrouping 333 assertTrue(sbn.getOverrideGroupKey() != null); 334 if (expectedGroupKey == null) { 335 expectedGroupKey = sbn.getGroupKey(); 336 } 337 // all notis should be in the same group 338 assertEquals(expectedGroupKey, sbn.getGroupKey()); 339 } 340 } 341 342 private void cancelAndPoll(int id) { 343 mNotificationManager.cancel(id); 344 345 if (!checkNotificationExistence(id, /*shouldExist=*/ false)) { 346 fail("canceled notification was still alive, id=" + id); 347 } 348 } 349 350 private void sendNotification(final int id, final int icon) throws Exception { 351 sendNotification(id, null, icon); 352 } 353 354 private void sendNotification(final int id, String groupKey, final int icon) throws Exception { 355 final Intent intent = new Intent(Intent.ACTION_MAIN, Threads.CONTENT_URI); 356 357 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP 358 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 359 intent.setAction(Intent.ACTION_MAIN); 360 361 final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0); 362 final Notification notification = 363 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 364 .setSmallIcon(icon) 365 .setWhen(System.currentTimeMillis()) 366 .setContentTitle("notify#" + id) 367 .setContentText("This is #" + id + "notification ") 368 .setContentIntent(pendingIntent) 369 .setGroup(groupKey) 370 .build(); 371 mNotificationManager.notify(id, notification); 372 373 if (!checkNotificationExistence(id, /*shouldExist=*/ true)) { 374 fail("couldn't find posted notification id=" + id); 375 } 376 } 377 378 private void sendAndVerifyBubble(final int id, Notification.Builder builder, 379 Notification.BubbleMetadata data, boolean shouldBeBubble) { 380 final Intent intent = new Intent(mContext, BubblesTestActivity.class); 381 382 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP 383 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 384 intent.setAction(Intent.ACTION_MAIN); 385 final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0); 386 387 if (data == null) { 388 data = new Notification.BubbleMetadata.Builder() 389 .setIcon(Icon.createWithResource(mContext, R.drawable.black)) 390 .setIntent(pendingIntent) 391 .build(); 392 } 393 if (builder == null) { 394 builder = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 395 .setSmallIcon(R.drawable.black) 396 .setWhen(System.currentTimeMillis()) 397 .setContentTitle("notify#" + id) 398 .setContentText("This is #" + id + "notification ") 399 .setContentIntent(pendingIntent); 400 } 401 builder.setBubbleMetadata(data); 402 403 Notification notif = builder.build(); 404 mNotificationManager.notify(id, notif); 405 406 if (!checkNotificationExistence(id, /*shouldExist=*/ true, shouldBeBubble)) { 407 fail("couldn't find posted notification bubble with id=" + id); 408 } 409 } 410 411 private boolean checkNotificationExistence(int id, boolean shouldExist) { 412 return checkNotificationExistence(id, shouldExist, false /* shouldBeBubble */); 413 } 414 415 private boolean checkNotificationExistence(int id, boolean shouldExist, 416 boolean shouldBeBubble) { 417 // notification is a bit asynchronous so it may take a few ms to appear in 418 // getActiveNotifications() 419 // we will check for it for up to 300ms before giving up 420 boolean found = false; 421 boolean isBubble = false; 422 for (int tries = 3; tries--> 0;) { 423 // Need reset flag. 424 found = false; 425 final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 426 for (StatusBarNotification sbn : sbns) { 427 isBubble = (sbn.getNotification().flags & FLAG_BUBBLE) != 0; 428 Log.d(TAG, "Found " + sbn.getKey() + " Bubble? " + isBubble); 429 if (sbn.getId() == id) { 430 found = true; 431 break; 432 } 433 } 434 if (found == shouldExist) break; 435 try { 436 Thread.sleep(100); 437 } catch (InterruptedException ex) { 438 // pass 439 } 440 } 441 return (found == shouldExist) && (isBubble == shouldBeBubble); 442 } 443 444 private void assertNotificationCount(int expectedCount) { 445 // notification is a bit asynchronous so it may take a few ms to appear in 446 // getActiveNotifications() 447 // we will check for it for up to 400ms before giving up 448 int lastCount = 0; 449 for (int tries = 4; tries-- > 0;) { 450 final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 451 lastCount = sbns.length; 452 if (expectedCount == lastCount) return; 453 try { 454 Thread.sleep(100); 455 } catch (InterruptedException ex) { 456 // pass 457 } 458 } 459 fail("Expected " + expectedCount + " posted notifications, were " + lastCount); 460 } 461 462 private void compareChannels(NotificationChannel expected, NotificationChannel actual) { 463 if (actual == null) { 464 fail("actual channel is null"); 465 return; 466 } 467 if (expected == null) { 468 fail("expected channel is null"); 469 return; 470 } 471 assertEquals(expected.getId(), actual.getId()); 472 assertEquals(expected.getName(), actual.getName()); 473 assertEquals(expected.getDescription(), actual.getDescription()); 474 assertEquals(expected.shouldVibrate(), actual.shouldVibrate()); 475 assertEquals(expected.shouldShowLights(), actual.shouldShowLights()); 476 assertEquals(expected.getImportance(), actual.getImportance()); 477 if (expected.getSound() == null) { 478 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actual.getSound()); 479 assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, actual.getAudioAttributes()); 480 } else { 481 assertEquals(expected.getSound(), actual.getSound()); 482 assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes()); 483 } 484 assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern())); 485 assertEquals(expected.getGroup(), actual.getGroup()); 486 } 487 488 private void toggleNotificationPolicyAccess(String packageName, 489 Instrumentation instrumentation, boolean on) throws IOException { 490 491 String command = " cmd notification " + (on ? "allow_dnd " : "disallow_dnd ") + packageName; 492 493 runCommand(command, instrumentation); 494 495 NotificationManager nm = mContext.getSystemService(NotificationManager.class); 496 Assert.assertEquals("Notification Policy Access Grant is " + 497 nm.isNotificationPolicyAccessGranted() + " not " + on, on, 498 nm.isNotificationPolicyAccessGranted()); 499 } 500 501 private void suspendPackage(String packageName, 502 Instrumentation instrumentation, boolean suspend) throws IOException { 503 int userId = mContext.getUserId(); 504 String command = " cmd package " + (suspend ? "suspend " : "unsuspend ") 505 + "--user " + userId + " " + packageName; 506 507 runCommand(command, instrumentation); 508 } 509 510 private void toggleListenerAccess(String componentName, Instrumentation instrumentation, 511 boolean on) throws IOException { 512 513 String command = " cmd notification " + (on ? "allow_listener " : "disallow_listener ") 514 + componentName; 515 516 runCommand(command, instrumentation); 517 518 final NotificationManager nm = mContext.getSystemService(NotificationManager.class); 519 final ComponentName listenerComponent = TestNotificationListener.getComponentName(); 520 assertTrue(listenerComponent + " has not been granted access", 521 nm.isNotificationListenerAccessGranted(listenerComponent) == on); 522 } 523 524 private void runCommand(String command, Instrumentation instrumentation) throws IOException { 525 UiAutomation uiAutomation = instrumentation.getUiAutomation(); 526 // Execute command 527 try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) { 528 Assert.assertNotNull("Failed to execute shell command: " + command, fd); 529 // Wait for the command to finish by reading until EOF 530 try (InputStream in = new FileInputStream(fd.getFileDescriptor())) { 531 byte[] buffer = new byte[4096]; 532 while (in.read(buffer) > 0) {} 533 } catch (IOException e) { 534 throw new IOException("Could not read stdout of command:" + command, e); 535 } 536 } finally { 537 uiAutomation.destroy(); 538 } 539 } 540 541 private boolean areRulesSame(AutomaticZenRule a, AutomaticZenRule b) { 542 return a.isEnabled() == b.isEnabled() 543 && Objects.equals(a.getName(), b.getName()) 544 && a.getInterruptionFilter() == b.getInterruptionFilter() 545 && Objects.equals(a.getConditionId(), b.getConditionId()) 546 && Objects.equals(a.getOwner(), b.getOwner()) 547 && Objects.equals(a.getZenPolicy(), b.getZenPolicy()) 548 && Objects.equals(a.getConfigurationActivity(), b.getConfigurationActivity()); 549 } 550 551 private AutomaticZenRule createRule(String name) { 552 return new AutomaticZenRule(name, null, 553 new ComponentName(mContext, AutomaticZenRuleActivity.class), 554 new Uri.Builder().scheme("scheme") 555 .appendPath("path") 556 .appendQueryParameter("fake_rule", "fake_value") 557 .build(), null, NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); 558 } 559 560 private void assertExpectedDndState(int expectedState) { 561 int tries = 3; 562 for (int i = tries; i >=0; i--) { 563 if (expectedState == 564 mNotificationManager.getCurrentInterruptionFilter()) { 565 break; 566 } 567 try { 568 Thread.sleep(100); 569 } catch (InterruptedException e) { 570 e.printStackTrace(); 571 } 572 } 573 574 assertEquals(expectedState, mNotificationManager.getCurrentInterruptionFilter()); 575 } 576 577 private Activity launchSendBubbleActivity() { 578 Class clazz = BubblesTestActivity.class; 579 580 Instrumentation.ActivityResult result = 581 new Instrumentation.ActivityResult(0, new Intent()); 582 Instrumentation.ActivityMonitor monitor = 583 new Instrumentation.ActivityMonitor(clazz.getName(), result, false); 584 InstrumentationRegistry.getInstrumentation().addMonitor(monitor); 585 586 Intent i = new Intent(mContext, BubblesTestActivity.class); 587 i.setFlags(FLAG_ACTIVITY_NEW_TASK); 588 InstrumentationRegistry.getInstrumentation().startActivitySync(i); 589 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 590 591 return monitor.waitForActivity(); 592 } 593 594 private class HomeHelper extends ActivityManagerTestBase implements AutoCloseable { 595 596 HomeHelper() throws Exception { 597 setUp(); 598 } 599 600 public void goHome() { 601 launchHomeActivity(); 602 } 603 604 @Override 605 public void close() throws Exception { 606 tearDown(); 607 } 608 } 609 610 public void testPostPCanToggleAlarmsMediaSystemTest() throws Exception { 611 if (mActivityManager.isLowRamDevice()) { 612 return; 613 } 614 615 toggleNotificationPolicyAccess(mContext.getPackageName(), 616 InstrumentationRegistry.getInstrumentation(), true); 617 618 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { 619 // Post-P can toggle alarms, media, system 620 // toggle on alarms, media, system: 621 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy( 622 NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS 623 | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA 624 | NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM, 0, 0)); 625 NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy(); 626 assertTrue((policy.priorityCategories 627 & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) != 0); 628 assertTrue((policy.priorityCategories 629 & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA) != 0); 630 assertTrue((policy.priorityCategories 631 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) != 0); 632 633 // toggle off alarms, media, system 634 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0)); 635 policy = mNotificationManager.getNotificationPolicy(); 636 assertTrue((policy.priorityCategories 637 & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) == 0); 638 assertTrue((policy.priorityCategories & 639 NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA) == 0); 640 assertTrue((policy.priorityCategories & 641 NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0); 642 } 643 } 644 645 public void testCreateChannelGroup() throws Exception { 646 final NotificationChannelGroup ncg = new NotificationChannelGroup("a group", "a label"); 647 final NotificationChannel channel = 648 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 649 channel.setGroup(ncg.getId()); 650 mNotificationManager.createNotificationChannelGroup(ncg); 651 final NotificationChannel ungrouped = 652 new NotificationChannel(mId + "!", "name", NotificationManager.IMPORTANCE_DEFAULT); 653 try { 654 mNotificationManager.createNotificationChannel(channel); 655 mNotificationManager.createNotificationChannel(ungrouped); 656 657 List<NotificationChannelGroup> ncgs = 658 mNotificationManager.getNotificationChannelGroups(); 659 assertEquals(1, ncgs.size()); 660 assertEquals(ncg.getName(), ncgs.get(0).getName()); 661 assertEquals(ncg.getDescription(), ncgs.get(0).getDescription()); 662 assertEquals(channel.getId(), ncgs.get(0).getChannels().get(0).getId()); 663 } finally { 664 mNotificationManager.deleteNotificationChannelGroup(ncg.getId()); 665 } 666 } 667 668 public void testGetChannelGroup() throws Exception { 669 final NotificationChannelGroup ncg = new NotificationChannelGroup("a group", "a label"); 670 ncg.setDescription("bananas"); 671 final NotificationChannelGroup ncg2 = new NotificationChannelGroup("group 2", "label 2"); 672 final NotificationChannel channel = 673 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 674 channel.setGroup(ncg.getId()); 675 676 mNotificationManager.createNotificationChannelGroup(ncg); 677 mNotificationManager.createNotificationChannelGroup(ncg2); 678 mNotificationManager.createNotificationChannel(channel); 679 680 NotificationChannelGroup actual = 681 mNotificationManager.getNotificationChannelGroup(ncg.getId()); 682 assertEquals(ncg.getId(), actual.getId()); 683 assertEquals(ncg.getName(), actual.getName()); 684 assertEquals(ncg.getDescription(), actual.getDescription()); 685 assertEquals(channel.getId(), actual.getChannels().get(0).getId()); 686 } 687 688 public void testGetChannelGroups() throws Exception { 689 final NotificationChannelGroup ncg = new NotificationChannelGroup("a group", "a label"); 690 ncg.setDescription("bananas"); 691 final NotificationChannelGroup ncg2 = new NotificationChannelGroup("group 2", "label 2"); 692 final NotificationChannel channel = 693 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 694 channel.setGroup(ncg2.getId()); 695 696 mNotificationManager.createNotificationChannelGroup(ncg); 697 mNotificationManager.createNotificationChannelGroup(ncg2); 698 mNotificationManager.createNotificationChannel(channel); 699 700 List<NotificationChannelGroup> actual = 701 mNotificationManager.getNotificationChannelGroups(); 702 assertEquals(2, actual.size()); 703 for (NotificationChannelGroup group : actual) { 704 if (group.getId().equals(ncg.getId())) { 705 assertEquals(group.getName(), ncg.getName()); 706 assertEquals(group.getDescription(), ncg.getDescription()); 707 assertEquals(0, group.getChannels().size()); 708 } else if (group.getId().equals(ncg2.getId())) { 709 assertEquals(group.getName(), ncg2.getName()); 710 assertEquals(group.getDescription(), ncg2.getDescription()); 711 assertEquals(1, group.getChannels().size()); 712 assertEquals(channel.getId(), group.getChannels().get(0).getId()); 713 } else { 714 fail("Extra group found " + group.getId()); 715 } 716 } 717 } 718 719 public void testDeleteChannelGroup() throws Exception { 720 final NotificationChannelGroup ncg = new NotificationChannelGroup("a group", "a label"); 721 final NotificationChannel channel = 722 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 723 channel.setGroup(ncg.getId()); 724 mNotificationManager.createNotificationChannelGroup(ncg); 725 mNotificationManager.createNotificationChannel(channel); 726 727 mNotificationManager.deleteNotificationChannelGroup(ncg.getId()); 728 729 assertNull(mNotificationManager.getNotificationChannel(channel.getId())); 730 assertEquals(0, mNotificationManager.getNotificationChannelGroups().size()); 731 } 732 733 public void testCreateChannel() throws Exception { 734 final NotificationChannel channel = 735 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 736 channel.setDescription("bananas"); 737 channel.enableVibration(true); 738 channel.setVibrationPattern(new long[] {5, 8, 2, 1}); 739 channel.setSound(new Uri.Builder().scheme("test").build(), 740 new AudioAttributes.Builder().setUsage( 741 AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED).build()); 742 channel.enableLights(true); 743 channel.setBypassDnd(true); 744 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 745 mNotificationManager.createNotificationChannel(channel); 746 final NotificationChannel createdChannel = 747 mNotificationManager.getNotificationChannel(mId); 748 compareChannels(channel, createdChannel); 749 // Lockscreen Visibility and canBypassDnd no longer settable. 750 assertTrue(createdChannel.getLockscreenVisibility() != Notification.VISIBILITY_SECRET); 751 assertFalse(createdChannel.canBypassDnd()); 752 } 753 754 public void testCreateChannel_rename() throws Exception { 755 NotificationChannel channel = 756 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 757 mNotificationManager.createNotificationChannel(channel); 758 channel.setName("new name"); 759 mNotificationManager.createNotificationChannel(channel); 760 final NotificationChannel createdChannel = 761 mNotificationManager.getNotificationChannel(mId); 762 compareChannels(channel, createdChannel); 763 764 channel.setImportance(NotificationManager.IMPORTANCE_HIGH); 765 mNotificationManager.createNotificationChannel(channel); 766 assertEquals(NotificationManager.IMPORTANCE_DEFAULT, 767 mNotificationManager.getNotificationChannel(mId).getImportance()); 768 } 769 770 public void testCreateChannel_addToGroup() throws Exception { 771 String oldGroup = null; 772 String newGroup = "new group"; 773 mNotificationManager.createNotificationChannelGroup( 774 new NotificationChannelGroup(newGroup, newGroup)); 775 776 NotificationChannel channel = 777 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 778 channel.setGroup(oldGroup); 779 mNotificationManager.createNotificationChannel(channel); 780 781 channel.setGroup(newGroup); 782 mNotificationManager.createNotificationChannel(channel); 783 784 final NotificationChannel updatedChannel = 785 mNotificationManager.getNotificationChannel(mId); 786 assertEquals("Failed to add non-grouped channel to a group on update ", 787 newGroup, updatedChannel.getGroup()); 788 } 789 790 public void testCreateChannel_cannotChangeGroup() throws Exception { 791 String oldGroup = "old group"; 792 String newGroup = "new group"; 793 mNotificationManager.createNotificationChannelGroup( 794 new NotificationChannelGroup(oldGroup, oldGroup)); 795 mNotificationManager.createNotificationChannelGroup( 796 new NotificationChannelGroup(newGroup, newGroup)); 797 798 NotificationChannel channel = 799 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 800 channel.setGroup(oldGroup); 801 mNotificationManager.createNotificationChannel(channel); 802 channel.setGroup(newGroup); 803 mNotificationManager.createNotificationChannel(channel); 804 final NotificationChannel updatedChannel = 805 mNotificationManager.getNotificationChannel(mId); 806 assertEquals("Channels should not be allowed to change groups", 807 oldGroup, updatedChannel.getGroup()); 808 } 809 810 public void testCreateSameChannelDoesNotUpdate() throws Exception { 811 final NotificationChannel channel = 812 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 813 mNotificationManager.createNotificationChannel(channel); 814 final NotificationChannel channelDupe = 815 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_HIGH); 816 mNotificationManager.createNotificationChannel(channelDupe); 817 final NotificationChannel createdChannel = 818 mNotificationManager.getNotificationChannel(mId); 819 compareChannels(channel, createdChannel); 820 } 821 822 public void testCreateChannelAlreadyExistsNoOp() throws Exception { 823 NotificationChannel channel = 824 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 825 mNotificationManager.createNotificationChannel(channel); 826 NotificationChannel channelDupe = 827 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_HIGH); 828 mNotificationManager.createNotificationChannel(channelDupe); 829 compareChannels(channel, mNotificationManager.getNotificationChannel(channel.getId())); 830 } 831 832 public void testCreateChannelWithGroup() throws Exception { 833 NotificationChannelGroup ncg = new NotificationChannelGroup("g", "n"); 834 mNotificationManager.createNotificationChannelGroup(ncg); 835 try { 836 NotificationChannel channel = 837 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 838 channel.setGroup(ncg.getId()); 839 mNotificationManager.createNotificationChannel(channel); 840 compareChannels(channel, mNotificationManager.getNotificationChannel(channel.getId())); 841 } finally { 842 mNotificationManager.deleteNotificationChannelGroup(ncg.getId()); 843 } 844 } 845 846 public void testCreateChannelWithBadGroup() throws Exception { 847 NotificationChannel channel = 848 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 849 channel.setGroup("garbage"); 850 try { 851 mNotificationManager.createNotificationChannel(channel); 852 fail("Created notification with bad group"); 853 } catch (IllegalArgumentException e) {} 854 } 855 856 public void testCreateChannelInvalidImportance() throws Exception { 857 NotificationChannel channel = 858 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_UNSPECIFIED); 859 try { 860 mNotificationManager.createNotificationChannel(channel); 861 } catch (IllegalArgumentException e) { 862 //success 863 } 864 } 865 866 public void testDeleteChannel() throws Exception { 867 NotificationChannel channel = 868 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_LOW); 869 mNotificationManager.createNotificationChannel(channel); 870 compareChannels(channel, mNotificationManager.getNotificationChannel(channel.getId())); 871 mNotificationManager.deleteNotificationChannel(channel.getId()); 872 assertNull(mNotificationManager.getNotificationChannel(channel.getId())); 873 } 874 875 public void testCannotDeleteDefaultChannel() throws Exception { 876 try { 877 mNotificationManager.deleteNotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID); 878 fail("Deleted default channel"); 879 } catch (IllegalArgumentException e) { 880 //success 881 } 882 } 883 884 public void testGetChannel() throws Exception { 885 NotificationChannel channel1 = 886 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 887 NotificationChannel channel2 = 888 new NotificationChannel( 889 UUID.randomUUID().toString(), "name2", NotificationManager.IMPORTANCE_HIGH); 890 NotificationChannel channel3 = 891 new NotificationChannel( 892 UUID.randomUUID().toString(), "name3", NotificationManager.IMPORTANCE_LOW); 893 NotificationChannel channel4 = 894 new NotificationChannel( 895 UUID.randomUUID().toString(), "name4", NotificationManager.IMPORTANCE_MIN); 896 mNotificationManager.createNotificationChannel(channel1); 897 mNotificationManager.createNotificationChannel(channel2); 898 mNotificationManager.createNotificationChannel(channel3); 899 mNotificationManager.createNotificationChannel(channel4); 900 901 compareChannels(channel2, 902 mNotificationManager.getNotificationChannel(channel2.getId())); 903 compareChannels(channel3, 904 mNotificationManager.getNotificationChannel(channel3.getId())); 905 compareChannels(channel1, 906 mNotificationManager.getNotificationChannel(channel1.getId())); 907 compareChannels(channel4, 908 mNotificationManager.getNotificationChannel(channel4.getId())); 909 } 910 911 public void testGetChannels() throws Exception { 912 NotificationChannel channel1 = 913 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 914 NotificationChannel channel2 = 915 new NotificationChannel( 916 UUID.randomUUID().toString(), "name2", NotificationManager.IMPORTANCE_HIGH); 917 NotificationChannel channel3 = 918 new NotificationChannel( 919 UUID.randomUUID().toString(), "name3", NotificationManager.IMPORTANCE_LOW); 920 NotificationChannel channel4 = 921 new NotificationChannel( 922 UUID.randomUUID().toString(), "name4", NotificationManager.IMPORTANCE_MIN); 923 924 Map<String, NotificationChannel> channelMap = new HashMap<>(); 925 channelMap.put(channel1.getId(), channel1); 926 channelMap.put(channel2.getId(), channel2); 927 channelMap.put(channel3.getId(), channel3); 928 channelMap.put(channel4.getId(), channel4); 929 mNotificationManager.createNotificationChannel(channel1); 930 mNotificationManager.createNotificationChannel(channel2); 931 mNotificationManager.createNotificationChannel(channel3); 932 mNotificationManager.createNotificationChannel(channel4); 933 934 mNotificationManager.deleteNotificationChannel(channel3.getId()); 935 936 List<NotificationChannel> channels = mNotificationManager.getNotificationChannels(); 937 for (NotificationChannel nc : channels) { 938 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 939 continue; 940 } 941 if (NOTIFICATION_CHANNEL_ID.equals(nc.getId())) { 942 continue; 943 } 944 assertFalse(channel3.getId().equals(nc.getId())); 945 if (!channelMap.containsKey(nc.getId())) { 946 // failed cleanup from prior test run; ignore 947 continue; 948 } 949 compareChannels(channelMap.get(nc.getId()), nc); 950 } 951 } 952 953 public void testRecreateDeletedChannel() throws Exception { 954 NotificationChannel channel = 955 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 956 channel.setShowBadge(true); 957 NotificationChannel newChannel = new NotificationChannel( 958 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 959 mNotificationManager.createNotificationChannel(channel); 960 mNotificationManager.deleteNotificationChannel(channel.getId()); 961 962 mNotificationManager.createNotificationChannel(newChannel); 963 964 compareChannels(channel, 965 mNotificationManager.getNotificationChannel(newChannel.getId())); 966 } 967 968 public void testNotify() throws Exception { 969 mNotificationManager.cancelAll(); 970 971 final int id = 1; 972 sendNotification(id, R.drawable.black); 973 // test updating the same notification 974 sendNotification(id, R.drawable.blue); 975 sendNotification(id, R.drawable.yellow); 976 977 // assume that sendNotification tested to make sure individual notifications were present 978 StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 979 for (StatusBarNotification sbn : sbns) { 980 if (sbn.getId() != id) { 981 fail("we got back other notifications besides the one we posted: " 982 + sbn.getKey()); 983 } 984 } 985 } 986 987 public void testSuspendPackage() throws Exception { 988 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 989 return; 990 } 991 992 toggleListenerAccess(TestNotificationListener.getId(), 993 InstrumentationRegistry.getInstrumentation(), true); 994 Thread.sleep(500); // wait for listener to be allowed 995 996 mListener = TestNotificationListener.getInstance(); 997 assertNotNull(mListener); 998 999 sendNotification(1, R.drawable.black); 1000 Thread.sleep(500); // wait for notification listener to receive notification 1001 assertEquals(1, mListener.mPosted.size()); 1002 1003 // suspend package, ranking should be updated with suspended = true 1004 suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(), 1005 true); 1006 Thread.sleep(500); // wait for notification listener to get response 1007 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1008 NotificationListenerService.Ranking outRanking = new NotificationListenerService.Ranking(); 1009 for (String key : rankingMap.getOrderedKeys()) { 1010 if (key.contains(mListener.getPackageName())) { 1011 rankingMap.getRanking(key, outRanking); 1012 Log.d(TAG, "key=" + key + " suspended=" + outRanking.isSuspended()); 1013 assertTrue(outRanking.isSuspended()); 1014 } 1015 } 1016 1017 // unsuspend package, ranking should be updated with suspended = false 1018 suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(), 1019 false); 1020 Thread.sleep(500); // wait for notification listener to get response 1021 rankingMap = mListener.mRankingMap; 1022 for (String key : rankingMap.getOrderedKeys()) { 1023 if (key.contains(mListener.getPackageName())) { 1024 rankingMap.getRanking(key, outRanking); 1025 Log.d(TAG, "key=" + key + " suspended=" + outRanking.isSuspended()); 1026 assertFalse(outRanking.isSuspended()); 1027 } 1028 } 1029 1030 mListener.resetData(); 1031 } 1032 1033 public void testSuspendedPackageSendsNotification() throws Exception { 1034 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 1035 return; 1036 } 1037 1038 toggleListenerAccess(TestNotificationListener.getId(), 1039 InstrumentationRegistry.getInstrumentation(), true); 1040 Thread.sleep(500); // wait for listener to be allowed 1041 1042 mListener = TestNotificationListener.getInstance(); 1043 assertNotNull(mListener); 1044 1045 // suspend package, post notification while package is suspended, see notification 1046 // in ranking map with suspended = true 1047 suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(), 1048 true); 1049 sendNotification(1, R.drawable.black); 1050 Thread.sleep(500); // wait for notification listener to receive notification 1051 assertEquals(1, mListener.mPosted.size()); // apps targeting P receive notification 1052 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1053 NotificationListenerService.Ranking outRanking = new NotificationListenerService.Ranking(); 1054 for (String key : rankingMap.getOrderedKeys()) { 1055 if (key.contains(mListener.getPackageName())) { 1056 rankingMap.getRanking(key, outRanking); 1057 Log.d(TAG, "key=" + key + " suspended=" + outRanking.isSuspended()); 1058 assertTrue(outRanking.isSuspended()); 1059 } 1060 } 1061 1062 // unsuspend package, ranking should be updated with suspended = false 1063 suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(), 1064 false); 1065 Thread.sleep(500); // wait for notification listener to get response 1066 assertEquals(1, mListener.mPosted.size()); // should see previously posted notification 1067 rankingMap = mListener.mRankingMap; 1068 for (String key : rankingMap.getOrderedKeys()) { 1069 if (key.contains(mListener.getPackageName())) { 1070 rankingMap.getRanking(key, outRanking); 1071 Log.d(TAG, "key=" + key + " suspended=" + outRanking.isSuspended()); 1072 assertFalse(outRanking.isSuspended()); 1073 } 1074 } 1075 1076 mListener.resetData(); 1077 } 1078 1079 public void testCanBubble_ranking() throws Exception { 1080 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 1081 return; 1082 } 1083 1084 // turn on bubbles globally 1085 toggleBubbleSetting(true); 1086 1087 assertEquals(1, Settings.Secure.getInt( 1088 mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BUBBLES)); 1089 1090 toggleListenerAccess(TestNotificationListener.getId(), 1091 InstrumentationRegistry.getInstrumentation(), true); 1092 Thread.sleep(500); // wait for listener to be allowed 1093 1094 mListener = TestNotificationListener.getInstance(); 1095 assertNotNull(mListener); 1096 try { 1097 sendNotification(1, R.drawable.black); 1098 Thread.sleep(500); // wait for notification listener to receive notification 1099 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1100 NotificationListenerService.Ranking outRanking = 1101 new NotificationListenerService.Ranking(); 1102 for (String key : rankingMap.getOrderedKeys()) { 1103 if (key.contains(mListener.getPackageName())) { 1104 rankingMap.getRanking(key, outRanking); 1105 // by default everything can bubble 1106 assertTrue(outRanking.canBubble()); 1107 } 1108 } 1109 1110 // turn off bubbles globally 1111 toggleBubbleSetting(false); 1112 1113 rankingMap = mListener.mRankingMap; 1114 outRanking = new NotificationListenerService.Ranking(); 1115 for (String key : rankingMap.getOrderedKeys()) { 1116 if (key.contains(mListener.getPackageName())) { 1117 rankingMap.getRanking(key, outRanking); 1118 assertFalse(outRanking.canBubble()); 1119 } 1120 } 1121 1122 mListener.resetData(); 1123 } finally { 1124 // turn off bubbles globally 1125 toggleBubbleSetting(false); 1126 } 1127 } 1128 1129 public void testShowBadging_ranking() throws Exception { 1130 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 1131 return; 1132 } 1133 1134 final int originalBadging = Settings.Secure.getInt( 1135 mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING); 1136 1137 SystemUtil.runWithShellPermissionIdentity(() -> 1138 Settings.Secure.putInt(mContext.getContentResolver(), 1139 Settings.Secure.NOTIFICATION_BADGING, 1)); 1140 assertEquals(1, Settings.Secure.getInt( 1141 mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING)); 1142 1143 toggleListenerAccess(TestNotificationListener.getId(), 1144 InstrumentationRegistry.getInstrumentation(), true); 1145 Thread.sleep(500); // wait for listener to be allowed 1146 1147 mListener = TestNotificationListener.getInstance(); 1148 assertNotNull(mListener); 1149 try { 1150 sendNotification(1, R.drawable.black); 1151 Thread.sleep(500); // wait for notification listener to receive notification 1152 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1153 NotificationListenerService.Ranking outRanking = 1154 new NotificationListenerService.Ranking(); 1155 for (String key : rankingMap.getOrderedKeys()) { 1156 if (key.contains(mListener.getPackageName())) { 1157 rankingMap.getRanking(key, outRanking); 1158 assertTrue(outRanking.canShowBadge()); 1159 } 1160 } 1161 1162 // turn off badging globally 1163 SystemUtil.runWithShellPermissionIdentity(() -> 1164 Settings.Secure.putInt(mContext.getContentResolver(), 1165 Settings.Secure.NOTIFICATION_BADGING, 0)); 1166 1167 Thread.sleep(500); // wait for ranking update 1168 1169 rankingMap = mListener.mRankingMap; 1170 outRanking = new NotificationListenerService.Ranking(); 1171 for (String key : rankingMap.getOrderedKeys()) { 1172 if (key.contains(mListener.getPackageName())) { 1173 assertFalse(outRanking.canShowBadge()); 1174 } 1175 } 1176 1177 mListener.resetData(); 1178 } finally { 1179 SystemUtil.runWithShellPermissionIdentity(() -> 1180 Settings.Secure.putInt(mContext.getContentResolver(), 1181 Settings.Secure.NOTIFICATION_BADGING, originalBadging)); 1182 } 1183 } 1184 1185 public void testGetSuppressedVisualEffectsOff_ranking() throws Exception { 1186 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 1187 return; 1188 } 1189 1190 toggleListenerAccess(TestNotificationListener.getId(), 1191 InstrumentationRegistry.getInstrumentation(), true); 1192 Thread.sleep(500); // wait for listener to be allowed 1193 1194 mListener = TestNotificationListener.getInstance(); 1195 assertNotNull(mListener); 1196 1197 final int notificationId = 1; 1198 sendNotification(notificationId, R.drawable.black); 1199 Thread.sleep(500); // wait for notification listener to receive notification 1200 1201 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1202 NotificationListenerService.Ranking outRanking = 1203 new NotificationListenerService.Ranking(); 1204 1205 for (String key : rankingMap.getOrderedKeys()) { 1206 if (key.contains(mListener.getPackageName())) { 1207 rankingMap.getRanking(key, outRanking); 1208 1209 // check notification key match 1210 assertEquals(0, outRanking.getSuppressedVisualEffects()); 1211 } 1212 } 1213 } 1214 1215 public void testGetSuppressedVisualEffects_ranking() throws Exception { 1216 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 1217 return; 1218 } 1219 1220 final int originalFilter = mNotificationManager.getCurrentInterruptionFilter(); 1221 try { 1222 toggleListenerAccess(TestNotificationListener.getId(), 1223 InstrumentationRegistry.getInstrumentation(), true); 1224 Thread.sleep(500); // wait for listener to be allowed 1225 1226 mListener = TestNotificationListener.getInstance(); 1227 assertNotNull(mListener); 1228 1229 toggleNotificationPolicyAccess(mContext.getPackageName(), 1230 InstrumentationRegistry.getInstrumentation(), true); 1231 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { 1232 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0, 1233 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK)); 1234 } else { 1235 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0, 1236 SUPPRESSED_EFFECT_SCREEN_ON)); 1237 } 1238 mNotificationManager.setInterruptionFilter( 1239 NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1240 1241 final int notificationId = 1; 1242 // update notification 1243 sendNotification(notificationId, R.drawable.black); 1244 Thread.sleep(500); // wait for notification listener to receive notification 1245 1246 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1247 NotificationListenerService.Ranking outRanking = 1248 new NotificationListenerService.Ranking(); 1249 1250 for (String key : rankingMap.getOrderedKeys()) { 1251 if (key.contains(mListener.getPackageName())) { 1252 rankingMap.getRanking(key, outRanking); 1253 1254 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { 1255 assertEquals(SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK, 1256 outRanking.getSuppressedVisualEffects()); 1257 } else { 1258 assertEquals(SUPPRESSED_EFFECT_SCREEN_ON, 1259 outRanking.getSuppressedVisualEffects()); 1260 } 1261 } 1262 } 1263 } finally { 1264 // reset notification policy 1265 mNotificationManager.setInterruptionFilter(originalFilter); 1266 } 1267 1268 } 1269 1270 public void testKeyChannelGroupOverrideImportanceExplanation_ranking() throws Exception { 1271 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 1272 return; 1273 } 1274 1275 toggleListenerAccess(TestNotificationListener.getId(), 1276 InstrumentationRegistry.getInstrumentation(), true); 1277 Thread.sleep(500); // wait for listener to be allowed 1278 1279 mListener = TestNotificationListener.getInstance(); 1280 assertNotNull(mListener); 1281 1282 final int notificationId = 1; 1283 sendNotification(notificationId, R.drawable.black); 1284 Thread.sleep(500); // wait for notification listener to receive notification 1285 1286 NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap; 1287 NotificationListenerService.Ranking outRanking = 1288 new NotificationListenerService.Ranking(); 1289 1290 StatusBarNotification sbn = findPostedNotification(notificationId); 1291 1292 // check that the key and channel ids are the same in the ranking as the posted notification 1293 for (String key : rankingMap.getOrderedKeys()) { 1294 if (key.contains(mListener.getPackageName())) { 1295 rankingMap.getRanking(key, outRanking); 1296 1297 // check notification key match 1298 assertEquals(sbn.getKey(), outRanking.getKey()); 1299 1300 // check notification channel ids match 1301 assertEquals(sbn.getNotification().getChannelId(), outRanking.getChannel().getId()); 1302 1303 // check override group key match 1304 assertEquals(sbn.getOverrideGroupKey(), outRanking.getOverrideGroupKey()); 1305 1306 // check importance explanation isn't null 1307 assertNotNull(outRanking.getImportanceExplanation()); 1308 } 1309 } 1310 } 1311 1312 public void testNotify_blockedChannel() throws Exception { 1313 mNotificationManager.cancelAll(); 1314 1315 NotificationChannel channel = 1316 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_NONE); 1317 mNotificationManager.createNotificationChannel(channel); 1318 1319 int id = 1; 1320 final Notification notification = 1321 new Notification.Builder(mContext, mId) 1322 .setSmallIcon(R.drawable.black) 1323 .setWhen(System.currentTimeMillis()) 1324 .setContentTitle("notify#" + id) 1325 .setContentText("This is #" + id + "notification ") 1326 .build(); 1327 mNotificationManager.notify(id, notification); 1328 1329 if (!checkNotificationExistence(id, /*shouldExist=*/ false)) { 1330 fail("found unexpected notification id=" + id); 1331 } 1332 } 1333 1334 public void testNotify_blockedChannelGroup() throws Exception { 1335 mNotificationManager.cancelAll(); 1336 1337 NotificationChannelGroup group = new NotificationChannelGroup(mId, "group name"); 1338 group.setBlocked(true); 1339 mNotificationManager.createNotificationChannelGroup(group); 1340 NotificationChannel channel = 1341 new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT); 1342 channel.setGroup(mId); 1343 mNotificationManager.createNotificationChannel(channel); 1344 1345 int id = 1; 1346 final Notification notification = 1347 new Notification.Builder(mContext, mId) 1348 .setSmallIcon(R.drawable.black) 1349 .setWhen(System.currentTimeMillis()) 1350 .setContentTitle("notify#" + id) 1351 .setContentText("This is #" + id + "notification ") 1352 .build(); 1353 mNotificationManager.notify(id, notification); 1354 1355 if (!checkNotificationExistence(id, /*shouldExist=*/ false)) { 1356 fail("found unexpected notification id=" + id); 1357 } 1358 } 1359 1360 public void testCancel() throws Exception { 1361 final int id = 9; 1362 sendNotification(id, R.drawable.black); 1363 mNotificationManager.cancel(id); 1364 1365 if (!checkNotificationExistence(id, /*shouldExist=*/ false)) { 1366 fail("canceled notification was still alive, id=" + id); 1367 } 1368 } 1369 1370 public void testCancelAll() throws Exception { 1371 sendNotification(1, R.drawable.black); 1372 sendNotification(2, R.drawable.blue); 1373 sendNotification(3, R.drawable.yellow); 1374 1375 if (DEBUG) { 1376 Log.d(TAG, "posted 3 notifications, here they are: "); 1377 StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications(); 1378 for (StatusBarNotification sbn : sbns) { 1379 Log.d(TAG, " " + sbn); 1380 } 1381 Log.d(TAG, "about to cancel..."); 1382 } 1383 mNotificationManager.cancelAll(); 1384 1385 for (int id = 1; id <= 3; id++) { 1386 if (!checkNotificationExistence(id, /*shouldExist=*/ false)) { 1387 fail("Failed to cancel notification id=" + id); 1388 } 1389 } 1390 1391 } 1392 1393 public void testNotifyWithTimeout() throws Exception { 1394 mNotificationManager.cancelAll(); 1395 final int id = 128; 1396 final long timeout = 1000; 1397 1398 final Notification notification = 1399 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 1400 .setSmallIcon(R.drawable.black) 1401 .setContentTitle("notify#" + id) 1402 .setContentText("This is #" + id + "notification ") 1403 .setTimeoutAfter(timeout) 1404 .build(); 1405 mNotificationManager.notify(id, notification); 1406 1407 if (!checkNotificationExistence(id, /*shouldExist=*/ true)) { 1408 fail("couldn't find posted notification id=" + id); 1409 } 1410 1411 try { 1412 Thread.sleep(timeout); 1413 } catch (InterruptedException ex) { 1414 // pass 1415 } 1416 checkNotificationExistence(id, false); 1417 } 1418 1419 public void testStyle() throws Exception { 1420 Notification.Style style = new Notification.Style() { 1421 public boolean areNotificationsVisiblyDifferent(Notification.Style other) { 1422 return false; 1423 } 1424 }; 1425 1426 Notification.Builder builder = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID); 1427 style.setBuilder(builder); 1428 1429 Notification notification = null; 1430 try { 1431 notification = style.build(); 1432 } catch (IllegalArgumentException e) { 1433 fail(e.getMessage()); 1434 } 1435 1436 assertNotNull(notification); 1437 1438 Notification builderNotification = builder.build(); 1439 assertEquals(builderNotification, notification); 1440 } 1441 1442 public void testStyle_getStandardView() throws Exception { 1443 Notification.Builder builder = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID); 1444 int layoutId = 0; 1445 1446 TestStyle overrideStyle = new TestStyle(); 1447 overrideStyle.setBuilder(builder); 1448 RemoteViews result = overrideStyle.testGetStandardView(layoutId); 1449 1450 assertNotNull(result); 1451 assertEquals(layoutId, result.getLayoutId()); 1452 } 1453 1454 private class TestStyle extends Notification.Style { 1455 public boolean areNotificationsVisiblyDifferent(Notification.Style other) { 1456 return false; 1457 } 1458 1459 public RemoteViews testGetStandardView(int layoutId) { 1460 // Wrapper method, since getStandardView is protected and otherwise unused in Android 1461 return getStandardView(layoutId); 1462 } 1463 } 1464 1465 public void testMediaStyle_empty() throws Exception { 1466 Notification.MediaStyle style = new Notification.MediaStyle(); 1467 assertNotNull(style); 1468 } 1469 1470 public void testMediaStyle() throws Exception { 1471 mNotificationManager.cancelAll(); 1472 final int id = 99; 1473 MediaSession session = new MediaSession(getContext(), "media"); 1474 1475 final Notification notification = 1476 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 1477 .setSmallIcon(R.drawable.black) 1478 .setContentTitle("notify#" + id) 1479 .setContentText("This is #" + id + "notification ") 1480 .addAction(new Notification.Action.Builder( 1481 Icon.createWithResource(getContext(), R.drawable.icon_black), 1482 "play", getPendingIntent()).build()) 1483 .addAction(new Notification.Action.Builder( 1484 Icon.createWithResource(getContext(), R.drawable.icon_blue), 1485 "pause", getPendingIntent()).build()) 1486 .setStyle(new Notification.MediaStyle() 1487 .setShowActionsInCompactView(0, 1) 1488 .setMediaSession(session.getSessionToken())) 1489 .build(); 1490 mNotificationManager.notify(id, notification); 1491 1492 if (!checkNotificationExistence(id, /*shouldExist=*/ true)) { 1493 fail("couldn't find posted notification id=" + id); 1494 } 1495 } 1496 1497 public void testInboxStyle() throws Exception { 1498 final int id = 100; 1499 1500 final Notification notification = 1501 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 1502 .setSmallIcon(R.drawable.black) 1503 .setContentTitle("notify#" + id) 1504 .setContentText("This is #" + id + "notification ") 1505 .addAction(new Notification.Action.Builder( 1506 Icon.createWithResource(getContext(), R.drawable.icon_black), 1507 "a1", getPendingIntent()).build()) 1508 .addAction(new Notification.Action.Builder( 1509 Icon.createWithResource(getContext(), R.drawable.icon_blue), 1510 "a2", getPendingIntent()).build()) 1511 .setStyle(new Notification.InboxStyle().addLine("line") 1512 .setSummaryText("summary")) 1513 .build(); 1514 mNotificationManager.notify(id, notification); 1515 1516 if (!checkNotificationExistence(id, /*shouldExist=*/ true)) { 1517 fail("couldn't find posted notification id=" + id); 1518 } 1519 } 1520 1521 public void testBigTextStyle() throws Exception { 1522 final int id = 101; 1523 1524 final Notification notification = 1525 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 1526 .setSmallIcon(R.drawable.black) 1527 .setContentTitle("notify#" + id) 1528 .setContentText("This is #" + id + "notification ") 1529 .addAction(new Notification.Action.Builder( 1530 Icon.createWithResource(getContext(), R.drawable.icon_black), 1531 "a1", getPendingIntent()).build()) 1532 .addAction(new Notification.Action.Builder( 1533 Icon.createWithResource(getContext(), R.drawable.icon_blue), 1534 "a2", getPendingIntent()).build()) 1535 .setStyle(new Notification.BigTextStyle() 1536 .setBigContentTitle("big title") 1537 .bigText("big text") 1538 .setSummaryText("summary")) 1539 .build(); 1540 mNotificationManager.notify(id, notification); 1541 1542 if (!checkNotificationExistence(id, /*shouldExist=*/ true)) { 1543 fail("couldn't find posted notification id=" + id); 1544 } 1545 } 1546 1547 public void testBigPictureStyle() throws Exception { 1548 final int id = 102; 1549 1550 final Notification notification = 1551 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 1552 .setSmallIcon(R.drawable.black) 1553 .setContentTitle("notify#" + id) 1554 .setContentText("This is #" + id + "notification ") 1555 .addAction(new Notification.Action.Builder( 1556 Icon.createWithResource(getContext(), R.drawable.icon_black), 1557 "a1", getPendingIntent()).build()) 1558 .addAction(new Notification.Action.Builder( 1559 Icon.createWithResource(getContext(), R.drawable.icon_blue), 1560 "a2", getPendingIntent()).build()) 1561 .setStyle(new Notification.BigPictureStyle() 1562 .setBigContentTitle("title") 1563 .bigPicture(Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565)) 1564 .bigLargeIcon(Icon.createWithResource(getContext(), R.drawable.icon_blue)) 1565 .setSummaryText("summary")) 1566 .build(); 1567 mNotificationManager.notify(id, notification); 1568 1569 if (!checkNotificationExistence(id, /*shouldExist=*/ true)) { 1570 fail("couldn't find posted notification id=" + id); 1571 } 1572 } 1573 1574 public void testAutogrouping() throws Exception { 1575 sendNotification(1, R.drawable.black); 1576 sendNotification(2, R.drawable.blue); 1577 sendNotification(3, R.drawable.yellow); 1578 sendNotification(4, R.drawable.yellow); 1579 1580 assertNotificationCount(5); 1581 assertAllPostedNotificationsAutogrouped(); 1582 } 1583 1584 public void testAutogrouping_autogroupStaysUntilAllNotificationsCanceled() throws Exception { 1585 sendNotification(1, R.drawable.black); 1586 sendNotification(2, R.drawable.blue); 1587 sendNotification(3, R.drawable.yellow); 1588 sendNotification(4, R.drawable.yellow); 1589 1590 assertNotificationCount(5); 1591 assertAllPostedNotificationsAutogrouped(); 1592 1593 // Assert all notis stay in the same autogroup until all children are canceled 1594 for (int i = 4; i > 1; i--) { 1595 cancelAndPoll(i); 1596 assertNotificationCount(i); 1597 assertAllPostedNotificationsAutogrouped(); 1598 } 1599 cancelAndPoll(1); 1600 assertNotificationCount(0); 1601 } 1602 1603 public void testAutogrouping_autogroupStaysUntilAllNotificationsAddedToGroup() 1604 throws Exception { 1605 String newGroup = "new!"; 1606 sendNotification(1, R.drawable.black); 1607 sendNotification(2, R.drawable.blue); 1608 sendNotification(3, R.drawable.yellow); 1609 sendNotification(4, R.drawable.yellow); 1610 1611 List<Integer> postedIds = new ArrayList<>(); 1612 postedIds.add(1); 1613 postedIds.add(2); 1614 postedIds.add(3); 1615 postedIds.add(4); 1616 1617 assertNotificationCount(5); 1618 assertAllPostedNotificationsAutogrouped(); 1619 1620 // Assert all notis stay in the same autogroup until all children are canceled 1621 for (int i = 4; i > 1; i--) { 1622 sendNotification(i, newGroup, R.drawable.blue); 1623 postedIds.remove(postedIds.size() - 1); 1624 assertNotificationCount(5); 1625 assertOnlySomeNotificationsAutogrouped(postedIds); 1626 } 1627 sendNotification(1, newGroup, R.drawable.blue); 1628 assertNotificationCount(4); // no more autogroup summary 1629 postedIds.remove(0); 1630 assertOnlySomeNotificationsAutogrouped(postedIds); 1631 } 1632 1633 public void testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled() 1634 throws Exception { 1635 String newGroup = "new!"; 1636 sendNotification(10, R.drawable.black); 1637 sendNotification(20, R.drawable.blue); 1638 sendNotification(30, R.drawable.yellow); 1639 sendNotification(40, R.drawable.yellow); 1640 1641 List<Integer> postedIds = new ArrayList<>(); 1642 postedIds.add(10); 1643 postedIds.add(20); 1644 postedIds.add(30); 1645 postedIds.add(40); 1646 1647 assertNotificationCount(5); 1648 assertAllPostedNotificationsAutogrouped(); 1649 1650 // regroup all but one of the children 1651 for (int i = postedIds.size() - 1; i > 0; i--) { 1652 try { 1653 Thread.sleep(200); 1654 } catch (InterruptedException ex) { 1655 // pass 1656 } 1657 int id = postedIds.remove(i); 1658 sendNotification(id, newGroup, R.drawable.blue); 1659 assertNotificationCount(5); 1660 assertOnlySomeNotificationsAutogrouped(postedIds); 1661 } 1662 1663 // send a new non-grouped notification. since the autogroup summary still exists, 1664 // the notification should be added to it 1665 sendNotification(50, R.drawable.blue); 1666 postedIds.add(50); 1667 try { 1668 Thread.sleep(200); 1669 } catch (InterruptedException ex) { 1670 // pass 1671 } 1672 assertOnlySomeNotificationsAutogrouped(postedIds); 1673 } 1674 1675 public void testAddAutomaticZenRule_configActivity() throws Exception { 1676 if (mActivityManager.isLowRamDevice()) { 1677 return; 1678 } 1679 1680 toggleNotificationPolicyAccess(mContext.getPackageName(), 1681 InstrumentationRegistry.getInstrumentation(), true); 1682 1683 AutomaticZenRule ruleToCreate = createRule("Rule"); 1684 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1685 1686 assertNotNull(id); 1687 mRuleIds.add(id); 1688 assertTrue(areRulesSame(ruleToCreate, mNotificationManager.getAutomaticZenRule(id))); 1689 } 1690 1691 public void testUpdateAutomaticZenRule_configActivity() throws Exception { 1692 if (mActivityManager.isLowRamDevice()) { 1693 return; 1694 } 1695 1696 toggleNotificationPolicyAccess(mContext.getPackageName(), 1697 InstrumentationRegistry.getInstrumentation(), true); 1698 1699 AutomaticZenRule ruleToCreate = createRule("Rule"); 1700 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1701 ruleToCreate.setEnabled(false); 1702 mNotificationManager.updateAutomaticZenRule(id, ruleToCreate); 1703 1704 assertNotNull(id); 1705 mRuleIds.add(id); 1706 assertTrue(areRulesSame(ruleToCreate, mNotificationManager.getAutomaticZenRule(id))); 1707 } 1708 1709 public void testRemoveAutomaticZenRule_configActivity() throws Exception { 1710 if (mActivityManager.isLowRamDevice()) { 1711 return; 1712 } 1713 1714 toggleNotificationPolicyAccess(mContext.getPackageName(), 1715 InstrumentationRegistry.getInstrumentation(), true); 1716 1717 AutomaticZenRule ruleToCreate = createRule("Rule"); 1718 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1719 1720 assertNotNull(id); 1721 mRuleIds.add(id); 1722 mNotificationManager.removeAutomaticZenRule(id); 1723 1724 assertNull(mNotificationManager.getAutomaticZenRule(id)); 1725 assertEquals(0, mNotificationManager.getAutomaticZenRules().size()); 1726 } 1727 1728 public void testSetAutomaticZenRuleState() throws Exception { 1729 if (mActivityManager.isLowRamDevice()) { 1730 return; 1731 } 1732 1733 toggleNotificationPolicyAccess(mContext.getPackageName(), 1734 InstrumentationRegistry.getInstrumentation(), true); 1735 1736 AutomaticZenRule ruleToCreate = createRule("Rule"); 1737 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1738 mRuleIds.add(id); 1739 1740 // make sure DND is off 1741 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 1742 1743 // enable DND 1744 Condition condition = 1745 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE); 1746 mNotificationManager.setAutomaticZenRuleState(id, condition); 1747 1748 assertExpectedDndState(ruleToCreate.getInterruptionFilter()); 1749 } 1750 1751 public void testSetAutomaticZenRuleState_turnOff() throws Exception { 1752 if (mActivityManager.isLowRamDevice()) { 1753 return; 1754 } 1755 1756 toggleNotificationPolicyAccess(mContext.getPackageName(), 1757 InstrumentationRegistry.getInstrumentation(), true); 1758 1759 AutomaticZenRule ruleToCreate = createRule("Rule"); 1760 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1761 mRuleIds.add(id); 1762 1763 // make sure DND is off 1764 // make sure DND is off 1765 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 1766 1767 // enable DND 1768 Condition condition = 1769 new Condition(ruleToCreate.getConditionId(), "on", Condition.STATE_TRUE); 1770 mNotificationManager.setAutomaticZenRuleState(id, condition); 1771 1772 assertExpectedDndState(ruleToCreate.getInterruptionFilter()); 1773 1774 // disable DND 1775 condition = new Condition(ruleToCreate.getConditionId(), "off", Condition.STATE_FALSE); 1776 1777 mNotificationManager.setAutomaticZenRuleState(id, condition); 1778 1779 // make sure DND is off 1780 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 1781 } 1782 1783 public void testSetAutomaticZenRuleState_deletedRule() throws Exception { 1784 if (mActivityManager.isLowRamDevice()) { 1785 return; 1786 } 1787 1788 toggleNotificationPolicyAccess(mContext.getPackageName(), 1789 InstrumentationRegistry.getInstrumentation(), true); 1790 1791 AutomaticZenRule ruleToCreate = createRule("Rule"); 1792 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1793 mRuleIds.add(id); 1794 1795 // make sure DND is off 1796 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 1797 1798 // enable DND 1799 Condition condition = 1800 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE); 1801 mNotificationManager.setAutomaticZenRuleState(id, condition); 1802 1803 assertExpectedDndState(ruleToCreate.getInterruptionFilter()); 1804 1805 mNotificationManager.removeAutomaticZenRule(id); 1806 1807 // make sure DND is off 1808 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 1809 } 1810 1811 @FlakyTest 1812 public void testSetAutomaticZenRuleState_multipleRules() throws Exception { 1813 if (mActivityManager.isLowRamDevice()) { 1814 return; 1815 } 1816 1817 toggleNotificationPolicyAccess(mContext.getPackageName(), 1818 InstrumentationRegistry.getInstrumentation(), true); 1819 1820 AutomaticZenRule ruleToCreate = createRule("Rule"); 1821 String id = mNotificationManager.addAutomaticZenRule(ruleToCreate); 1822 mRuleIds.add(id); 1823 1824 AutomaticZenRule secondRuleToCreate = createRule("Rule 2"); 1825 secondRuleToCreate.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE); 1826 String secondId = mNotificationManager.addAutomaticZenRule(secondRuleToCreate); 1827 mRuleIds.add(secondId); 1828 1829 // make sure DND is off 1830 assertExpectedDndState(INTERRUPTION_FILTER_ALL); 1831 1832 // enable DND 1833 Condition condition = 1834 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE); 1835 mNotificationManager.setAutomaticZenRuleState(id, condition); 1836 Condition secondCondition = 1837 new Condition(secondRuleToCreate.getConditionId(), "summary", Condition.STATE_TRUE); 1838 mNotificationManager.setAutomaticZenRuleState(secondId, secondCondition); 1839 1840 // the second rule has a 'more silent' DND filter, so the system wide DND should be 1841 // using its filter 1842 assertExpectedDndState(secondRuleToCreate.getInterruptionFilter()); 1843 1844 // remove intense rule, system should fallback to other rule 1845 mNotificationManager.removeAutomaticZenRule(secondId); 1846 assertExpectedDndState(ruleToCreate.getInterruptionFilter()); 1847 } 1848 1849 public void testSetNotificationPolicy_P_setOldFields() throws Exception { 1850 if (mActivityManager.isLowRamDevice()) { 1851 return; 1852 } 1853 toggleNotificationPolicyAccess(mContext.getPackageName(), 1854 InstrumentationRegistry.getInstrumentation(), true); 1855 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { 1856 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 1857 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 1858 mNotificationManager.setNotificationPolicy(appPolicy); 1859 1860 int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 1861 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT 1862 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 1863 1864 assertEquals(expected, 1865 mNotificationManager.getNotificationPolicy().suppressedVisualEffects); 1866 } 1867 } 1868 1869 public void testSetNotificationPolicy_P_setNewFields() throws Exception { 1870 if (mActivityManager.isLowRamDevice()) { 1871 return; 1872 } 1873 toggleNotificationPolicyAccess(mContext.getPackageName(), 1874 InstrumentationRegistry.getInstrumentation(), true); 1875 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { 1876 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 1877 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT 1878 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 1879 mNotificationManager.setNotificationPolicy(appPolicy); 1880 1881 int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF 1882 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS 1883 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 1884 assertEquals(expected, 1885 mNotificationManager.getNotificationPolicy().suppressedVisualEffects); 1886 } 1887 } 1888 1889 public void testSetNotificationPolicy_P_setOldNewFields() throws Exception { 1890 if (mActivityManager.isLowRamDevice()) { 1891 return; 1892 } 1893 toggleNotificationPolicyAccess(mContext.getPackageName(), 1894 InstrumentationRegistry.getInstrumentation(), true); 1895 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { 1896 1897 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 1898 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 1899 mNotificationManager.setNotificationPolicy(appPolicy); 1900 1901 int expected = SUPPRESSED_EFFECT_STATUS_BAR; 1902 assertEquals(expected, 1903 mNotificationManager.getNotificationPolicy().suppressedVisualEffects); 1904 1905 appPolicy = new NotificationManager.Policy(0, 0, 0, 1906 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT 1907 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 1908 mNotificationManager.setNotificationPolicy(appPolicy); 1909 1910 expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT 1911 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 1912 assertEquals(expected, 1913 mNotificationManager.getNotificationPolicy().suppressedVisualEffects); 1914 } 1915 } 1916 1917 public void testPostFullScreenIntent_permission() { 1918 int id = 6000; 1919 1920 final Notification notification = 1921 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 1922 .setSmallIcon(R.drawable.black) 1923 .setWhen(System.currentTimeMillis()) 1924 .setFullScreenIntent(getPendingIntent(), true) 1925 .setContentText("This is #FSI notification") 1926 .setContentIntent(getPendingIntent()) 1927 .build(); 1928 mNotificationManager.notify(id, notification); 1929 1930 StatusBarNotification n = findPostedNotification(id); 1931 assertNotNull(n); 1932 assertEquals(notification.fullScreenIntent, n.getNotification().fullScreenIntent); 1933 } 1934 1935 public void testNotificationPolicyVisualEffectsEqual() { 1936 NotificationManager.Policy policy = new NotificationManager.Policy(0,0 ,0 , 1937 SUPPRESSED_EFFECT_SCREEN_ON); 1938 NotificationManager.Policy policy2 = new NotificationManager.Policy(0,0 ,0 , 1939 SUPPRESSED_EFFECT_PEEK); 1940 assertTrue(policy.equals(policy2)); 1941 assertTrue(policy2.equals(policy)); 1942 1943 policy = new NotificationManager.Policy(0,0 ,0 , 1944 SUPPRESSED_EFFECT_SCREEN_ON); 1945 policy2 = new NotificationManager.Policy(0,0 ,0 , 1946 0); 1947 assertFalse(policy.equals(policy2)); 1948 assertFalse(policy2.equals(policy)); 1949 1950 policy = new NotificationManager.Policy(0,0 ,0 , 1951 SUPPRESSED_EFFECT_SCREEN_OFF); 1952 policy2 = new NotificationManager.Policy(0,0 ,0 , 1953 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_AMBIENT 1954 | SUPPRESSED_EFFECT_LIGHTS); 1955 assertTrue(policy.equals(policy2)); 1956 assertTrue(policy2.equals(policy)); 1957 1958 policy = new NotificationManager.Policy(0,0 ,0 , 1959 SUPPRESSED_EFFECT_SCREEN_OFF); 1960 policy2 = new NotificationManager.Policy(0,0 ,0 , 1961 SUPPRESSED_EFFECT_LIGHTS); 1962 assertFalse(policy.equals(policy2)); 1963 assertFalse(policy2.equals(policy)); 1964 } 1965 1966 public void testNotificationDelegate_grantAndPost() throws Exception { 1967 // grant this test permission to post 1968 final Intent activityIntent = new Intent(); 1969 activityIntent.setPackage(DELEGATOR); 1970 activityIntent.setAction(Intent.ACTION_MAIN); 1971 activityIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1972 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1973 1974 // wait for the activity to launch and finish 1975 mContext.startActivity(activityIntent); 1976 Thread.sleep(1000); 1977 1978 // send notification 1979 Notification n = new Notification.Builder(mContext, "channel") 1980 .setSmallIcon(android.R.id.icon) 1981 .build(); 1982 mNotificationManager.notifyAsPackage(DELEGATOR, "tag", 0, n); 1983 1984 findPostedNotification(0); 1985 1986 final Intent revokeIntent = new Intent(); 1987 revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS); 1988 revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1989 mContext.startActivity(revokeIntent); 1990 Thread.sleep(1000); 1991 } 1992 1993 public void testNotificationDelegate_grantAndReadChannels() throws Exception { 1994 // grant this test permission to post 1995 final Intent activityIntent = new Intent(); 1996 activityIntent.setPackage(DELEGATOR); 1997 activityIntent.setAction(Intent.ACTION_MAIN); 1998 activityIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1999 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2000 2001 // wait for the activity to launch and finish 2002 mContext.startActivity(activityIntent); 2003 Thread.sleep(500); 2004 2005 List<NotificationChannel> channels = 2006 mContext.createPackageContextAsUser(DELEGATOR, /* flags= */ 0, mContext.getUser()) 2007 .getSystemService(NotificationManager.class) 2008 .getNotificationChannels(); 2009 2010 assertNotNull(channels); 2011 2012 final Intent revokeIntent = new Intent(); 2013 revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS); 2014 revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2015 mContext.startActivity(revokeIntent); 2016 Thread.sleep(500); 2017 } 2018 2019 public void testNotificationDelegate_grantAndReadChannel() throws Exception { 2020 // grant this test permission to post 2021 final Intent activityIntent = new Intent(); 2022 activityIntent.setPackage(DELEGATOR); 2023 activityIntent.setAction(Intent.ACTION_MAIN); 2024 activityIntent.addCategory(Intent.CATEGORY_LAUNCHER); 2025 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2026 2027 // wait for the activity to launch and finish 2028 mContext.startActivity(activityIntent); 2029 Thread.sleep(500); 2030 2031 NotificationChannel channel = 2032 mContext.createPackageContextAsUser(DELEGATOR, /* flags= */ 0, mContext.getUser()) 2033 .getSystemService(NotificationManager.class) 2034 .getNotificationChannel("channel"); 2035 2036 assertNotNull(channel); 2037 2038 final Intent revokeIntent = new Intent(); 2039 revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS); 2040 revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2041 mContext.startActivity(revokeIntent); 2042 Thread.sleep(500); 2043 } 2044 2045 public void testNotificationDelegate_grantAndRevoke() throws Exception { 2046 // grant this test permission to post 2047 final Intent activityIntent = new Intent(); 2048 activityIntent.setPackage(DELEGATOR); 2049 activityIntent.setAction(Intent.ACTION_MAIN); 2050 activityIntent.addCategory(Intent.CATEGORY_LAUNCHER); 2051 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2052 2053 mContext.startActivity(activityIntent); 2054 Thread.sleep(500); 2055 2056 assertTrue(mNotificationManager.canNotifyAsPackage(DELEGATOR)); 2057 2058 final Intent revokeIntent = new Intent(); 2059 revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS); 2060 revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2061 mContext.startActivity(revokeIntent); 2062 Thread.sleep(500); 2063 2064 try { 2065 // send notification 2066 Notification n = new Notification.Builder(mContext, "channel") 2067 .setSmallIcon(android.R.id.icon) 2068 .build(); 2069 mNotificationManager.notifyAsPackage(DELEGATOR, "tag", 0, n); 2070 fail("Should not be able to post as a delegate when permission revoked"); 2071 } catch (SecurityException e) { 2072 // yay 2073 } 2074 } 2075 2076 public void testAreBubblesAllowed() { 2077 assertTrue(mNotificationManager.areBubblesAllowed()); 2078 } 2079 2080 public void testNotificationIcon() { 2081 int id = 6000; 2082 2083 Notification notification = 2084 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2085 .setSmallIcon(android.R.id.icon) 2086 .setWhen(System.currentTimeMillis()) 2087 .setFullScreenIntent(getPendingIntent(), true) 2088 .setContentText("This notification has a resource icon") 2089 .setContentIntent(getPendingIntent()) 2090 .build(); 2091 mNotificationManager.notify(id, notification); 2092 2093 notification = 2094 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2095 .setSmallIcon(Icon.createWithResource(mContext, android.R.id.icon)) 2096 .setWhen(System.currentTimeMillis()) 2097 .setFullScreenIntent(getPendingIntent(), true) 2098 .setContentText("This notification has an Icon icon") 2099 .setContentIntent(getPendingIntent()) 2100 .build(); 2101 mNotificationManager.notify(id, notification); 2102 2103 StatusBarNotification n = findPostedNotification(id); 2104 assertNotNull(n); 2105 } 2106 2107 public void testShouldHideSilentStatusIcons() throws Exception { 2108 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2109 return; 2110 } 2111 2112 try { 2113 mNotificationManager.shouldHideSilentStatusBarIcons(); 2114 fail("Non-privileged apps should not get this information"); 2115 } catch (SecurityException e) { 2116 // pass 2117 } 2118 2119 toggleListenerAccess(TestNotificationListener.getId(), 2120 InstrumentationRegistry.getInstrumentation(), true); 2121 // no exception this time 2122 mNotificationManager.shouldHideSilentStatusBarIcons(); 2123 } 2124 2125 public void testMatchesCallFilter() throws Exception { 2126 if (mActivityManager.isLowRamDevice()) { 2127 return; 2128 } 2129 2130 // allow all callers 2131 toggleNotificationPolicyAccess(mContext.getPackageName(), 2132 InstrumentationRegistry.getInstrumentation(), true); 2133 NotificationManager.Policy currPolicy = mNotificationManager.getNotificationPolicy(); 2134 NotificationManager.Policy newPolicy = new NotificationManager.Policy( 2135 NotificationManager.Policy.PRIORITY_CATEGORY_CALLS 2136 | NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 2137 NotificationManager.Policy.PRIORITY_SENDERS_ANY, 2138 currPolicy.priorityMessageSenders, 2139 currPolicy.suppressedVisualEffects); 2140 mNotificationManager.setNotificationPolicy(newPolicy); 2141 2142 // add a contact 2143 String ALICE = "Alice"; 2144 String ALICE_PHONE = "+16175551212"; 2145 String ALICE_EMAIL = "alice (at) _foo._bar"; 2146 2147 insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, false); 2148 2149 final Bundle peopleExtras = new Bundle(); 2150 ArrayList<Person> personList = new ArrayList<>(); 2151 personList.add(new Person.Builder().setUri(lookupContact(ALICE_PHONE).toString()).build()); 2152 peopleExtras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, personList); 2153 SystemUtil.runWithShellPermissionIdentity(() -> 2154 assertTrue(mNotificationManager.matchesCallFilter(peopleExtras))); 2155 } 2156 2157 /* Confirm that the optional methods of TestNotificationListener still exist and 2158 * don't fail. */ 2159 public void testNotificationListenerMethods() { 2160 NotificationListenerService listener = new TestNotificationListener(); 2161 listener.onListenerConnected(); 2162 2163 listener.onSilentStatusBarIconsVisibilityChanged(false); 2164 2165 listener.onNotificationPosted(null); 2166 listener.onNotificationPosted(null, null); 2167 2168 listener.onNotificationRemoved(null); 2169 listener.onNotificationRemoved(null, null); 2170 2171 listener.onNotificationChannelGroupModified("", UserHandle.CURRENT, null, 2172 NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 2173 listener.onNotificationChannelModified("", UserHandle.CURRENT, null, 2174 NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED); 2175 2176 listener.onListenerDisconnected(); 2177 } 2178 2179 public void testNotificationListener_setNotificationsShown() throws Exception { 2180 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2181 return; 2182 } 2183 2184 toggleListenerAccess(TestNotificationListener.getId(), 2185 InstrumentationRegistry.getInstrumentation(), true); 2186 Thread.sleep(500); // wait for listener to be allowed 2187 2188 mListener = TestNotificationListener.getInstance(); 2189 assertNotNull(mListener); 2190 final int notificationId1 = 1; 2191 final int notificationId2 = 2; 2192 2193 sendNotification(notificationId1, R.drawable.black); 2194 sendNotification(notificationId2, R.drawable.black); 2195 Thread.sleep(500); // wait for notification listener to receive notification 2196 2197 StatusBarNotification sbn1 = findPostedNotification(notificationId1); 2198 StatusBarNotification sbn2 = findPostedNotification(notificationId2); 2199 mListener.setNotificationsShown(new String[]{ sbn1.getKey() }); 2200 2201 toggleListenerAccess(TestNotificationListener.getId(), 2202 InstrumentationRegistry.getInstrumentation(), false); 2203 Thread.sleep(500); // wait for listener to be disallowed 2204 try { 2205 mListener.setNotificationsShown(new String[]{ sbn2.getKey() }); 2206 fail("Should not be able to set shown if listener access isn't granted"); 2207 } catch (SecurityException e) { 2208 // expected 2209 } 2210 } 2211 2212 public void testNotificationListener_getNotificationChannels() throws Exception { 2213 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2214 return; 2215 } 2216 2217 toggleListenerAccess(TestNotificationListener.getId(), 2218 InstrumentationRegistry.getInstrumentation(), true); 2219 Thread.sleep(500); // wait for listener to be allowed 2220 2221 mListener = TestNotificationListener.getInstance(); 2222 assertNotNull(mListener); 2223 2224 try { 2225 mListener.getNotificationChannels(mContext.getPackageName(), UserHandle.CURRENT); 2226 fail("Shouldn't be able get channels without CompanionDeviceManager#getAssociations()"); 2227 } catch (SecurityException e) { 2228 // expected 2229 } 2230 } 2231 2232 public void testNotificationListener_getNotificationChannelGroups() throws Exception { 2233 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2234 return; 2235 } 2236 2237 toggleListenerAccess(TestNotificationListener.getId(), 2238 InstrumentationRegistry.getInstrumentation(), true); 2239 Thread.sleep(500); // wait for listener to be allowed 2240 2241 mListener = TestNotificationListener.getInstance(); 2242 assertNotNull(mListener); 2243 try { 2244 mListener.getNotificationChannelGroups(mContext.getPackageName(), UserHandle.CURRENT); 2245 fail("Should not be able get groups without CompanionDeviceManager#getAssociations()"); 2246 } catch (SecurityException e) { 2247 // expected 2248 } 2249 } 2250 2251 public void testNotificationListener_updateNotificationChannel() throws Exception { 2252 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2253 return; 2254 } 2255 2256 toggleListenerAccess(TestNotificationListener.getId(), 2257 InstrumentationRegistry.getInstrumentation(), true); 2258 Thread.sleep(500); // wait for listener to be allowed 2259 2260 mListener = TestNotificationListener.getInstance(); 2261 assertNotNull(mListener); 2262 2263 NotificationChannel channel = new NotificationChannel( 2264 NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT); 2265 try { 2266 mListener.updateNotificationChannel(mContext.getPackageName(), UserHandle.CURRENT, 2267 channel); 2268 fail("Shouldn't be able to update channel without " 2269 + "CompanionDeviceManager#getAssociations()"); 2270 } catch (SecurityException e) { 2271 // expected 2272 } 2273 } 2274 2275 public void testNotificationListener_getActiveNotifications() throws Exception { 2276 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2277 return; 2278 } 2279 2280 toggleListenerAccess(TestNotificationListener.getId(), 2281 InstrumentationRegistry.getInstrumentation(), true); 2282 Thread.sleep(500); // wait for listener to be allowed 2283 2284 mListener = TestNotificationListener.getInstance(); 2285 assertNotNull(mListener); 2286 final int notificationId1 = 1; 2287 final int notificationId2 = 2; 2288 2289 sendNotification(notificationId1, R.drawable.black); 2290 sendNotification(notificationId2, R.drawable.black); 2291 Thread.sleep(500); // wait for notification listener to receive notification 2292 2293 StatusBarNotification sbn1 = findPostedNotification(notificationId1); 2294 StatusBarNotification sbn2 = findPostedNotification(notificationId2); 2295 StatusBarNotification[] notifs = 2296 mListener.getActiveNotifications(new String[]{ sbn2.getKey(), sbn1.getKey() }); 2297 assertEquals(sbn2.getKey(), notifs[0].getKey()); 2298 assertEquals(sbn2.getId(), notifs[0].getId()); 2299 assertEquals(sbn2.getPackageName(), notifs[0].getPackageName()); 2300 2301 assertEquals(sbn1.getKey(), notifs[1].getKey()); 2302 assertEquals(sbn1.getId(), notifs[1].getId()); 2303 assertEquals(sbn1.getPackageName(), notifs[1].getPackageName()); 2304 } 2305 2306 2307 public void testNotificationListener_getCurrentRanking() throws Exception { 2308 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2309 return; 2310 } 2311 2312 toggleListenerAccess(TestNotificationListener.getId(), 2313 InstrumentationRegistry.getInstrumentation(), true); 2314 Thread.sleep(500); // wait for listener to be allowed 2315 2316 mListener = TestNotificationListener.getInstance(); 2317 assertNotNull(mListener); 2318 2319 sendNotification(1, R.drawable.black); 2320 Thread.sleep(500); // wait for notification listener to receive notification 2321 2322 assertEquals(mListener.mRankingMap, mListener.getCurrentRanking()); 2323 } 2324 2325 public void testNotificationListener_cancelNotifications() throws Exception { 2326 if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) { 2327 return; 2328 } 2329 2330 toggleListenerAccess(TestNotificationListener.getId(), 2331 InstrumentationRegistry.getInstrumentation(), true); 2332 Thread.sleep(500); // wait for listener to be allowed 2333 2334 mListener = TestNotificationListener.getInstance(); 2335 assertNotNull(mListener); 2336 final int notificationId = 1; 2337 2338 sendNotification(notificationId, R.drawable.black); 2339 Thread.sleep(500); // wait for notification listener to receive notification 2340 2341 StatusBarNotification sbn = findPostedNotification(notificationId); 2342 2343 mListener.cancelNotification(sbn.getPackageName(), sbn.getTag(), sbn.getId()); 2344 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { 2345 if (!checkNotificationExistence(notificationId, /*shouldExist=*/ true)) { 2346 fail("Notification shouldn't have been cancelled. " 2347 + "cancelNotification(String, String, int) shouldn't cancel notif for L+"); 2348 } 2349 } else { 2350 // Tested in LegacyNotificationManager20Test 2351 if (checkNotificationExistence(notificationId, /*shouldExist=*/ true)) { 2352 fail("Notification should have been cancelled for targetSdk below L. targetSdk=" 2353 + mContext.getApplicationInfo().targetSdkVersion); 2354 } 2355 } 2356 2357 mListener.cancelNotifications(new String[]{ sbn.getKey() }); 2358 if (!checkNotificationExistence(notificationId, /*shouldExist=*/ false)) { 2359 fail("Failed to cancel notification id=" + notificationId); 2360 } 2361 } 2362 2363 public void testNotificationManagerPolicy_priorityCategoriesToString() { 2364 String zeroString = NotificationManager.Policy.priorityCategoriesToString(0); 2365 assertEquals("priorityCategories of 0 produces empty string", "", zeroString); 2366 2367 String oneString = NotificationManager.Policy.priorityCategoriesToString(1); 2368 assertNotNull("priorityCategories of 1 returns a string", oneString); 2369 boolean lengthGreaterThanZero = oneString.length() > 0; 2370 assertTrue("priorityCategories of 1 returns a string with length greater than 0", 2371 lengthGreaterThanZero); 2372 2373 String badNumberString = NotificationManager.Policy.priorityCategoriesToString(1234567); 2374 assertNotNull("priorityCategories with a non-relevant int returns a string", oneString); 2375 } 2376 2377 public void testNotificationManagerPolicy_prioritySendersToString() { 2378 String zeroString = NotificationManager.Policy.prioritySendersToString(0); 2379 assertNotNull("prioritySenders of 1 returns a string", zeroString); 2380 boolean lengthGreaterThanZero = zeroString.length() > 0; 2381 assertTrue("prioritySenders of 1 returns a string with length greater than 0", 2382 lengthGreaterThanZero); 2383 2384 String badNumberString = NotificationManager.Policy.prioritySendersToString(1234567); 2385 assertNotNull("prioritySenders with a non-relevant int returns a string", badNumberString); 2386 } 2387 2388 public void testNotificationManagerPolicy_suppressedEffectsToString() { 2389 String zeroString = NotificationManager.Policy.suppressedEffectsToString(0); 2390 assertEquals("suppressedEffects of 0 produces empty string", "", zeroString); 2391 2392 String oneString = NotificationManager.Policy.suppressedEffectsToString(1); 2393 assertNotNull("suppressedEffects of 1 returns a string", oneString); 2394 boolean lengthGreaterThanZero = oneString.length() > 0; 2395 assertTrue("suppressedEffects of 1 returns a string with length greater than 0", 2396 lengthGreaterThanZero); 2397 2398 String badNumberString = NotificationManager.Policy.suppressedEffectsToString(1234567); 2399 assertNotNull("suppressedEffects with a non-relevant int returns a string", 2400 badNumberString); 2401 } 2402 2403 public void testNotificationManagerBubblePolicy_flagForMessage_failsNoRemoteInput() 2404 throws InterruptedException { 2405 try { 2406 // turn on bubbles globally 2407 toggleBubbleSetting(true); 2408 2409 Person person = new Person.Builder() 2410 .setName("bubblebot") 2411 .build(); 2412 Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2413 .setContentTitle("foo") 2414 .setStyle(new Notification.MessagingStyle(person) 2415 .setConversationTitle("Bubble Chat") 2416 .addMessage("Hello?", 2417 SystemClock.currentThreadTimeMillis() - 300000, person) 2418 .addMessage("Is it me you're looking for?", 2419 SystemClock.currentThreadTimeMillis(), person) 2420 ) 2421 .setSmallIcon(android.R.drawable.sym_def_app_icon); 2422 sendAndVerifyBubble(1, nb, null /* use default metadata */, false); 2423 } finally { 2424 // turn off bubbles globally 2425 toggleBubbleSetting(false); 2426 } 2427 } 2428 2429 public void testNotificationManagerBubblePolicy_flagForMessage_succeeds() 2430 throws InterruptedException { 2431 try { 2432 // turn on bubbles globally 2433 toggleBubbleSetting(true); 2434 2435 Person person = new Person.Builder() 2436 .setName("bubblebot") 2437 .build(); 2438 2439 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel( 2440 "reply").build(); 2441 PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0); 2442 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 2443 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 2444 inputIntent).addRemoteInput(remoteInput) 2445 .build(); 2446 2447 Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2448 .setContentTitle("foo") 2449 .setStyle(new Notification.MessagingStyle(person) 2450 .setConversationTitle("Bubble Chat") 2451 .addMessage("Hello?", 2452 SystemClock.currentThreadTimeMillis() - 300000, person) 2453 .addMessage("Is it me you're looking for?", 2454 SystemClock.currentThreadTimeMillis(), person) 2455 ) 2456 .setActions(replyAction) 2457 .setSmallIcon(android.R.drawable.sym_def_app_icon); 2458 2459 boolean shouldBeBubble = !mActivityManager.isLowRamDevice(); 2460 sendAndVerifyBubble(1, nb, null /* use default metadata */, shouldBeBubble); 2461 } finally { 2462 // turn off bubbles globally 2463 toggleBubbleSetting(false); 2464 } 2465 } 2466 2467 public void testNotificationManagerBubblePolicy_flagForPhonecall() throws InterruptedException { 2468 Intent serviceIntent = new Intent(mContext, BubblesTestService.class); 2469 serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_SUCCESS); 2470 2471 try { 2472 // turn on bubbles globally 2473 toggleBubbleSetting(true); 2474 mContext.startService(serviceIntent); 2475 2476 boolean shouldBeBubble = !mActivityManager.isLowRamDevice(); 2477 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2478 true /* shouldExist */, shouldBeBubble)) { 2479 fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID); 2480 } 2481 2482 } finally { 2483 mContext.stopService(serviceIntent); 2484 // turn off bubbles globally 2485 toggleBubbleSetting(false); 2486 } 2487 } 2488 2489 public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoPerson() 2490 throws InterruptedException { 2491 Intent serviceIntent = new Intent(mContext, BubblesTestService.class); 2492 serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_PERSON); 2493 2494 try { 2495 // turn on bubbles globally 2496 toggleBubbleSetting(true); 2497 mContext.startService(serviceIntent); 2498 2499 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2500 true /* shouldExist */, false /* shouldBeBubble */)) { 2501 fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID 2502 + " or it was a bubble when it shouldn't be"); 2503 } 2504 } finally { 2505 mContext.stopService(serviceIntent); 2506 // turn off bubbles globally 2507 toggleBubbleSetting(false); 2508 } 2509 } 2510 2511 public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoForeground() 2512 throws InterruptedException { 2513 try { 2514 // turn on bubbles globally 2515 toggleBubbleSetting(true); 2516 2517 Person person = new Person.Builder() 2518 .setName("bubblebot") 2519 .build(); 2520 Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2521 .setContentTitle("foo") 2522 .setCategory(CATEGORY_CALL) 2523 .addPerson(person) 2524 .setSmallIcon(android.R.drawable.sym_def_app_icon); 2525 sendAndVerifyBubble(1, nb, null /* use default metadata */, false /* shouldBeBubble */); 2526 2527 } finally { 2528 // turn off bubbles globally 2529 toggleBubbleSetting(false); 2530 } 2531 } 2532 2533 public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoCategory() 2534 throws InterruptedException { 2535 Intent serviceIntent = new Intent(mContext, BubblesTestService.class); 2536 serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_CATEGORY); 2537 2538 try { 2539 // turn on bubbles globally 2540 toggleBubbleSetting(true); 2541 mContext.startService(serviceIntent); 2542 2543 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2544 true /* shouldExist */, false /* shouldBeBubble */)) { 2545 fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID 2546 + " or it was a bubble when it shouldn't be"); 2547 } 2548 2549 } finally { 2550 mContext.stopService(serviceIntent); 2551 // turn off bubbles globally 2552 toggleBubbleSetting(false); 2553 } 2554 2555 } 2556 2557 public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoMetadata() 2558 throws InterruptedException { 2559 Intent serviceIntent = new Intent(mContext, BubblesTestService.class); 2560 serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_BUBBLE_METADATA); 2561 2562 try { 2563 // turn on bubbles globally 2564 toggleBubbleSetting(true); 2565 mContext.startService(serviceIntent); 2566 2567 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2568 true /* shouldExist */, false /* shouldBeBubble */)) { 2569 fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID 2570 + " or it was a bubble when it shouldn't be"); 2571 } 2572 } finally { 2573 mContext.stopService(serviceIntent); 2574 // turn off bubbles globally 2575 toggleBubbleSetting(false); 2576 } 2577 } 2578 2579 public void testNotificationManagerBubblePolicy_noFlagForAppNotForeground() 2580 throws InterruptedException { 2581 try { 2582 // turn on bubbles globally 2583 toggleBubbleSetting(true); 2584 2585 sendAndVerifyBubble(1, null /* use default notif */, null /* use default metadata */, 2586 false /* shouldBeBubble */); 2587 } finally { 2588 // turn off bubbles globally 2589 toggleBubbleSetting(false); 2590 } 2591 } 2592 2593 public void testNotificationManagerBubblePolicy_flagForAppForeground() throws Exception { 2594 try { 2595 // turn on bubbles globally 2596 toggleBubbleSetting(true); 2597 2598 final CountDownLatch latch = new CountDownLatch(2); 2599 BroadcastReceiver receiver = new BroadcastReceiver() { 2600 @Override 2601 public void onReceive(Context context, Intent intent) { 2602 latch.countDown(); 2603 } 2604 }; 2605 IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED); 2606 mContext.registerReceiver(receiver, filter); 2607 2608 // Start & get the activity 2609 BubblesTestActivity a = (BubblesTestActivity) launchSendBubbleActivity(); 2610 2611 // Make sure device is unlocked 2612 KeyguardManager keyguardManager = 2613 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 2614 keyguardManager.requestDismissKeyguard(a, new KeyguardManager.KeyguardDismissCallback() { 2615 @Override 2616 public void onDismissSucceeded() { 2617 latch.countDown(); 2618 } 2619 }); 2620 try { 2621 latch.await(100, TimeUnit.MILLISECONDS); 2622 } catch (InterruptedException e) { 2623 e.printStackTrace(); 2624 } 2625 2626 // Should be foreground now 2627 a.sendBubble(1); 2628 2629 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2630 true /* shouldExist */, true /* shouldBeBubble */)) { 2631 fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID); 2632 } 2633 2634 // Make ourselves not foreground 2635 HomeHelper homeHelper = new HomeHelper(); 2636 homeHelper.goHome(); 2637 2638 // The notif should be allowed to update as a bubble 2639 a.sendBubble(2); 2640 2641 boolean shouldBeBubble = !mActivityManager.isLowRamDevice(); 2642 2643 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2644 true /* shouldExist */, shouldBeBubble)) { 2645 fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID); 2646 } 2647 2648 // Cancel the notif 2649 cancelAndPoll(BUBBLE_NOTIF_ID); 2650 2651 // Send it again when not foreground, this should not be a bubble & just be a notif 2652 a.sendBubble(3); 2653 if (!checkNotificationExistence(BUBBLE_NOTIF_ID, 2654 true /* shouldExist */, false /* shouldBeBubble */)) { 2655 fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID 2656 + " or it was a bubble when it shouldn't be"); 2657 } 2658 2659 mContext.unregisterReceiver(receiver); 2660 homeHelper.close(); 2661 } finally { 2662 // turn off bubbles globally 2663 toggleBubbleSetting(false); 2664 } 2665 } 2666 2667 public void testNotificationManagerBubblePolicy_noFlag_notEmbeddable() throws Exception { 2668 Person person = new Person.Builder() 2669 .setName("bubblebot") 2670 .build(); 2671 2672 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 2673 PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0); 2674 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 2675 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 2676 inputIntent).addRemoteInput(remoteInput) 2677 .build(); 2678 2679 Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2680 .setContentTitle("foo") 2681 .setStyle(new Notification.MessagingStyle(person) 2682 .setConversationTitle("Bubble Chat") 2683 .addMessage("Hello?", 2684 SystemClock.currentThreadTimeMillis() - 300000, person) 2685 .addMessage("Is it me you're looking for?", 2686 SystemClock.currentThreadTimeMillis(), person) 2687 ) 2688 .setActions(replyAction) 2689 .setSmallIcon(android.R.drawable.sym_def_app_icon); 2690 2691 final Intent intent = new Intent(mContext, BubblesTestNotEmbeddableActivity.class); 2692 final PendingIntent pendingIntent = 2693 PendingIntent.getActivity(mContext, 0, intent, 0); 2694 2695 Notification.BubbleMetadata.Builder metadataBuilder = 2696 new Notification.BubbleMetadata.Builder() 2697 .setIntent(pendingIntent) 2698 .setIcon(Icon.createWithResource(mContext, R.drawable.black)); 2699 2700 sendAndVerifyBubble(1, nb, metadataBuilder.build(), false); 2701 } 2702 2703 public void testNotificationManagerBubblePolicy_noFlag_notDocumentLaunchModeAlways() throws Exception { 2704 Person person = new Person.Builder() 2705 .setName("bubblebot") 2706 .build(); 2707 2708 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 2709 PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0); 2710 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 2711 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 2712 inputIntent).addRemoteInput(remoteInput) 2713 .build(); 2714 2715 Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID) 2716 .setContentTitle("foo") 2717 .setStyle(new Notification.MessagingStyle(person) 2718 .setConversationTitle("Bubble Chat") 2719 .addMessage("Hello?", 2720 SystemClock.currentThreadTimeMillis() - 300000, person) 2721 .addMessage("Is it me you're looking for?", 2722 SystemClock.currentThreadTimeMillis(), person) 2723 ) 2724 .setActions(replyAction) 2725 .setSmallIcon(android.R.drawable.sym_def_app_icon); 2726 2727 final Intent intent = new Intent(mContext, BubblesTestNotDocumentLaunchModeActivity.class); 2728 final PendingIntent pendingIntent = 2729 PendingIntent.getActivity(mContext, 0, intent, 0); 2730 2731 Notification.BubbleMetadata.Builder metadataBuilder = 2732 new Notification.BubbleMetadata.Builder() 2733 .setIntent(pendingIntent) 2734 .setIcon(Icon.createWithResource(mContext, R.drawable.black)); 2735 2736 sendAndVerifyBubble(1, nb, metadataBuilder.build(), false); 2737 } 2738 } 2739