Home | History | Annotate | Download | only in cts
      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