1 /*
2  * Copyright (C) 2023 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.notification.current.cts;
18 
19 import static android.Manifest.permission.POST_NOTIFICATIONS;
20 import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
21 import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
22 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
23 import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED;
24 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED;
25 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED;
26 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DEACTIVATED;
27 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
28 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
29 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_UNKNOWN;
30 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
31 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
32 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
33 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
34 import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
35 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
36 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
37 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
38 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_NONE;
39 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS;
40 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
41 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
42 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS;
43 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA;
44 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
45 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
46 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
47 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM;
48 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
49 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
50 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
51 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
52 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
53 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
54 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
55 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
56 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
57 import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
58 import static android.content.pm.PackageManager.FEATURE_WATCH;
59 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
60 import static android.service.notification.Condition.STATE_FALSE;
61 import static android.service.notification.Condition.STATE_TRUE;
62 
63 import static com.google.common.base.Preconditions.checkNotNull;
64 import static com.google.common.truth.Truth.assertThat;
65 
66 import static org.junit.Assert.assertEquals;
67 import static org.junit.Assert.assertFalse;
68 import static org.junit.Assert.assertNotNull;
69 import static org.junit.Assert.assertNull;
70 import static org.junit.Assert.assertThrows;
71 import static org.junit.Assert.assertTrue;
72 import static org.junit.Assume.assumeFalse;
73 import static org.junit.Assume.assumeTrue;
74 
75 import android.Manifest;
76 import android.app.AutomaticZenRule;
77 import android.app.Flags;
78 import android.app.Notification;
79 import android.app.NotificationChannel;
80 import android.app.NotificationManager;
81 import android.app.UiModeManager;
82 import android.app.WallpaperManager;
83 import android.app.compat.CompatChanges;
84 import android.app.cts.CtsAppTestUtils;
85 import android.app.stubs.AutomaticZenRuleActivity;
86 import android.app.stubs.GetResultActivity;
87 import android.app.stubs.R;
88 import android.app.stubs.shared.NotificationHelper.SEARCH_TYPE;
89 import android.content.ComponentName;
90 import android.content.ContentProviderOperation;
91 import android.content.Intent;
92 import android.content.OperationApplicationException;
93 import android.content.pm.PackageManager;
94 import android.content.pm.ResolveInfo;
95 import android.database.Cursor;
96 import android.hardware.display.ColorDisplayManager;
97 import android.media.AudioAttributes;
98 import android.media.AudioManager;
99 import android.net.Uri;
100 import android.os.Build;
101 import android.os.PowerManager;
102 import android.os.RemoteException;
103 import android.permission.PermissionManager;
104 import android.permission.cts.PermissionUtils;
105 import android.platform.test.annotations.RequiresFlagsDisabled;
106 import android.platform.test.annotations.RequiresFlagsEnabled;
107 import android.provider.ContactsContract;
108 import android.provider.Settings;
109 import android.service.notification.Condition;
110 import android.service.notification.NotificationListenerService;
111 import android.service.notification.StatusBarNotification;
112 import android.service.notification.ZenDeviceEffects;
113 import android.service.notification.ZenPolicy;
114 import android.util.Log;
115 
116 import androidx.test.platform.app.InstrumentationRegistry;
117 import androidx.test.runner.AndroidJUnit4;
118 import androidx.test.uiautomator.UiDevice;
119 
120 import com.android.bedstead.harrier.DeviceState;
121 import com.android.bedstead.multiuser.annotations.RequireNotVisibleBackgroundUsers;
122 import com.android.bedstead.multiuser.annotations.RequireRunNotOnVisibleBackgroundNonProfileUser;
123 import com.android.compatibility.common.util.ScreenUtils;
124 import com.android.compatibility.common.util.SystemUtil;
125 import com.android.modules.utils.build.SdkLevel;
126 
127 import com.google.common.collect.ImmutableSet;
128 import com.google.common.collect.Iterables;
129 
130 import org.junit.After;
131 import org.junit.Before;
132 import org.junit.ClassRule;
133 import org.junit.Rule;
134 import org.junit.Test;
135 import org.junit.runner.RunWith;
136 
137 import java.time.Duration;
138 import java.util.ArrayList;
139 import java.util.List;
140 import java.util.Map;
141 import java.util.Objects;
142 
143 /**
144  * Tests zen/dnd related logic in NotificationManager.
145  */
146 @RunWith(AndroidJUnit4.class)
147 // TODO(b/355106764): Remove the annotation once zen/dnd supports visible background users.
148 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "zen/dnd does not support visible"
149         + " background users at the moment")
150 public class NotificationManagerZenTest extends BaseNotificationManagerTest {
151 
152     private static final String TAG = NotificationManagerZenTest.class.getSimpleName();
153 
154     @ClassRule
155     @Rule
156     public static final DeviceState sDeviceState = new DeviceState();
157 
158     private static final String NOTIFICATION_CHANNEL_ID = TAG;
159     private static final String NOTIFICATION_CHANNEL_ID_NOISY = TAG + "/noisy";
160     private static final String NOTIFICATION_CHANNEL_ID_MEDIA = TAG + "/media";
161     private static final String NOTIFICATION_CHANNEL_ID_GAME = TAG + "/game";
162     private static final String NOTIFICATION_CHANNEL_ID_PRIORITY = TAG + "/priority";
163     private static final String ALICE = "Alice";
164     private static final String ALICE_PHONE = "+16175551212";
165     private static final String ALICE_EMAIL = "alice@_foo._bar";
166     private static final String BOB = "Bob";
167     private static final String BOB_PHONE = "+16505551212";
168     private static final String BOB_EMAIL = "bob@_foo._bar";
169     private static final String CHARLIE = "Charlie";
170     private static final String CHARLIE_PHONE = "+13305551212";
171     private static final String CHARLIE_EMAIL = "charlie@_foo._bar";
172     private static final int MODE_URI = 1;
173     private static final int MODE_PHONE = 2;
174     private static final int MODE_EMAIL = 3;
175     private static final int SEND_A = 0x1;
176     private static final int SEND_B = 0x2;
177     private static final int SEND_C = 0x4;
178     private static final int SEND_ALL = SEND_A | SEND_B | SEND_C;
179     private static final int MATCHES_CALL_FILTER_NOT_PERMITTED = 0;
180     private static final int MATCHES_CALL_FILTER_PERMITTED = 1;
181     private static final String MATCHES_CALL_FILTER_CLASS =
182             TEST_APP + ".MatchesCallFilterTestActivity";
183     private static final String MINIMAL_LISTENER_CLASS = TEST_APP + ".TestNotificationListener";
184     private static final int ZEN_EFFECTS_WAIT_MS = 600;
185 
186     private final String NAME = "name";
187     private ComponentName CONFIG_ACTIVITY;
188     private final ZenPolicy POLICY = new ZenPolicy.Builder().allowAlarms(true).build();
189     private final Uri CONDITION_ID = new Uri.Builder().scheme("scheme")
190             .authority("authority")
191             .appendPath("path")
192             .appendPath("test")
193             .build();
194     private static final String TRIGGER_DESC = "Triggered mysteriously";
195     private static final int UNRESTRICTED_TYPE = AutomaticZenRule.TYPE_IMMERSIVE; // Freely usable.
196     private static final boolean ALLOW_MANUAL = true;
197     private static final int ICON_RES_ID =
198             android.app.notification.current.cts.R.drawable.ic_android;
199     private NotificationManager.Policy mOriginalPolicy;
200     private ZenPolicy mDefaultPolicy;
201 
202     @Before
setUp()203     public void setUp() throws Exception {
204         PermissionUtils.grantPermission(mContext.getPackageName(), POST_NOTIFICATIONS);
205 
206         CONFIG_ACTIVITY = new ComponentName(mContext, AutomaticZenRuleActivity.class);
207 
208         mListener = mNotificationHelper.enableListener(STUB_PACKAGE_NAME);
209         assertNotNull(mListener);
210 
211         createChannels();
212 
213         // Set up a known DND state for all tests:
214         // * DND off.
215         // * Alarms, Media, Calls (starred), Messages (starred), Repeat Calls, Conversations
216         //   (starred) allowed.
217         // * Some suppressed visual effects.
218         // (using the SystemUI permission so we're certain to update global state).
219         runAsSystemUi(() -> {
220             mOriginalPolicy = mNotificationManager.getNotificationPolicy();
221 
222             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
223                     PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_CALLS
224                             | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
225                             | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
226                     PRIORITY_SENDERS_STARRED,
227                     SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS
228                             | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
229                     CONVERSATION_SENDERS_IMPORTANT));
230             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL);
231 
232             // Also get and cache the default policy for comparison later.
233             if (Flags.modesApi()) {
234                 if (Flags.modesUi()) {
235                     mDefaultPolicy = mNotificationManager.getDefaultZenPolicy();
236                 } else {
237                     // Pre-modes_ui, the "default policy" (for the purposes of merging with missing
238                     // or underspecified policies) is actually the manual policy. Thus we construct
239                     // a ZenPolicy matching the previous setNotificationPolicy() call.
240                     mDefaultPolicy = new ZenPolicy.Builder()
241                             .allowPriorityChannels(true)
242                             .disallowAllSounds()
243                             .allowAlarms(true)
244                             .allowMedia(true)
245                             .allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED)
246                             .allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
247                             .allowConversations(ZenPolicy.CONVERSATION_SENDERS_IMPORTANT)
248                             .allowRepeatCallers(true)
249                             .showAllVisualEffects()
250                             .showInAmbientDisplay(false)
251                             .showPeeking(false)
252                             .showLights(false)
253                             .showFullScreenIntent(false)
254                             .build();
255                 }
256             }
257         });
258     }
259 
260     @After
tearDown()261     public void tearDown() throws Exception {
262         // Use test API to prevent PermissionManager from killing the test process when revoking
263         // permission.
264         SystemUtil.runWithShellPermissionIdentity(
265                 () -> mContext.getSystemService(PermissionManager.class)
266                         .revokePostNotificationPermissionWithoutKillForTest(
267                                 mContext.getPackageName(),
268                                 android.os.Process.myUserHandle().getIdentifier()),
269                 REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
270                 REVOKE_RUNTIME_PERMISSIONS);
271 
272         // Restore to the previous DND state.
273         runAsSystemUi(() -> {
274             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL);
275             if (mOriginalPolicy != null) {
276                 mNotificationManager.setNotificationPolicy(mOriginalPolicy);
277             }
278         });
279 
280         final ArrayList<ContentProviderOperation> operationList = new ArrayList<>();
281         Uri aliceUri = lookupContact(ALICE_PHONE);
282         if (aliceUri != null) {
283             operationList.add(ContentProviderOperation.newDelete(aliceUri).build());
284         }
285         Uri bobUri = lookupContact(BOB_PHONE);
286         if (bobUri != null) {
287             operationList.add(ContentProviderOperation.newDelete(bobUri).build());
288         }
289         Uri charlieUri = lookupContact(CHARLIE_PHONE);
290         if (charlieUri != null) {
291             operationList.add(ContentProviderOperation.newDelete(charlieUri).build());
292         }
293         if (aliceUri != null || bobUri != null || charlieUri != null) {
294             try {
295                 mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
296             } catch (RemoteException e) {
297                 Log.e(TAG, String.format("%s: %s", e, e.getMessage()));
298             } catch (OperationApplicationException e) {
299                 Log.e(TAG, String.format("%s: %s", e, e.getMessage()));
300             }
301         }
302 
303         deleteAllAutomaticZenRules();
304 
305         if (mListener != null) {
306             // setUp asserts mListener isn't null, but tearDown will still run after that assertion
307             // failure.
308             mListener.resetData();
309             mNotificationHelper.disableListener(STUB_PACKAGE_NAME);
310         }
311 
312         deleteChannels();
313     }
314 
sleep()315     private void sleep() {
316         try {
317             Thread.sleep(500);
318         } catch (InterruptedException ignored) {
319         }
320     }
321     // usePriorities true: B, C, A
322     // usePriorities false:
323     //   MODE_NONE: C, B, A
324     //   otherwise: A, B ,C
sendNotifications(int uriMode, boolean usePriorities, boolean noisy)325     private void sendNotifications(int uriMode, boolean usePriorities, boolean noisy) {
326         sendNotifications(SEND_ALL, uriMode, usePriorities, noisy);
327     }
328 
sendNotifications(int which, int uriMode, boolean usePriorities, boolean noisy)329     private void sendNotifications(int which, int uriMode, boolean usePriorities, boolean noisy) {
330         // C, B, A when sorted by time.  Times must be in the past
331         long whenA = System.currentTimeMillis() - 4000000L;
332         long whenB = System.currentTimeMillis() - 2000000L;
333         long whenC = System.currentTimeMillis() - 1000000L;
334 
335         // B, C, A when sorted by priorities
336         int priorityA = usePriorities ? Notification.PRIORITY_MIN : Notification.PRIORITY_DEFAULT;
337         int priorityB = usePriorities ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
338         int priorityC = usePriorities ? Notification.PRIORITY_LOW : Notification.PRIORITY_DEFAULT;
339 
340         final String channelId = noisy ? NOTIFICATION_CHANNEL_ID_NOISY : NOTIFICATION_CHANNEL_ID;
341 
342         Uri aliceUri = lookupContact(ALICE_PHONE);
343         Uri bobUri = lookupContact(BOB_PHONE);
344         Uri charlieUri = lookupContact(CHARLIE_PHONE);
345         if ((which & SEND_B) != 0) {
346             Notification.Builder bob = new Notification.Builder(mContext, channelId)
347                     .setContentTitle(BOB)
348                     .setContentText(BOB)
349                     .setSmallIcon(android.R.drawable.sym_def_app_icon)
350                     .setPriority(priorityB)
351                     .setCategory(Notification.CATEGORY_MESSAGE)
352                     .setWhen(whenB);
353             addPerson(uriMode, bob, bobUri, BOB_PHONE, BOB_EMAIL);
354             mNotificationManager.notify(BOB, 2, bob.build());
355         }
356         if ((which & SEND_C) != 0) {
357             Notification.Builder charlie =
358                     new Notification.Builder(mContext, channelId)
359                             .setContentTitle(CHARLIE)
360                             .setContentText(CHARLIE)
361                             .setSmallIcon(android.R.drawable.sym_def_app_icon)
362                             .setPriority(priorityC)
363                             .setCategory(Notification.CATEGORY_MESSAGE)
364                             .setWhen(whenC);
365             addPerson(uriMode, charlie, charlieUri, CHARLIE_PHONE, CHARLIE_EMAIL);
366             mNotificationManager.notify(CHARLIE, 3, charlie.build());
367         }
368         if ((which & SEND_A) != 0) {
369             Notification.Builder alice = new Notification.Builder(mContext, channelId)
370                     .setContentTitle(ALICE)
371                     .setContentText(ALICE)
372                     .setSmallIcon(android.R.drawable.sym_def_app_icon)
373                     .setPriority(priorityA)
374                     .setCategory(Notification.CATEGORY_MESSAGE)
375                     .setWhen(whenA);
376             addPerson(uriMode, alice, aliceUri, ALICE_PHONE, ALICE_EMAIL);
377             mNotificationManager.notify(ALICE, 1, alice.build());
378         }
379 
380         mNotificationHelper.findPostedNotification(ALICE, 1, SEARCH_TYPE.POSTED);
381         mNotificationHelper.findPostedNotification(BOB, 2, SEARCH_TYPE.POSTED);
382         mNotificationHelper.findPostedNotification(CHARLIE, 3, SEARCH_TYPE.POSTED);
383     }
384 
sendEventAlarmReminderNotifications(int which)385     private void sendEventAlarmReminderNotifications(int which) {
386         long when = System.currentTimeMillis() - 4000000L;
387         final String channelId = NOTIFICATION_CHANNEL_ID;
388 
389         // Event notification to Alice
390         if ((which & SEND_A) != 0) {
391             Notification.Builder alice = new Notification.Builder(mContext, channelId)
392                     .setContentTitle(ALICE)
393                     .setContentText(ALICE)
394                     .setSmallIcon(android.R.drawable.sym_def_app_icon)
395                     .setCategory(Notification.CATEGORY_EVENT)
396                     .setWhen(when);
397             mNotificationManager.notify(ALICE, 4, alice.build());
398         }
399 
400         // Alarm notification to Bob
401         if ((which & SEND_B) != 0) {
402             Notification.Builder bob = new Notification.Builder(mContext, channelId)
403                     .setContentTitle(BOB)
404                     .setContentText(BOB)
405                     .setSmallIcon(android.R.drawable.sym_def_app_icon)
406                     .setCategory(Notification.CATEGORY_ALARM)
407                     .setWhen(when);
408             mNotificationManager.notify(BOB, 5, bob.build());
409         }
410 
411         // Reminder notification to Charlie
412         if ((which & SEND_C) != 0) {
413             Notification.Builder charlie =
414                     new Notification.Builder(mContext, channelId)
415                             .setContentTitle(CHARLIE)
416                             .setContentText(CHARLIE)
417                             .setSmallIcon(android.R.drawable.sym_def_app_icon)
418                             .setCategory(Notification.CATEGORY_REMINDER)
419                             .setWhen(when);
420             mNotificationManager.notify(CHARLIE, 6, charlie.build());
421         }
422 
423         mNotificationHelper.findPostedNotification(ALICE, 4, SEARCH_TYPE.POSTED);
424         mNotificationHelper.findPostedNotification(BOB, 5, SEARCH_TYPE.POSTED);
425         mNotificationHelper.findPostedNotification(CHARLIE, 6, SEARCH_TYPE.POSTED);
426     }
427 
sendAlarmOtherMediaNotifications(int which)428     private void sendAlarmOtherMediaNotifications(int which) {
429         long when = System.currentTimeMillis() - 4000000L;
430         final String channelId = NOTIFICATION_CHANNEL_ID;
431 
432         // Alarm notification to Alice
433         if ((which & SEND_A) != 0) {
434             Notification.Builder alice = new Notification.Builder(mContext, channelId)
435                     .setContentTitle(ALICE)
436                     .setContentText(ALICE)
437                     .setSmallIcon(android.R.drawable.sym_def_app_icon)
438                     .setCategory(Notification.CATEGORY_ALARM)
439                     .setWhen(when);
440             mNotificationManager.notify(ALICE, 7, alice.build());
441         }
442 
443         // "Other" notification to Bob
444         if ((which & SEND_B) != 0) {
445             Notification.Builder bob = new Notification.Builder(mContext,
446                     NOTIFICATION_CHANNEL_ID_GAME)
447                     .setContentTitle(BOB)
448                     .setContentText(BOB)
449                     .setSmallIcon(android.R.drawable.sym_def_app_icon)
450                     .setWhen(when);
451             mNotificationManager.notify(BOB, 8, bob.build());
452         }
453 
454         // Media notification to Charlie
455         if ((which & SEND_C) != 0) {
456             Notification.Builder charlie =
457                     new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID_MEDIA)
458                             .setContentTitle(CHARLIE)
459                             .setContentText(CHARLIE)
460                             .setSmallIcon(android.R.drawable.sym_def_app_icon)
461                             .setWhen(when);
462             mNotificationManager.notify(CHARLIE, 9, charlie.build());
463         }
464 
465         mNotificationHelper.findPostedNotification(ALICE, 7, SEARCH_TYPE.POSTED);
466         mNotificationHelper.findPostedNotification(BOB, 8, SEARCH_TYPE.POSTED);
467         mNotificationHelper.findPostedNotification(CHARLIE, 9, SEARCH_TYPE.POSTED);
468     }
469 
hasReadContactsPermission(String pkgName)470     private boolean hasReadContactsPermission(String pkgName) {
471         return mPackageManager.checkPermission(Manifest.permission.READ_CONTACTS, pkgName)
472                 == PackageManager.PERMISSION_GRANTED;
473     }
474 
toggleReadContactsPermission(String pkgName, boolean on)475     private void toggleReadContactsPermission(String pkgName, boolean on) {
476         SystemUtil.runWithShellPermissionIdentity(() -> {
477             if (on) {
478                 mInstrumentation.getUiAutomation().grantRuntimePermission(pkgName,
479                         Manifest.permission.READ_CONTACTS);
480             } else {
481                 mInstrumentation.getUiAutomation().revokeRuntimePermission(pkgName,
482                         Manifest.permission.READ_CONTACTS);
483             }
484         });
485     }
486 
487     // Creates a GetResultActivity into which one can call startActivityForResult with
488     // in order to test the outcome of an activity that returns a result code.
setUpGetResultActivity()489     private GetResultActivity setUpGetResultActivity() {
490         final Intent intent = new Intent(mContext, GetResultActivity.class);
491         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
492         GetResultActivity activity = (GetResultActivity) mInstrumentation.startActivitySync(intent);
493         mInstrumentation.waitForIdleSync();
494         activity.clearResult();
495         return activity;
496     }
497 
addPerson(int mode, Notification.Builder note, Uri uri, String phone, String email)498     private void addPerson(int mode, Notification.Builder note,
499             Uri uri, String phone, String email) {
500         if (mode == MODE_URI && uri != null) {
501             note.addPerson(uri.toString());
502         } else if (mode == MODE_PHONE) {
503             note.addPerson(Uri.fromParts("tel", phone, null).toString());
504         } else if (mode == MODE_EMAIL) {
505             note.addPerson(Uri.fromParts("mailto", email, null).toString());
506         }
507     }
508 
insertSingleContact(String name, String phone, String email, boolean starred)509     private void insertSingleContact(String name, String phone, String email, boolean starred) {
510         final ArrayList<ContentProviderOperation> operationList =
511                 new ArrayList<ContentProviderOperation>();
512         ContentProviderOperation.Builder builder =
513                 ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI);
514         builder.withValue(ContactsContract.RawContacts.STARRED, starred ? 1 : 0);
515         operationList.add(builder.build());
516 
517         builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
518         builder.withValueBackReference(
519                 ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0);
520         builder.withValue(ContactsContract.Data.MIMETYPE,
521                 ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
522         builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
523         operationList.add(builder.build());
524 
525         if (phone != null) {
526             builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
527             builder.withValueBackReference(
528                     ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID, 0);
529             builder.withValue(ContactsContract.Data.MIMETYPE,
530                     ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
531             builder.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
532                     ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
533             builder.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
534             builder.withValue(ContactsContract.Data.IS_PRIMARY, 1);
535             operationList.add(builder.build());
536         }
537         if (email != null) {
538             builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
539             builder.withValueBackReference(
540                     ContactsContract.CommonDataKinds.Email.RAW_CONTACT_ID, 0);
541             builder.withValue(ContactsContract.Data.MIMETYPE,
542                     ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
543             builder.withValue(ContactsContract.CommonDataKinds.Email.TYPE,
544                     ContactsContract.CommonDataKinds.Email.TYPE_HOME);
545             builder.withValue(ContactsContract.CommonDataKinds.Email.DATA, email);
546             operationList.add(builder.build());
547         }
548 
549         try {
550             mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
551         } catch (RemoteException e) {
552             Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
553         } catch (OperationApplicationException e) {
554             Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
555         }
556     }
557 
lookupContact(String phone)558     private Uri lookupContact(String phone) {
559         Cursor c = null;
560         try {
561             Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
562                     Uri.encode(phone));
563             String[] projection = new String[] { ContactsContract.Contacts._ID,
564                     ContactsContract.Contacts.LOOKUP_KEY };
565             c = mContext.getContentResolver().query(phoneUri, projection, null, null, null);
566             if (c != null && c.getCount() > 0) {
567                 c.moveToFirst();
568                 int lookupIdx = c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
569                 int idIdx = c.getColumnIndex(ContactsContract.Contacts._ID);
570                 String lookupKey = c.getString(lookupIdx);
571                 long contactId = c.getLong(idIdx);
572                 return ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
573             }
574         } catch (Throwable t) {
575             Log.w(TAG, "Problem getting content resolver or performing contacts query.", t);
576         } finally {
577             if (c != null) {
578                 c.close();
579             }
580         }
581         return null;
582     }
583 
isStarred(Uri uri)584     private boolean isStarred(Uri uri) {
585         Cursor c = null;
586         boolean starred = false;
587         try {
588             String[] projection = new String[] { ContactsContract.Contacts.STARRED };
589             c = mContext.getContentResolver().query(uri, projection, null, null, null);
590             if (c != null && c.getCount() > 0) {
591                 int starredIdx = c.getColumnIndex(ContactsContract.Contacts.STARRED);
592                 while (c.moveToNext()) {
593                     starred |= c.getInt(starredIdx) == 1;
594                 }
595             }
596         } catch (Throwable t) {
597             Log.w(TAG, "Problem getting content resolver or performing contacts query.", t);
598         } finally {
599             if (c != null) {
600                 c.close();
601             }
602         }
603         return starred;
604     }
605 
createChannels()606     private void createChannels() {
607         NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
608                 NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_MIN);
609         mNotificationManager.createNotificationChannel(channel);
610         NotificationChannel noisyChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID_NOISY,
611                 NOTIFICATION_CHANNEL_ID_NOISY, NotificationManager.IMPORTANCE_HIGH);
612         noisyChannel.enableVibration(true);
613         mNotificationManager.createNotificationChannel(noisyChannel);
614         NotificationChannel mediaChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID_MEDIA,
615                 NOTIFICATION_CHANNEL_ID_MEDIA, NotificationManager.IMPORTANCE_HIGH);
616         AudioAttributes.Builder aa = new AudioAttributes.Builder()
617                 .setUsage(AudioAttributes.USAGE_MEDIA);
618         mediaChannel.setSound(null, aa.build());
619         mNotificationManager.createNotificationChannel(mediaChannel);
620         NotificationChannel gameChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID_GAME,
621                 NOTIFICATION_CHANNEL_ID_GAME, NotificationManager.IMPORTANCE_HIGH);
622         AudioAttributes.Builder aa2 = new AudioAttributes.Builder()
623                 .setUsage(AudioAttributes.USAGE_GAME);
624         gameChannel.setSound(null, aa2.build());
625         mNotificationManager.createNotificationChannel(gameChannel);
626         if (Flags.modesApi()) {
627             // "Priority" channel has canBypassDnd set to true.
628             NotificationChannel priorityChannel = new NotificationChannel(
629                     NOTIFICATION_CHANNEL_ID_PRIORITY, NOTIFICATION_CHANNEL_ID_PRIORITY,
630                     NotificationManager.IMPORTANCE_HIGH);
631             priorityChannel.setBypassDnd(true);
632             mNotificationManager.createNotificationChannel(priorityChannel);
633         }
634     }
635 
deleteChannels()636     private void deleteChannels() {
637         mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
638         mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID_NOISY);
639         mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID_MEDIA);
640         mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID_GAME);
641         if (Flags.modesApi()) {
642             mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID_PRIORITY);
643         }
644     }
645 
deleteAllAutomaticZenRules()646     private void deleteAllAutomaticZenRules() {
647         Map<String, AutomaticZenRule> rules = mNotificationManager.getAutomaticZenRules();
648         for (String ruleId : rules.keySet()) {
649             // Delete rules "as system" so they are not preserved.
650             // Otherwise, if updated with fromUser=true and then deleted "as app", they might be
651             // resurrected by other tests, making the outcome order-dependent.
652             runAsSystemUi(() -> mNotificationManager.removeAutomaticZenRule(ruleId));
653         }
654     }
655 
deleteSingleContact(Uri uri)656     private void deleteSingleContact(Uri uri) {
657         final ArrayList<ContentProviderOperation> operationList =
658                 new ArrayList<ContentProviderOperation>();
659         operationList.add(ContentProviderOperation.newDelete(uri).build());
660         try {
661             mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
662         } catch (RemoteException e) {
663             Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
664         } catch (OperationApplicationException e) {
665             Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
666         }
667     }
668 
findTagInKeys(String tag, List<String> orderedKeys)669     private int findTagInKeys(String tag, List<String> orderedKeys) {
670         for (int i = 0; i < orderedKeys.size(); i++) {
671             if (orderedKeys.get(i).contains(tag)) {
672                 return i;
673             }
674         }
675         return -1;
676     }
677 
678     // Simple helper function to take a phone number's string representation and make a tel: uri
makePhoneUri(String phone)679     private Uri makePhoneUri(String phone) {
680         return new Uri.Builder()
681                 .scheme("tel")
682                 .encodedOpaquePart(phone)  // don't re-encode anything passed in
683                 .build();
684     }
685 
686     // Returns whether ZenPolicies are equivalent after any unset fields are set to the defaults.
doPoliciesMatchWithDefaults(ZenPolicy a, ZenPolicy b)687     private boolean doPoliciesMatchWithDefaults(ZenPolicy a, ZenPolicy b) {
688         return Objects.equals(mDefaultPolicy.overwrittenWith(a), mDefaultPolicy.overwrittenWith(b));
689     }
690 
createRule(String name, int filter)691     private AutomaticZenRule createRule(String name, int filter) {
692         return new AutomaticZenRule(name, null,
693                 new ComponentName(mContext, AutomaticZenRuleActivity.class),
694                 new Uri.Builder().scheme("scheme")
695                         .appendPath("path")
696                         .appendQueryParameter("fake_rule", "fake_value")
697                         .build(), null, filter, true);
698     }
699 
createRule(String name)700     private AutomaticZenRule createRule(String name) {
701         return createRule(name, INTERRUPTION_FILTER_PRIORITY);
702     }
703 
704     // TESTS START
705 
706     @Test
707     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
708     @RequiresFlagsDisabled(Flags.FLAG_MODES_UI)
testAreAutomaticZenRulesUserManaged_flagsOff()709     public void testAreAutomaticZenRulesUserManaged_flagsOff() {
710         assertFalse(mNotificationManager.areAutomaticZenRulesUserManaged());
711     }
712 
713     @Test
714     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
testAreAutomaticZenRulesUserManaged_flagsOn()715     public void testAreAutomaticZenRulesUserManaged_flagsOn() {
716         if (mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE)
717                 || mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
718             assertFalse(mNotificationManager.areAutomaticZenRulesUserManaged());
719         } else {
720             assertTrue(mNotificationManager.areAutomaticZenRulesUserManaged());
721         }
722     }
723 
724     @Test
testNotificationPolicyVisualEffectsEqual()725     public void testNotificationPolicyVisualEffectsEqual() {
726         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
727                 SUPPRESSED_EFFECT_SCREEN_ON);
728         NotificationManager.Policy policy2 = new NotificationManager.Policy(0, 0, 0,
729                 SUPPRESSED_EFFECT_PEEK);
730         assertTrue(policy.equals(policy2));
731         assertTrue(policy2.equals(policy));
732 
733         policy = new NotificationManager.Policy(0, 0, 0,
734                 SUPPRESSED_EFFECT_SCREEN_ON);
735         policy2 = new NotificationManager.Policy(0, 0, 0,
736                 0);
737         assertFalse(policy.equals(policy2));
738         assertFalse(policy2.equals(policy));
739 
740         policy = new NotificationManager.Policy(0, 0, 0,
741                 SUPPRESSED_EFFECT_SCREEN_OFF);
742         policy2 = new NotificationManager.Policy(0, 0, 0,
743                 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_AMBIENT
744                         | SUPPRESSED_EFFECT_LIGHTS);
745         assertTrue(policy.equals(policy2));
746         assertTrue(policy2.equals(policy));
747 
748         policy = new NotificationManager.Policy(0, 0, 0,
749                 SUPPRESSED_EFFECT_SCREEN_OFF);
750         policy2 = new NotificationManager.Policy(0, 0, 0,
751                 SUPPRESSED_EFFECT_LIGHTS);
752         assertFalse(policy.equals(policy2));
753         assertFalse(policy2.equals(policy));
754     }
755 
756     @Test
testGetSuppressedVisualEffectsOff_ranking()757     public void testGetSuppressedVisualEffectsOff_ranking() throws Exception {
758         mListener = mNotificationHelper.enableListener(STUB_PACKAGE_NAME);
759         assertNotNull(mListener);
760 
761         final int notificationId = 1;
762         sendNotification(notificationId, R.drawable.black);
763         Thread.sleep(500); // wait for notification listener to receive notification
764 
765         NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
766         NotificationListenerService.Ranking outRanking =
767                 new NotificationListenerService.Ranking();
768 
769         for (String key : rankingMap.getOrderedKeys()) {
770             if (key.contains(mListener.getPackageName())) {
771                 rankingMap.getRanking(key, outRanking);
772 
773                 // check notification key match
774                 assertEquals(0, outRanking.getSuppressedVisualEffects());
775             }
776         }
777     }
778 
779     @Test
testGetSuppressedVisualEffects_ranking()780     public void testGetSuppressedVisualEffects_ranking() throws Exception {
781         final int originalFilter = mNotificationManager.getCurrentInterruptionFilter();
782         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
783         try {
784             mListener = mNotificationHelper.enableListener(STUB_PACKAGE_NAME);
785             assertNotNull(mListener);
786 
787             toggleNotificationPolicyAccess(mContext.getPackageName(),
788                     InstrumentationRegistry.getInstrumentation(), true);
789             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
790                 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0,
791                         SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK));
792             } else {
793                 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0,
794                         SUPPRESSED_EFFECT_SCREEN_ON));
795             }
796             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
797 
798             final int notificationId = 1;
799             // update notification
800             sendNotification(notificationId, R.drawable.black);
801             Thread.sleep(500); // wait for notification listener to receive notification
802 
803             NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
804             NotificationListenerService.Ranking outRanking =
805                     new NotificationListenerService.Ranking();
806 
807             for (String key : rankingMap.getOrderedKeys()) {
808                 if (key.contains(mListener.getPackageName())) {
809                     rankingMap.getRanking(key, outRanking);
810 
811                     if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
812                         assertEquals(SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK,
813                                 outRanking.getSuppressedVisualEffects());
814                     } else {
815                         assertEquals(SUPPRESSED_EFFECT_SCREEN_ON,
816                                 outRanking.getSuppressedVisualEffects());
817                     }
818                 }
819             }
820         } finally {
821             // reset notification policy
822             mNotificationManager.setInterruptionFilter(originalFilter);
823             mNotificationManager.setNotificationPolicy(origPolicy);
824         }
825 
826     }
827 
828     @Test
testConsolidatedNotificationPolicy()829     public void testConsolidatedNotificationPolicy() throws Exception {
830         final int originalFilter = mNotificationManager.getCurrentInterruptionFilter();
831         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
832         try {
833             toggleNotificationPolicyAccess(mContext.getPackageName(),
834                     InstrumentationRegistry.getInstrumentation(), true);
835 
836             // no custom ZenPolicy, so consolidatedPolicy should equal the default notif policy
837             assertEquals(mNotificationManager.getConsolidatedNotificationPolicy(),
838                     mNotificationManager.getNotificationPolicy());
839 
840             // setup custom ZenPolicy for an automatic rule
841             AutomaticZenRule rule = createRule("test_consolidated_policy",
842                     INTERRUPTION_FILTER_PRIORITY);
843             rule.setZenPolicy(new ZenPolicy.Builder()
844                     .allowReminders(true)
845                     .allowMedia(false)
846                     .build());
847             String id = mNotificationManager.addAutomaticZenRule(rule);
848             // set condition of the automatic rule to TRUE
849             Condition condition = new Condition(rule.getConditionId(), "summary",
850                     Condition.STATE_TRUE);
851             mNotificationManager.setAutomaticZenRuleState(id, condition);
852 
853             Thread.sleep(300); // wait for rules to be applied - it's done asynchronously
854 
855             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
856 
857             NotificationManager.Policy consolidatedPolicy =
858                     mNotificationManager.getConsolidatedNotificationPolicy();
859 
860             if (Flags.modesApi()) {
861                 // Expect the final consolidated policy to be effectively equivalent to the
862                 // specified custom policy with remaining fields filled in by defaults.
863                 ZenPolicy fullySpecified = mDefaultPolicy.overwrittenWith(rule.getZenPolicy());
864                 assertPolicyCategoriesMatchZenPolicy(consolidatedPolicy, fullySpecified);
865             } else {
866                 // reminders is allowed from the automatic rule's custom ZenPolicy
867                 assertTrue(
868                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_REMINDERS) != 0);
869 
870                 // media is disallowed from the automatic rule's custom ZenPolicy
871                 assertFalse((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_MEDIA) != 0);
872 
873                 // other stuff is from the default notification policy (see #setUp)
874                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS) != 0);
875                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS)
876                         != 0);
877                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_CALLS) != 0);
878                 assertTrue(
879                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_REPEAT_CALLERS)
880                             != 0);
881                 assertTrue(
882                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_MESSAGES) != 0);
883                 assertFalse(
884                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_SYSTEM) != 0);
885                 assertFalse(
886                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_EVENTS) != 0);
887             }
888         } finally {
889             mNotificationManager.setInterruptionFilter(originalFilter);
890             mNotificationManager.setNotificationPolicy(origPolicy);
891         }
892     }
893 
894     @Test
testConsolidatedNotificationPolicyMultiRules()895     public void testConsolidatedNotificationPolicyMultiRules() throws Exception {
896         final int originalFilter = mNotificationManager.getCurrentInterruptionFilter();
897         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
898         try {
899             toggleNotificationPolicyAccess(mContext.getPackageName(),
900                     InstrumentationRegistry.getInstrumentation(), true);
901 
902             // setup custom ZenPolicy for two automatic rules
903             AutomaticZenRule rule1 = createRule("test_consolidated_policyq",
904                     INTERRUPTION_FILTER_PRIORITY);
905             rule1.setZenPolicy(new ZenPolicy.Builder()
906                     .allowReminders(false)
907                     .allowSystem(true)
908                     .allowAlarms(false)
909                     .build());
910             AutomaticZenRule rule2 = createRule("test_consolidated_policy2",
911                     INTERRUPTION_FILTER_PRIORITY);
912             rule2.setZenPolicy(new ZenPolicy.Builder()
913                     .allowReminders(true)
914                     .allowSystem(true)
915                     .allowMedia(true)
916                     .build());
917             String id1 = mNotificationManager.addAutomaticZenRule(rule1);
918             String id2 = mNotificationManager.addAutomaticZenRule(rule2);
919             Condition onCondition1 = new Condition(rule1.getConditionId(), "summary",
920                     Condition.STATE_TRUE);
921             Condition onCondition2 = new Condition(rule2.getConditionId(), "summary",
922                     Condition.STATE_TRUE);
923             mNotificationManager.setAutomaticZenRuleState(id1, onCondition1);
924             mNotificationManager.setAutomaticZenRuleState(id2, onCondition2);
925 
926             Thread.sleep(300); // wait for rules to be applied - it's done asynchronously
927 
928             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
929 
930             NotificationManager.Policy consolidatedPolicy =
931                     mNotificationManager.getConsolidatedNotificationPolicy();
932 
933             if (Flags.modesApi()) {
934                 // if modesApi is enabled, confirm that these settings match depending on the device
935                 // defaults. Each rule inherits default values for any unset fields, so for fields
936                 // where only one rule has expressed an explicit opinion about the setting, the
937                 // default setting may be more restrictive and win.
938                 ZenPolicy expectedCombined = new ZenPolicy.Builder()
939                         .allowReminders(false)  // rule1 wins over rule2
940                         .allowSystem(true)  // both active rules set this
941                         .allowAlarms(false)  // opinion only from rule1
942                         // media opinion only from rule2 (to be allowed); therefore it depends on
943                         // default settings
944                         .allowMedia(
945                                 mDefaultPolicy.getPriorityCategoryAlarms() == ZenPolicy.STATE_ALLOW)
946                         .build();
947 
948                 // The rest are entirely from the default policy.
949                 ZenPolicy fullySpecified = mDefaultPolicy.overwrittenWith(expectedCombined);
950                 assertPolicyCategoriesMatchZenPolicy(consolidatedPolicy, fullySpecified);
951             } else {
952                 // reminders aren't allowed from rule1 overriding rule2
953                 // (not allowed takes precedence over allowed)
954                 assertTrue(
955                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_REMINDERS) == 0);
956 
957                 // system allowed from both
958                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_SYSTEM) != 0);
959 
960                 // alarms aren't allowed from rule1, so that alarm setting will always win
961                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS) == 0);
962 
963                 // media is allowed from rule2
964                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_MEDIA) != 0);
965 
966                 // other stuff is from the default notification policy (see #setUp)
967                 assertTrue(
968                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS)
969                             != 0);
970                 assertTrue((consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_CALLS) != 0);
971                 assertTrue(
972                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_MESSAGES) != 0);
973                 assertFalse(
974                         (consolidatedPolicy.priorityCategories & PRIORITY_CATEGORY_EVENTS) != 0);
975             }
976         } finally {
977             mNotificationManager.setInterruptionFilter(originalFilter);
978             mNotificationManager.setNotificationPolicy(origPolicy);
979         }
980     }
981 
982     @Test
983     @RequiresFlagsEnabled({Flags.FLAG_MODES_API})
testConsolidatedNotificationPolicy_broadcasts()984     public void testConsolidatedNotificationPolicy_broadcasts() throws Exception {
985         // Setup also changes Policy and creates a DND-bypassing channel, so we might get 1-2
986         // extra broadcasts. Make sure they are out of the way.
987         Thread.sleep(500);
988         assertThat(mNotificationManager.getConsolidatedNotificationPolicy().priorityCategories
989                 & PRIORITY_CATEGORY_ALARMS).isNotEqualTo(0);
990 
991         // Set up a rule with a custom ZenPolicy.
992         AutomaticZenRule rule = createRule("testRule");
993         rule.setZenPolicy(new ZenPolicy.Builder()
994                 .allowReminders(false)
995                 .allowSystem(true)
996                 .allowAlarms(false)
997                 .build());
998         String id = mNotificationManager.addAutomaticZenRule(rule);
999 
1000         // Enable rule, and check for broadcast.
1001         NotificationManagerBroadcastReceiver brOn = new NotificationManagerBroadcastReceiver();
1002         brOn.register(mContext, ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED, 1);
1003         Condition conditionOn =
1004                 new Condition(rule.getConditionId(), "on", Condition.STATE_TRUE);
1005         mNotificationManager.setAutomaticZenRuleState(id, conditionOn);
1006 
1007         brOn.assertBroadcastsReceivedWithin(Duration.ofMillis(500));
1008         NotificationManager.Policy ruleOnPolicy = (NotificationManager.Policy) brOn.getExtra(
1009                 NotificationManager.EXTRA_NOTIFICATION_POLICY, 0, 0);
1010         assertThat(ruleOnPolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS).isEqualTo(0);
1011 
1012         // TODO: b/324376849 - Registered BR in a DND-access pkg gets broadcast twice.
1013         // Thread.sleep(500);
1014         // assertThat(brOn.results).hasSize(1); // Also no *extra* broadcasts received.
1015         brOn.unregister();
1016 
1017         // Disable rule, and check for broadcast.
1018         NotificationManagerBroadcastReceiver brOff = new NotificationManagerBroadcastReceiver();
1019         brOff.register(mContext, ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED, 1);
1020         Condition conditionOff =
1021                 new Condition(rule.getConditionId(), "on", Condition.STATE_FALSE);
1022         mNotificationManager.setAutomaticZenRuleState(id, conditionOff);
1023 
1024         brOff.assertBroadcastsReceivedWithin(Duration.ofMillis(500));
1025         NotificationManager.Policy ruleOffPolicy = (NotificationManager.Policy) brOff.getExtra(
1026                 NotificationManager.EXTRA_NOTIFICATION_POLICY, 0, 0);
1027         assertThat(ruleOffPolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS).isNotEqualTo(0);
1028 
1029         // TODO: b/324376849 - Registered BR in a DND-access pkg gets broadcast twice.
1030         // Thread.sleep(500);
1031         // assertThat(brOff.results).hasSize(1); // Also no *extra* broadcasts received.
1032         brOff.unregister();
1033     }
1034 
1035     @Test
testNotificationPolicy_broadcasts()1036     public void testNotificationPolicy_broadcasts() throws Exception {
1037         // Setup also changes Policy and creates a DND-bypassing channel, so we might get 1-2
1038         // extra broadcasts. Make sure they are out of the way.
1039         Thread.sleep(500);
1040         assertThat(mNotificationManager.getNotificationPolicy().priorityCategories
1041                 & PRIORITY_CATEGORY_ALARMS).isNotEqualTo(0);
1042         NotificationManagerBroadcastReceiver br = new NotificationManagerBroadcastReceiver();
1043         br.register(mContext, ACTION_NOTIFICATION_POLICY_CHANGED, 1);
1044 
1045         NotificationManager.Policy updatePolicy = new NotificationManager.Policy(0, 0, 0);
1046         runAsSystemUi(() -> mNotificationManager.setNotificationPolicy(updatePolicy));
1047 
1048         br.assertBroadcastsReceivedWithin(Duration.ofMillis(500));
1049         if (Flags.modesApi()) {
1050             NotificationManager.Policy broadcastPolicy = (NotificationManager.Policy) br.getExtra(
1051                     NotificationManager.EXTRA_NOTIFICATION_POLICY, 0, 0);
1052             assertThat(broadcastPolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS).isEqualTo(0);
1053         }
1054     }
1055 
1056     @Test
1057     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
testConsolidatedNotificationPolicy_mergesAllowPriorityChannels()1058     public void testConsolidatedNotificationPolicy_mergesAllowPriorityChannels() throws Exception {
1059         toggleNotificationPolicyAccess(mContext.getPackageName(),
1060                 InstrumentationRegistry.getInstrumentation(), true);
1061 
1062         // setup custom ZenPolicy for an automatic rule
1063         AutomaticZenRule rule = createRule("test_consolidated_policy_priority_channels",
1064                 INTERRUPTION_FILTER_PRIORITY);
1065         rule.setZenPolicy(new ZenPolicy.Builder()
1066                 .allowPriorityChannels(true)
1067                 .build());
1068         String id = mNotificationManager.addAutomaticZenRule(rule);
1069         // set condition of the automatic rule to TRUE
1070         Condition condition = new Condition(rule.getConditionId(), "summary",
1071                 Condition.STATE_TRUE);
1072         mNotificationManager.setAutomaticZenRuleState(id, condition);
1073 
1074         Thread.sleep(300); // wait for rules to be applied - it's done asynchronously
1075 
1076         assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1077 
1078         NotificationManager.Policy consolidatedPolicy =
1079                 mNotificationManager.getConsolidatedNotificationPolicy();
1080 
1081         // channels are permitted as set by the rule
1082         assertTrue(consolidatedPolicy.allowPriorityChannels());
1083 
1084         // new rule that disallows channels
1085         AutomaticZenRule rule2 = createRule("test_consolidated_policy_no_channels",
1086                 INTERRUPTION_FILTER_PRIORITY);
1087         rule2.setZenPolicy(new ZenPolicy.Builder()
1088                 .allowPriorityChannels(false)
1089                 .build());
1090         String id2 = mNotificationManager.addAutomaticZenRule(rule2);
1091         Condition onCondition2 = new Condition(rule2.getConditionId(), "summary",
1092                 Condition.STATE_TRUE);
1093         mNotificationManager.setAutomaticZenRuleState(id2, onCondition2);
1094 
1095         // now priority channels are disallowed because "no channels" overrides "priority"
1096         consolidatedPolicy =
1097                 mNotificationManager.getConsolidatedNotificationPolicy();
1098         assertFalse(consolidatedPolicy.allowPriorityChannels());
1099     }
1100 
1101     @Test
testPostPCanToggleAlarmsMediaSystemTest()1102     public void testPostPCanToggleAlarmsMediaSystemTest() throws Exception {
1103         toggleNotificationPolicyAccess(mContext.getPackageName(),
1104                 InstrumentationRegistry.getInstrumentation(), true);
1105 
1106         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1107         try {
1108             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
1109                 // Post-P can toggle alarms, media, system
1110                 // toggle on alarms, media, system:
1111                 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1112                         PRIORITY_CATEGORY_ALARMS
1113                                 | PRIORITY_CATEGORY_MEDIA
1114                                 | PRIORITY_CATEGORY_SYSTEM, 0, 0));
1115                 NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
1116                 assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_ALARMS) != 0);
1117                 assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_MEDIA) != 0);
1118                 assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_SYSTEM) != 0);
1119 
1120                 // toggle off alarms, media, system
1121                 mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
1122                 policy = mNotificationManager.getNotificationPolicy();
1123                 assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_ALARMS) == 0);
1124                 assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_MEDIA) == 0);
1125                 assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_SYSTEM) == 0);
1126             }
1127         } finally {
1128             mNotificationManager.setNotificationPolicy(origPolicy);
1129         }
1130     }
1131 
1132     @Test
testPostRCanToggleConversationsTest()1133     public void testPostRCanToggleConversationsTest() throws Exception {
1134         toggleNotificationPolicyAccess(mContext.getPackageName(),
1135                 InstrumentationRegistry.getInstrumentation(), true);
1136 
1137         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1138 
1139         try {
1140             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1141                     0, 0, 0, 0));
1142             NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
1143             assertEquals(0, (policy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS));
1144             assertEquals(CONVERSATION_SENDERS_NONE, policy.priorityConversationSenders);
1145 
1146             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1147                     PRIORITY_CATEGORY_CONVERSATIONS, 0, 0, 0, CONVERSATION_SENDERS_ANYONE));
1148             policy = mNotificationManager.getNotificationPolicy();
1149             assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) != 0);
1150             assertEquals(CONVERSATION_SENDERS_ANYONE, policy.priorityConversationSenders);
1151 
1152         } finally {
1153             mNotificationManager.setNotificationPolicy(origPolicy);
1154         }
1155     }
1156 
1157     @Test
testTotalSilenceOnlyMuteStreams()1158     public void testTotalSilenceOnlyMuteStreams() throws Exception {
1159         assumeFalse("Skipping test on automotive platform",
1160                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
1161 
1162         toggleNotificationPolicyAccess(mContext.getPackageName(),
1163                 InstrumentationRegistry.getInstrumentation(), true);
1164 
1165         // ensure volume is not muted/0 to start test
1166         mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
1167         // exception for presidential alert
1168         //mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 1, 0);
1169         mAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, 1, 0);
1170         mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 1, 0);
1171 
1172         AutomaticZenRule rule = createRule("test_total_silence", INTERRUPTION_FILTER_NONE);
1173         String id = mNotificationManager.addAutomaticZenRule(rule);
1174         Condition condition =
1175                 new Condition(rule.getConditionId(), "summary", Condition.STATE_TRUE);
1176         mNotificationManager.setAutomaticZenRuleState(id, condition);
1177         if (!SdkLevel.isAtLeastV()) {
1178             runAsSystemUi(
1179                     () -> mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY));
1180         }
1181 
1182         // delay for streams to get into correct mute states
1183         Thread.sleep(1000);
1184         assertTrue("Music (media) stream should be muted",
1185                 mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
1186         assertTrue("System stream should be muted",
1187                 mAudioManager.isStreamMute(AudioManager.STREAM_SYSTEM));
1188         // exception for presidential alert
1189         //assertTrue("Alarm stream should be muted",
1190         //        mAudioManager.isStreamMute(AudioManager.STREAM_ALARM));
1191 
1192         if (SdkLevel.isAtLeastV()) {
1193             // For the audio stream to be muted correctly, we need the priority channels setting;
1194             // otherwise, pre-V, we cannot guarantee that no channels are bypassing DND.
1195             assertTrue("Ringer stream should be muted",
1196                     mAudioManager.isStreamMute(AudioManager.STREAM_RING));
1197         }
1198     }
1199 
1200     @Test
testAlarmsOnlyMuteStreams()1201     public void testAlarmsOnlyMuteStreams() throws Exception {
1202         assumeFalse("Skipping test on automotive platform",
1203                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
1204 
1205         toggleNotificationPolicyAccess(mContext.getPackageName(),
1206                 InstrumentationRegistry.getInstrumentation(), true);
1207 
1208         // ensure volume is not muted/0 to start test
1209         mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
1210         mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 1, 0);
1211         mAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, 1, 0);
1212         mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 1, 0);
1213 
1214         if (!SdkLevel.isAtLeastV()) {
1215             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1216                     PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_MEDIA, 0, 0));
1217         }
1218         AutomaticZenRule rule = createRule("test_alarms", INTERRUPTION_FILTER_ALARMS);
1219         String id = mNotificationManager.addAutomaticZenRule(rule);
1220         Condition condition =
1221                 new Condition(rule.getConditionId(), "summary", Condition.STATE_TRUE);
1222         mNotificationManager.setAutomaticZenRuleState(id, condition);
1223         if (!SdkLevel.isAtLeastV()) {
1224             runAsSystemUi(
1225                     () -> mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY));
1226         }
1227 
1228         // delay for streams to get into correct mute states
1229         Thread.sleep(1000);
1230         assertFalse("Music (media) stream should not be muted",
1231                 mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
1232         assertTrue("System stream should be muted",
1233                 mAudioManager.isStreamMute(AudioManager.STREAM_SYSTEM));
1234         assertFalse("Alarm stream should not be muted",
1235                 mAudioManager.isStreamMute(AudioManager.STREAM_ALARM));
1236 
1237         if (SdkLevel.isAtLeastV()) {
1238             // For the audio stream to be muted correctly, we need the priority channels setting;
1239             // otherwise, pre-V, we cannot guarantee that no channels are bypassing DND.
1240             assertTrue("Ringer stream should be muted",
1241                     mAudioManager.isStreamMute(AudioManager.STREAM_RING));
1242         }
1243     }
1244 
1245     @Test
testAddAutomaticZenRule_configActivity()1246     public void testAddAutomaticZenRule_configActivity() throws Exception {
1247         toggleNotificationPolicyAccess(mContext.getPackageName(),
1248                 InstrumentationRegistry.getInstrumentation(), true);
1249 
1250         AutomaticZenRule ruleToCreate = createRule("Rule");
1251         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1252 
1253         assertNotNull(id);
1254         assertRulesEqual(ruleToCreate, mNotificationManager.getAutomaticZenRule(id));
1255     }
1256 
1257     @Test
testUpdateAutomaticZenRule_configActivity()1258     public void testUpdateAutomaticZenRule_configActivity() throws Exception {
1259         toggleNotificationPolicyAccess(mContext.getPackageName(),
1260                 InstrumentationRegistry.getInstrumentation(), true);
1261 
1262         AutomaticZenRule ruleToCreate = createRule("Rule");
1263         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1264         ruleToCreate.setEnabled(false);
1265         mNotificationManager.updateAutomaticZenRule(id, ruleToCreate);
1266 
1267         assertNotNull(id);
1268         assertRulesEqual(ruleToCreate, mNotificationManager.getAutomaticZenRule(id));
1269     }
1270 
1271     @Test
testRemoveAutomaticZenRule_configActivity()1272     public void testRemoveAutomaticZenRule_configActivity() throws Exception {
1273         toggleNotificationPolicyAccess(mContext.getPackageName(),
1274                 InstrumentationRegistry.getInstrumentation(), true);
1275 
1276         AutomaticZenRule ruleToCreate = createRule("Rule");
1277         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1278 
1279         assertNotNull(id);
1280         mNotificationManager.removeAutomaticZenRule(id);
1281 
1282         assertNull(mNotificationManager.getAutomaticZenRule(id));
1283         assertEquals(0, mNotificationManager.getAutomaticZenRules().size());
1284     }
1285 
1286     @Test
testSetAutomaticZenRuleState()1287     public void testSetAutomaticZenRuleState() throws Exception {
1288         toggleNotificationPolicyAccess(mContext.getPackageName(),
1289                 InstrumentationRegistry.getInstrumentation(), true);
1290 
1291         AutomaticZenRule ruleToCreate = createRule("Rule");
1292         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1293 
1294         // make sure DND is off
1295         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1296 
1297         // enable DND
1298         Condition condition =
1299                 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE);
1300         mNotificationManager.setAutomaticZenRuleState(id, condition);
1301 
1302         assertExpectedDndState(ruleToCreate.getInterruptionFilter());
1303     }
1304 
1305     @Test
testSetAutomaticZenRuleState_turnOff()1306     public void testSetAutomaticZenRuleState_turnOff() throws Exception {
1307         toggleNotificationPolicyAccess(mContext.getPackageName(),
1308                 InstrumentationRegistry.getInstrumentation(), true);
1309 
1310         AutomaticZenRule ruleToCreate = createRule("Rule");
1311         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1312 
1313         // make sure DND is off
1314         // make sure DND is off
1315         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1316 
1317         // enable DND
1318         Condition condition =
1319                 new Condition(ruleToCreate.getConditionId(), "on", Condition.STATE_TRUE);
1320         mNotificationManager.setAutomaticZenRuleState(id, condition);
1321 
1322         assertExpectedDndState(ruleToCreate.getInterruptionFilter());
1323 
1324         // disable DND
1325         condition = new Condition(ruleToCreate.getConditionId(), "off", Condition.STATE_FALSE);
1326 
1327         mNotificationManager.setAutomaticZenRuleState(id, condition);
1328 
1329         // make sure DND is off
1330         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1331     }
1332 
1333     @Test
testSetAutomaticZenRuleState_deletedRule()1334     public void testSetAutomaticZenRuleState_deletedRule() throws Exception {
1335         toggleNotificationPolicyAccess(mContext.getPackageName(),
1336                 InstrumentationRegistry.getInstrumentation(), true);
1337 
1338         AutomaticZenRule ruleToCreate = createRule("Rule");
1339         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1340 
1341         // make sure DND is off
1342         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1343 
1344         // enable DND
1345         Condition condition =
1346                 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE);
1347         mNotificationManager.setAutomaticZenRuleState(id, condition);
1348 
1349         assertExpectedDndState(ruleToCreate.getInterruptionFilter());
1350 
1351         mNotificationManager.removeAutomaticZenRule(id);
1352 
1353         // make sure DND is off
1354         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1355     }
1356 
1357     @Test
testSetAutomaticZenRuleState_multipleRules()1358     public void testSetAutomaticZenRuleState_multipleRules() throws Exception {
1359         toggleNotificationPolicyAccess(mContext.getPackageName(),
1360                 InstrumentationRegistry.getInstrumentation(), true);
1361 
1362         AutomaticZenRule ruleToCreate = createRule("Rule");
1363         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
1364 
1365         AutomaticZenRule secondRuleToCreate = createRule("Rule 2");
1366         secondRuleToCreate.setInterruptionFilter(INTERRUPTION_FILTER_NONE);
1367         String secondId = mNotificationManager.addAutomaticZenRule(secondRuleToCreate);
1368 
1369         // make sure DND is off
1370         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1371 
1372         // enable DND
1373         Condition condition =
1374                 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE);
1375         mNotificationManager.setAutomaticZenRuleState(id, condition);
1376         Condition secondCondition =
1377                 new Condition(secondRuleToCreate.getConditionId(), "summary", Condition.STATE_TRUE);
1378         mNotificationManager.setAutomaticZenRuleState(secondId, secondCondition);
1379 
1380         // the second rule has a 'more silent' DND filter, so the system wide DND should be
1381         // using its filter
1382         assertExpectedDndState(secondRuleToCreate.getInterruptionFilter());
1383 
1384         // remove intense rule, system should fallback to other rule
1385         mNotificationManager.removeAutomaticZenRule(secondId);
1386         assertExpectedDndState(ruleToCreate.getInterruptionFilter());
1387     }
1388 
1389     @Test
testSetNotificationPolicy_P_setOldFields()1390     public void testSetNotificationPolicy_P_setOldFields() throws Exception {
1391         toggleNotificationPolicyAccess(mContext.getPackageName(),
1392                 InstrumentationRegistry.getInstrumentation(), true);
1393         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1394         try {
1395             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
1396                 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
1397                         SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
1398                 mNotificationManager.setNotificationPolicy(appPolicy);
1399 
1400                 int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
1401                         | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
1402                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1403 
1404                 assertEquals(expected,
1405                         mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
1406             }
1407         } finally {
1408             mNotificationManager.setNotificationPolicy(origPolicy);
1409         }
1410     }
1411 
1412     @Test
testSetNotificationPolicy_P_setNewFields()1413     public void testSetNotificationPolicy_P_setNewFields() throws Exception {
1414         toggleNotificationPolicyAccess(mContext.getPackageName(),
1415                 InstrumentationRegistry.getInstrumentation(), true);
1416         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1417         try {
1418             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
1419                 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
1420                         SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
1421                                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
1422                 mNotificationManager.setNotificationPolicy(appPolicy);
1423 
1424                 int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
1425                         | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
1426                         | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1427                 assertEquals(expected,
1428                         mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
1429             }
1430         } finally {
1431             mNotificationManager.setNotificationPolicy(origPolicy);
1432         }
1433     }
1434 
1435     @Test
testSetNotificationPolicy_P_setOldNewFields()1436     public void testSetNotificationPolicy_P_setOldNewFields() throws Exception {
1437         toggleNotificationPolicyAccess(mContext.getPackageName(),
1438                 InstrumentationRegistry.getInstrumentation(), true);
1439         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1440         try {
1441             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
1442 
1443                 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
1444                         SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
1445                 mNotificationManager.setNotificationPolicy(appPolicy);
1446 
1447                 int expected = SUPPRESSED_EFFECT_STATUS_BAR;
1448                 assertEquals(expected,
1449                         mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
1450 
1451                 appPolicy = new NotificationManager.Policy(0, 0, 0,
1452                         SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
1453                                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
1454                 mNotificationManager.setNotificationPolicy(appPolicy);
1455 
1456                 expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
1457                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1458                 assertEquals(expected,
1459                         mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
1460             }
1461         } finally {
1462             mNotificationManager.setNotificationPolicy(origPolicy);
1463         }
1464     }
1465 
1466 
1467     @Test
testMatchesCallFilter_noPermissions()1468     public void testMatchesCallFilter_noPermissions() {
1469         // make sure we definitely don't have contacts access
1470         boolean hadReadPerm = hasReadContactsPermission(TEST_APP);
1471         try {
1472             toggleReadContactsPermission(TEST_APP, false);
1473 
1474             // start an activity that has no permissions, which will run matchesCallFilter on
1475             // a meaningless uri. The result code indicates whether or not the method call was
1476             // permitted.
1477             final Intent mcfIntent = new Intent(Intent.ACTION_MAIN);
1478             mcfIntent.setClassName(TEST_APP, MATCHES_CALL_FILTER_CLASS);
1479             GetResultActivity grActivity = setUpGetResultActivity();
1480             grActivity.startActivityForResult(mcfIntent, REQUEST_CODE);
1481             UiDevice.getInstance(mInstrumentation).waitForIdle();
1482 
1483             // with no permissions, this call should not have been permitted
1484             GetResultActivity.Result result = grActivity.getResult();
1485             assertEquals(REQUEST_CODE, result.requestCode);
1486             assertEquals(MATCHES_CALL_FILTER_NOT_PERMITTED, result.resultCode);
1487             grActivity.finishActivity(REQUEST_CODE);
1488         } finally {
1489             toggleReadContactsPermission(TEST_APP, hadReadPerm);
1490         }
1491     }
1492 
1493     @Test
testMatchesCallFilter_listenerPermissionOnly()1494     public void testMatchesCallFilter_listenerPermissionOnly() throws Exception {
1495         boolean hadReadPerm = hasReadContactsPermission(TEST_APP);
1496         // minimal listener service so that it can be given listener permissions
1497         final ComponentName listenerComponent =
1498                 new ComponentName(TEST_APP, MINIMAL_LISTENER_CLASS);
1499         try {
1500             // make surethat we don't for some reason have contacts access
1501             toggleReadContactsPermission(TEST_APP, false);
1502 
1503             // grant the notification app package notification listener access;
1504             // give it time to succeed
1505             toggleExternalListenerAccess(listenerComponent, true);
1506             Thread.sleep(500);
1507 
1508             // set up & run intent
1509             final Intent mcfIntent = new Intent(Intent.ACTION_MAIN);
1510             mcfIntent.setClassName(TEST_APP, MATCHES_CALL_FILTER_CLASS);
1511             GetResultActivity grActivity = setUpGetResultActivity();
1512             grActivity.startActivityForResult(mcfIntent, REQUEST_CODE);
1513             UiDevice.getInstance(mInstrumentation).waitForIdle();
1514 
1515             // with just listener permissions, this call should have been permitted
1516             GetResultActivity.Result result = grActivity.getResult();
1517             assertEquals(REQUEST_CODE, result.requestCode);
1518             assertEquals(MATCHES_CALL_FILTER_PERMITTED, result.resultCode);
1519             grActivity.finishActivity(REQUEST_CODE);
1520         } finally {
1521             // clean up listener access, reset read contacts access
1522             toggleExternalListenerAccess(listenerComponent, false);
1523             toggleReadContactsPermission(TEST_APP, hadReadPerm);
1524         }
1525     }
1526 
1527     @Test
testMatchesCallFilter_contactsPermissionOnly()1528     public void testMatchesCallFilter_contactsPermissionOnly() throws Exception {
1529         // grant the notification app package contacts read access
1530         boolean hadReadPerm = hasReadContactsPermission(TEST_APP);
1531         try {
1532             toggleReadContactsPermission(TEST_APP, true);
1533 
1534             // set up & run intent
1535             final Intent mcfIntent = new Intent(Intent.ACTION_MAIN);
1536             mcfIntent.setClassName(TEST_APP, MATCHES_CALL_FILTER_CLASS);
1537             GetResultActivity grActivity = setUpGetResultActivity();
1538             grActivity.startActivityForResult(mcfIntent, REQUEST_CODE);
1539             UiDevice.getInstance(mInstrumentation).waitForIdle();
1540 
1541             // with just contacts read permissions, this call should have been permitted
1542             GetResultActivity.Result result = grActivity.getResult();
1543             assertEquals(REQUEST_CODE, result.requestCode);
1544             assertEquals(MATCHES_CALL_FILTER_PERMITTED, result.resultCode);
1545             grActivity.finishActivity(REQUEST_CODE);
1546         } finally {
1547             // clean up contacts access
1548             toggleReadContactsPermission(TEST_APP, hadReadPerm);
1549         }
1550     }
1551 
1552     @Test
testMatchesCallFilter_zenOff()1553     public void testMatchesCallFilter_zenOff() throws Exception {
1554         // zen mode is not on so nothing is filtered; matchesCallFilter should always pass
1555         toggleNotificationPolicyAccess(mContext.getPackageName(),
1556                 InstrumentationRegistry.getInstrumentation(), true);
1557         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1558         try {
1559             // allowed from anyone: nothing is filtered, and make sure change went through
1560             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL);
1561             assertExpectedDndState(INTERRUPTION_FILTER_ALL);
1562 
1563             // create a phone URI from which to receive a call
1564             Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
1565                     Uri.encode("+16175551212"));
1566             assertTrue(mNotificationManager.matchesCallFilter(phoneUri));
1567         } finally {
1568             mNotificationManager.setInterruptionFilter(origFilter);
1569         }
1570     }
1571 
1572     @Test
testMatchesCallFilter_noCallInterruptions()1573     public void testMatchesCallFilter_noCallInterruptions() throws Exception {
1574         // when no call interruptions are allowed at all, or only alarms, matchesCallFilter
1575         // should always fail
1576         toggleNotificationPolicyAccess(mContext.getPackageName(),
1577                 InstrumentationRegistry.getInstrumentation(), true);
1578         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1579         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1580         try {
1581             // create a phone URI from which to receive a call
1582             Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
1583                     Uri.encode("+16175551212"));
1584 
1585             // no interruptions allowed at all
1586             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_NONE);
1587             assertExpectedDndState(INTERRUPTION_FILTER_NONE);
1588             assertFalse(mNotificationManager.matchesCallFilter(phoneUri));
1589 
1590             // only alarms
1591             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALARMS);
1592             assertExpectedDndState(INTERRUPTION_FILTER_ALARMS);
1593             assertFalse(mNotificationManager.matchesCallFilter(phoneUri));
1594 
1595             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1596                     PRIORITY_CATEGORY_MESSAGES, 0, 0));
1597             // turn on manual DND
1598             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1599             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1600             assertFalse(mNotificationManager.matchesCallFilter(phoneUri));
1601         } finally {
1602             mNotificationManager.setInterruptionFilter(origFilter);
1603             mNotificationManager.setNotificationPolicy(origPolicy);
1604         }
1605     }
1606 
1607     @Test
testMatchesCallFilter_someCallers()1608     public void testMatchesCallFilter_someCallers() throws Exception {
1609         // zen mode is active; check various configurations where some calls, but not all calls,
1610         // are allowed
1611         toggleNotificationPolicyAccess(mContext.getPackageName(),
1612                 InstrumentationRegistry.getInstrumentation(), true);
1613         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1614         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1615 
1616         // for storing lookup URIs for deleting the contacts afterwards
1617         Uri aliceUri = null;
1618         Uri bobUri = null;
1619         try {
1620             // set up phone numbers: one starred, one regular, one unknown number
1621             // starred contact from whom to receive a call
1622             insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
1623             aliceUri = lookupContact(ALICE_PHONE);
1624             Uri alicePhoneUri = makePhoneUri(ALICE_PHONE);
1625 
1626             // non-starred contact from whom to also receive a call
1627             insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
1628             bobUri = lookupContact(BOB_PHONE);
1629             Uri bobPhoneUri = makePhoneUri(BOB_PHONE);
1630 
1631             // non-contact phone URI
1632             Uri phoneUri = makePhoneUri("+16175555656");
1633 
1634             // set up: any contacts are allowed to call.
1635             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1636                     PRIORITY_CATEGORY_CALLS,
1637                     NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS, 0));
1638 
1639             // turn on manual DND
1640             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1641             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1642 
1643             // in this case Alice and Bob should get through but not the unknown number.
1644             assertTrue(mNotificationManager.matchesCallFilter(alicePhoneUri));
1645             assertTrue(mNotificationManager.matchesCallFilter(bobPhoneUri));
1646             assertFalse(mNotificationManager.matchesCallFilter(phoneUri));
1647 
1648             // set up: only starred contacts are allowed to call.
1649             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1650                     PRIORITY_CATEGORY_CALLS,
1651                     PRIORITY_SENDERS_STARRED, 0));
1652             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1653 
1654             // now only Alice should be allowed to get through
1655             assertTrue(mNotificationManager.matchesCallFilter(alicePhoneUri));
1656             assertFalse(mNotificationManager.matchesCallFilter(bobPhoneUri));
1657             assertFalse(mNotificationManager.matchesCallFilter(phoneUri));
1658         } finally {
1659             mNotificationManager.setInterruptionFilter(origFilter);
1660             mNotificationManager.setNotificationPolicy(origPolicy);
1661             if (aliceUri != null) {
1662                 // delete the contact
1663                 deleteSingleContact(aliceUri);
1664             }
1665             if (bobUri != null) {
1666                 deleteSingleContact(bobUri);
1667             }
1668         }
1669     }
1670 
1671     @Test
testMatchesCallFilter_repeatCallers()1672     public void testMatchesCallFilter_repeatCallers() throws Exception {
1673         // if repeat callers are allowed, an unknown number calling twice should go through
1674         toggleNotificationPolicyAccess(mContext.getPackageName(),
1675                 InstrumentationRegistry.getInstrumentation(), true);
1676         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1677         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1678         long startTime = System.currentTimeMillis();
1679         try {
1680             // create phone URIs from which to receive a call; one US, one non-US,
1681             // both fully specified
1682             Uri phoneUri = makePhoneUri("+16175551212");
1683             Uri phoneUri2 = makePhoneUri("+81 75 350 6006");
1684 
1685             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1686                     PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0));
1687             // turn on manual DND
1688             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1689             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1690 
1691             // not repeat callers yet, so it shouldn't be allowed
1692             assertFalse(mNotificationManager.matchesCallFilter(phoneUri));
1693             assertFalse(mNotificationManager.matchesCallFilter(phoneUri2));
1694 
1695             // register a call from number 1, then cancel the notification, which is when
1696             // a call is actually recorded.
1697             sendNotification(1, null, R.drawable.blue, true, phoneUri);
1698             cancelAndPoll(1);
1699 
1700             // now this number should count as a repeat caller
1701             assertTrue(mNotificationManager.matchesCallFilter(phoneUri));
1702             assertFalse(mNotificationManager.matchesCallFilter(phoneUri2));
1703 
1704             // also, any other variants of this phone number should also count as a repeat caller
1705             Uri[] variants = { makePhoneUri(Uri.encode("+1-617-555-1212")),
1706                     makePhoneUri("+1 (617) 555-1212") };
1707             for (int i = 0; i < variants.length; i++) {
1708                 assertTrue("phone variant " + variants[i] + " should still match",
1709                         mNotificationManager.matchesCallFilter(variants[i]));
1710             }
1711 
1712             // register call 2
1713             sendNotification(2, null, R.drawable.blue, true, phoneUri2);
1714             cancelAndPoll(2);
1715 
1716             // now this should be a repeat caller
1717             assertTrue(mNotificationManager.matchesCallFilter(phoneUri2));
1718 
1719             Uri[] variants2 = { makePhoneUri(Uri.encode("+81 75 350 6006")),
1720                     makePhoneUri("+81753506006")};
1721             for (int j = 0; j < variants2.length; j++) {
1722                 assertTrue("phone variant " + variants2[j] + " should still match",
1723                         mNotificationManager.matchesCallFilter(variants2[j]));
1724             }
1725         } finally {
1726             mNotificationManager.setInterruptionFilter(origFilter);
1727             mNotificationManager.setNotificationPolicy(origPolicy);
1728 
1729             // make sure we clean up the recent call, otherwise future runs of this will fail
1730             // and we'll have a fake call still kicking around somewhere.
1731             SystemUtil.runWithShellPermissionIdentity(() ->
1732                     mNotificationManager.cleanUpCallersAfter(startTime));
1733         }
1734     }
1735 
1736     @Test
testMatchesCallFilter_repeatCallers_fromContact()1737     public void testMatchesCallFilter_repeatCallers_fromContact() throws Exception {
1738         // set up such that only repeat callers (and not any individuals) are allowed; make sure
1739         // that a call registered with a contact's lookup URI will return the correct info
1740         // when matchesCallFilter is called with their phone number
1741         toggleNotificationPolicyAccess(mContext.getPackageName(),
1742                 InstrumentationRegistry.getInstrumentation(), true);
1743         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1744         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1745         Uri aliceUri = null;
1746         long startTime = System.currentTimeMillis();
1747         try {
1748             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1749                     PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0));
1750             // turn on manual DND
1751             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1752             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1753 
1754             insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, false);
1755             aliceUri = lookupContact(ALICE_PHONE);
1756             Uri alicePhoneUri = makePhoneUri(ALICE_PHONE);
1757 
1758             // no one has called; matchesCallFilter should return false for both URIs
1759             assertFalse(mNotificationManager.matchesCallFilter(aliceUri));
1760             assertFalse(mNotificationManager.matchesCallFilter(alicePhoneUri));
1761 
1762             assertTrue(aliceUri.toString()
1763                     .startsWith(ContactsContract.Contacts.CONTENT_LOOKUP_URI.toString()));
1764 
1765             // register a call from Alice via the contact lookup URI, then cancel so the call is
1766             // recorded accordingly.
1767             sendNotification(1, null, R.drawable.blue, true, aliceUri);
1768             // wait for contact lookup of number to finish; this can take a while because it runs
1769             // in the background, so give it a fair bit of time
1770             Thread.sleep(3000);
1771             cancelAndPoll(1);
1772 
1773             // now a phone call from Alice's phone number should match the repeat callers list
1774             assertTrue(mNotificationManager.matchesCallFilter(alicePhoneUri));
1775         } finally {
1776             mNotificationManager.setInterruptionFilter(origFilter);
1777             mNotificationManager.setNotificationPolicy(origPolicy);
1778             if (aliceUri != null) {
1779                 // delete the contact
1780                 deleteSingleContact(aliceUri);
1781             }
1782 
1783             // clean up the recorded calls
1784             SystemUtil.runWithShellPermissionIdentity(() ->
1785                     mNotificationManager.cleanUpCallersAfter(startTime));
1786         }
1787     }
1788 
1789     @Test
testRepeatCallers_repeatCallNotIntercepted_contactAfterPhone()1790     public void testRepeatCallers_repeatCallNotIntercepted_contactAfterPhone() throws Exception {
1791         mListener = mNotificationHelper.enableListener(STUB_PACKAGE_NAME);
1792         assertNotNull(mListener);
1793 
1794         // if a call is recorded with just phone number info (not a contact's uri), which may
1795         // happen when the same contact calls across multiple apps (or if the contact uri provided
1796         // is otherwise inconsistent), check for the contact's phone number
1797         toggleNotificationPolicyAccess(mContext.getPackageName(),
1798                 InstrumentationRegistry.getInstrumentation(), true);
1799         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1800         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1801         Uri aliceUri = null;
1802         long startTime = System.currentTimeMillis();
1803         try {
1804             mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
1805                     PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0));
1806             // turn on manual DND
1807             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1808             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1809 
1810             insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, false);
1811             aliceUri = lookupContact(ALICE_PHONE);
1812             Uri alicePhoneUri = makePhoneUri(ALICE_PHONE);
1813 
1814             // no one has called; matchesCallFilter should return false for both URIs
1815             assertFalse(mNotificationManager.matchesCallFilter(aliceUri));
1816             assertFalse(mNotificationManager.matchesCallFilter(alicePhoneUri));
1817 
1818             // register a call from Alice via just the phone number
1819             sendNotification(1, null, R.drawable.blue, true, alicePhoneUri);
1820             Thread.sleep(1000); // give the listener some time to receive info
1821 
1822             // check that the first notification is intercepted
1823             StatusBarNotification sbn = mNotificationHelper.findPostedNotification(null, 1,
1824                     SEARCH_TYPE.POSTED);
1825             assertNotNull(sbn);
1826             assertTrue(mListener.mIntercepted.containsKey(sbn.getKey()));
1827             assertTrue(mListener.mIntercepted.get(sbn.getKey()));  // should be intercepted
1828 
1829             // cancel first notification
1830             cancelAndPoll(1);
1831 
1832             // now send a call with only Alice's contact Uri as the info
1833             // Note that this is a test of the repeat caller check, not matchesCallFilter itself
1834             sendNotification(2, null, R.drawable.blue, true, aliceUri);
1835             // wait for contact lookup, which may take a while
1836             Thread.sleep(3000);
1837 
1838             // now check that the second notification is not intercepted
1839             StatusBarNotification sbn2 = mNotificationHelper.findPostedNotification(null, 2,
1840                     SEARCH_TYPE.POSTED);
1841             assertTrue(mListener.mIntercepted.containsKey(sbn2.getKey()));
1842             assertFalse(mListener.mIntercepted.get(sbn2.getKey()));  // should not be intercepted
1843 
1844             // cancel second notification
1845             cancelAndPoll(2);
1846         } finally {
1847             mNotificationManager.setInterruptionFilter(origFilter);
1848             mNotificationManager.setNotificationPolicy(origPolicy);
1849             if (aliceUri != null) {
1850                 // delete the contact
1851                 deleteSingleContact(aliceUri);
1852             }
1853 
1854             // clean up the recorded calls
1855             SystemUtil.runWithShellPermissionIdentity(() ->
1856                     mNotificationManager.cleanUpCallersAfter(startTime));
1857         }
1858     }
1859 
1860     @Test
testMatchesCallFilter_allCallers()1861     public void testMatchesCallFilter_allCallers() throws Exception {
1862         // allow all callers
1863         toggleNotificationPolicyAccess(mContext.getPackageName(),
1864                 InstrumentationRegistry.getInstrumentation(), true);
1865         int origFilter = mNotificationManager.getCurrentInterruptionFilter();
1866         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
1867         Uri aliceUri = null;  // for deletion after the test is done
1868         try {
1869             NotificationManager.Policy currPolicy = mNotificationManager.getNotificationPolicy();
1870             NotificationManager.Policy newPolicy = new NotificationManager.Policy(
1871                     NotificationManager.Policy.PRIORITY_CATEGORY_CALLS
1872                             | PRIORITY_CATEGORY_REPEAT_CALLERS,
1873                     NotificationManager.Policy.PRIORITY_SENDERS_ANY,
1874                     currPolicy.priorityMessageSenders,
1875                     currPolicy.suppressedVisualEffects);
1876             mNotificationManager.setNotificationPolicy(newPolicy);
1877             mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1878             assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
1879 
1880             insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, false);
1881             aliceUri = lookupContact(ALICE_PHONE);
1882 
1883             Uri alicePhoneUri = makePhoneUri(ALICE_PHONE);
1884             assertTrue(mNotificationManager.matchesCallFilter(alicePhoneUri));
1885         } finally {
1886             mNotificationManager.setInterruptionFilter(origFilter);
1887             mNotificationManager.setNotificationPolicy(origPolicy);
1888             if (aliceUri != null) {
1889                 // delete the contact
1890                 deleteSingleContact(aliceUri);
1891             }
1892         }
1893     }
1894 
1895     @Test
testInterruptionFilterNoneInterceptsMessages()1896     public void testInterruptionFilterNoneInterceptsMessages() throws Exception {
1897         insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
1898         insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
1899         // Not Charlie
1900 
1901         mNotificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
1902         sendNotifications(MODE_URI, false, false);
1903 
1904         StatusBarNotification alice = mNotificationHelper.findPostedNotification(ALICE, 1,
1905                 SEARCH_TYPE.POSTED);
1906         StatusBarNotification bob = mNotificationHelper.findPostedNotification(BOB, 2,
1907                 SEARCH_TYPE.POSTED);
1908         StatusBarNotification charlie = mNotificationHelper.findPostedNotification(CHARLIE, 3,
1909                 SEARCH_TYPE.POSTED);
1910 
1911         assertTrue(mListener.mIntercepted.get(alice.getKey()));
1912         assertTrue(mListener.mIntercepted.get(bob.getKey()));
1913         assertTrue(mListener.mIntercepted.get(charlie.getKey()));
1914     }
1915 
1916     @Test
testInterruptionFilterNoneInterceptsEventAlarmReminder()1917     public void testInterruptionFilterNoneInterceptsEventAlarmReminder() throws Exception {
1918         insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
1919         insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
1920         // Not Charlie
1921 
1922         mNotificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
1923         sendEventAlarmReminderNotifications(SEND_ALL);
1924 
1925         StatusBarNotification alice = mNotificationHelper.findPostedNotification(ALICE, 4,
1926                 SEARCH_TYPE.POSTED);
1927         StatusBarNotification bob = mNotificationHelper.findPostedNotification(BOB, 5,
1928                 SEARCH_TYPE.POSTED);
1929         StatusBarNotification charlie = mNotificationHelper.findPostedNotification(CHARLIE, 6,
1930                 SEARCH_TYPE.POSTED);
1931 
1932         assertTrue(mListener.mIntercepted.get(alice.getKey()));
1933         assertTrue(mListener.mIntercepted.get(bob.getKey()));
1934         assertTrue(mListener.mIntercepted.get(charlie.getKey()));
1935     }
1936 
1937     @Test
testInterruptionFilterAllInterceptsNothing()1938     public void testInterruptionFilterAllInterceptsNothing() throws Exception {
1939         insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
1940         insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
1941         // Not Charlie
1942 
1943         mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL);
1944         sendNotifications(MODE_URI, false, false);
1945         sendEventAlarmReminderNotifications(SEND_ALL);
1946         sendAlarmOtherMediaNotifications(SEND_ALL);
1947 
1948         StatusBarNotification alice = mNotificationHelper.findPostedNotification(ALICE, 1,
1949                 SEARCH_TYPE.POSTED);
1950         StatusBarNotification bob = mNotificationHelper.findPostedNotification(BOB, 2,
1951                 SEARCH_TYPE.POSTED);
1952         StatusBarNotification charlie = mNotificationHelper.findPostedNotification(CHARLIE, 3,
1953                 SEARCH_TYPE.POSTED);
1954 
1955         StatusBarNotification aliceEvent = mNotificationHelper.findPostedNotification(ALICE, 4,
1956                 SEARCH_TYPE.POSTED);
1957         StatusBarNotification bobAlarm = mNotificationHelper.findPostedNotification(BOB, 5,
1958                 SEARCH_TYPE.POSTED);
1959         StatusBarNotification charlieReminder = mNotificationHelper.findPostedNotification(CHARLIE, 6,
1960                 SEARCH_TYPE.POSTED);
1961 
1962         StatusBarNotification aliceAlarm = mNotificationHelper.findPostedNotification(ALICE, 7,
1963                 SEARCH_TYPE.POSTED);
1964         StatusBarNotification bobOther = mNotificationHelper.findPostedNotification(BOB, 8,
1965                 SEARCH_TYPE.POSTED);
1966         StatusBarNotification charlieMedia = mNotificationHelper.findPostedNotification(CHARLIE, 9,
1967                 SEARCH_TYPE.POSTED);
1968 
1969         assertFalse(mListener.mIntercepted.get(alice.getKey()));
1970         assertFalse(mListener.mIntercepted.get(bob.getKey()));
1971         assertFalse(mListener.mIntercepted.get(charlie.getKey()));
1972         assertFalse(mListener.mIntercepted.get(aliceEvent.getKey()));
1973         assertFalse(mListener.mIntercepted.get(bobAlarm.getKey()));
1974         assertFalse(mListener.mIntercepted.get(charlieReminder.getKey()));
1975         assertFalse(mListener.mIntercepted.get(aliceAlarm.getKey()));
1976         assertFalse(mListener.mIntercepted.get(bobOther.getKey()));
1977         assertFalse(mListener.mIntercepted.get(charlieMedia.getKey()));
1978     }
1979 
1980     @Test
testPriorityStarredMessages()1981     public void testPriorityStarredMessages() throws Exception {
1982         insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
1983         assertTrue(isStarred(lookupContact(ALICE_PHONE)));
1984         insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
1985         // Not Charlie
1986 
1987         mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
1988         NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
1989         policy = new NotificationManager.Policy(
1990                 NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES,
1991                 policy.priorityCallSenders,
1992                 PRIORITY_SENDERS_STARRED);
1993         mNotificationManager.setNotificationPolicy(policy);
1994         sendNotifications(MODE_URI, false, false);
1995 
1996         StatusBarNotification alice = mNotificationHelper.findPostedNotification(ALICE, 1,
1997                 SEARCH_TYPE.POSTED);
1998         StatusBarNotification bob = mNotificationHelper.findPostedNotification(BOB, 2,
1999                 SEARCH_TYPE.POSTED);
2000         StatusBarNotification charlie = mNotificationHelper.findPostedNotification(CHARLIE, 3,
2001                 SEARCH_TYPE.POSTED);
2002 
2003         // wait for contacts lookup in NMS to finish so we have the correct interception info
2004         boolean isAliceIntercepted = true;
2005         for (int i = 0; i < 6; i++) {
2006             isAliceIntercepted = mListener.mIntercepted.get(alice.getKey());
2007             if (!isAliceIntercepted) {
2008                 break;
2009             }
2010             sleep();
2011         }
2012         assertFalse(isAliceIntercepted);
2013         assertTrue(mListener.mIntercepted.get(bob.getKey()));
2014         assertTrue(mListener.mIntercepted.get(charlie.getKey()));
2015     }
2016 
2017     @Test
testPriorityInterceptsAlarms()2018     public void testPriorityInterceptsAlarms() throws Exception {
2019         insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
2020         insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
2021         // Not Charlie
2022 
2023         mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
2024         NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
2025         policy = new NotificationManager.Policy(
2026                 NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS,
2027                 policy.priorityCallSenders,
2028                 policy.priorityMessageSenders);
2029         mNotificationManager.setNotificationPolicy(policy);
2030         sendEventAlarmReminderNotifications(SEND_ALL);
2031 
2032         StatusBarNotification alice = mNotificationHelper.findPostedNotification(ALICE, 4,
2033                 SEARCH_TYPE.POSTED);
2034         StatusBarNotification bob = mNotificationHelper.findPostedNotification(BOB, 5,
2035                 SEARCH_TYPE.POSTED);
2036         StatusBarNotification charlie = mNotificationHelper.findPostedNotification(CHARLIE, 6,
2037                 SEARCH_TYPE.POSTED);
2038 
2039         boolean isBobIntercepted = true;
2040         for (int i = 0; i < 6; i++) {
2041             isBobIntercepted = mListener.mIntercepted.get(bob.getKey());
2042             if (!isBobIntercepted) {
2043                 break;
2044             }
2045             sleep();
2046         }
2047         assertFalse(isBobIntercepted);
2048 
2049         assertTrue(mListener.mIntercepted.get(alice.getKey()));
2050         assertTrue(mListener.mIntercepted.get(charlie.getKey()));
2051     }
2052 
2053     @Test
testPriorityInterceptsMediaSystemOther()2054     public void testPriorityInterceptsMediaSystemOther() throws Exception {
2055         insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true);
2056         insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false);
2057         // Not Charlie
2058 
2059         mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
2060         NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
2061         policy = new NotificationManager.Policy(
2062                 NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA,
2063                 policy.priorityCallSenders,
2064                 policy.priorityMessageSenders);
2065         mNotificationManager.setNotificationPolicy(policy);
2066         sendAlarmOtherMediaNotifications(SEND_ALL);
2067 
2068         StatusBarNotification alice = mNotificationHelper.findPostedNotification(ALICE, 7,
2069                 SEARCH_TYPE.POSTED);
2070         StatusBarNotification bob = mNotificationHelper.findPostedNotification(BOB, 8,
2071                 SEARCH_TYPE.POSTED);
2072         StatusBarNotification charlie = mNotificationHelper.findPostedNotification(CHARLIE, 9,
2073                 SEARCH_TYPE.POSTED);
2074 
2075         boolean isBobIntercepted = true;
2076         for (int i = 0; i < 6; i++) {
2077             isBobIntercepted = mListener.mIntercepted.get(bob.getKey());
2078             if (!isBobIntercepted) {
2079                 break;
2080             }
2081             sleep();
2082         }
2083         assertFalse(isBobIntercepted);
2084 
2085 
2086         boolean isCharlieIntercepted = true;
2087         for (int i = 0; i < 6; i++) {
2088             isCharlieIntercepted = mListener.mIntercepted.get(charlie.getKey());
2089             if (!isCharlieIntercepted) {
2090                 break;
2091             }
2092             sleep();
2093         }
2094         if (android.app.Flags.restrictAudioAttributesMedia()) {
2095             // media notifications are moved to notification stream, so they should be intercepted
2096             assertTrue(isCharlieIntercepted);
2097         } else {
2098             assertFalse(isCharlieIntercepted);
2099         }
2100 
2101         assertTrue(mListener.mIntercepted.get(alice.getKey()));
2102     }
2103 
2104     @Test
2105     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
testPriorityChannelNotInterceptedByDefault()2106     public void testPriorityChannelNotInterceptedByDefault() throws Exception {
2107         toggleNotificationPolicyAccess(mContext.getPackageName(),
2108                 InstrumentationRegistry.getInstrumentation(), true);
2109 
2110         // Setup: no contacts, so nobody counts as "priority" in terms of senders.
2111         // Construct a policy that doesn't allow anything except priority channels through;
2112         // apply it via zen rule
2113         AutomaticZenRule rule = createRule("test_channel_bypass",
2114                 INTERRUPTION_FILTER_PRIORITY);
2115         rule.setZenPolicy(new ZenPolicy.Builder().disallowAllSounds().build());
2116         String id = mNotificationManager.addAutomaticZenRule(rule);
2117 
2118         // enable rule
2119         Condition condition = new Condition(rule.getConditionId(), "summary",
2120                 Condition.STATE_TRUE);
2121         mNotificationManager.setAutomaticZenRuleState(id, condition);
2122 
2123         Thread.sleep(300); // wait for rules to be applied - it's done asynchronously
2124 
2125         // Create a notification under the PRIORITY (set to bypass DND) channel and send.
2126         Notification.Builder notif = new Notification.Builder(mContext,
2127                 NOTIFICATION_CHANNEL_ID_PRIORITY)
2128                 .setContentTitle(NAME)
2129                 .setContentText("content")
2130                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2131                 .setCategory(Notification.CATEGORY_MESSAGE)
2132                 .setWhen(System.currentTimeMillis() - 1000000L);
2133         mNotificationManager.notify(NAME, 1, notif.build());
2134 
2135         StatusBarNotification sbn = mNotificationHelper.findPostedNotification(NAME, 1,
2136                 SEARCH_TYPE.POSTED);
2137 
2138         // should not be intercepted because priority channels are allowed.
2139         assertFalse(mListener.mIntercepted.get(sbn.getKey()));
2140     }
2141 
2142     @Test
2143     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
testPriorityChannelInterceptedWhenChannelsDisallowed()2144     public void testPriorityChannelInterceptedWhenChannelsDisallowed() throws Exception {
2145         toggleNotificationPolicyAccess(mContext.getPackageName(),
2146                 InstrumentationRegistry.getInstrumentation(), true);
2147 
2148         // Setup: no contacts, so nobody counts as "priority" in terms of senders, not that the
2149         // policy allows senders anyway.
2150         // Construct a policy that doesn't allow anything through and also disallows channels.
2151         AutomaticZenRule rule = createRule("test_channels_disallowed",
2152                 INTERRUPTION_FILTER_PRIORITY);
2153         rule.setZenPolicy(new ZenPolicy.Builder()
2154                 .disallowAllSounds()
2155                 .allowPriorityChannels(false)
2156                 .build());
2157         String id = mNotificationManager.addAutomaticZenRule(rule);
2158 
2159         // enable rule
2160         Condition condition = new Condition(rule.getConditionId(), "summary",
2161                 Condition.STATE_TRUE);
2162         mNotificationManager.setAutomaticZenRuleState(id, condition);
2163         Thread.sleep(300); // wait for rules to be applied - it's done asynchronously
2164 
2165         // Send notification under the priority channel.
2166         Notification.Builder notif = new Notification.Builder(mContext,
2167                 NOTIFICATION_CHANNEL_ID_PRIORITY)
2168                 .setContentTitle(NAME)
2169                 .setContentText("content")
2170                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2171                 .setCategory(Notification.CATEGORY_MESSAGE)
2172                 .setWhen(System.currentTimeMillis() - 1000000L);
2173         mNotificationManager.notify(NAME, 1, notif.build());
2174 
2175         StatusBarNotification sbn = mNotificationHelper.findPostedNotification(NAME, 1,
2176                 SEARCH_TYPE.POSTED);
2177 
2178         // Notification should be intercepted now
2179         assertTrue(mListener.mIntercepted.get(sbn.getKey()));
2180     }
2181 
2182     @Test
2183     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
testAddAutomaticZenRule_includesModesApiFields()2184     public void testAddAutomaticZenRule_includesModesApiFields() throws Exception {
2185         toggleNotificationPolicyAccess(mContext.getPackageName(),
2186                 InstrumentationRegistry.getInstrumentation(), true);
2187 
2188         AutomaticZenRule ruleToCreate = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
2189                 .setZenPolicy(POLICY)
2190                 .setManualInvocationAllowed(ALLOW_MANUAL)
2191                 .setOwner(null)
2192                 .setType(UNRESTRICTED_TYPE)
2193                 .setConfigurationActivity(CONFIG_ACTIVITY)
2194                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2195                 .setTriggerDescription(TRIGGER_DESC)
2196                 .setIconResId(ICON_RES_ID)
2197                 .build();
2198         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
2199 
2200         assertNotNull(id);
2201         assertRulesEqual(ruleToCreate, mNotificationManager.getAutomaticZenRule(id));
2202     }
2203 
2204     @Test
testSnoozeRule()2205     public void testSnoozeRule() throws Exception {
2206         if (!Flags.modesApi() || !CompatChanges.isChangeEnabled(308673617)) {
2207             Log.d(TAG, "Skipping testSnoozeRule() "
2208                     + Flags.modesApi() + " " + Build.VERSION.SDK_INT);
2209             return;
2210         }
2211         NotificationManagerBroadcastReceiver br = new NotificationManagerBroadcastReceiver();
2212         br.register(mContext, ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED, 2);
2213 
2214         toggleNotificationPolicyAccess(mContext.getPackageName(),
2215                 InstrumentationRegistry.getInstrumentation(), true);
2216 
2217         AutomaticZenRule ruleToCreate = createRule("testSnoozeRule");
2218         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
2219 
2220         // enable DND
2221         Condition condition =
2222                 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE);
2223         mNotificationManager.setAutomaticZenRuleState(id, condition);
2224 
2225         // snooze the rule
2226         runAsSystemUi(() -> mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL));
2227 
2228         assertEquals(AUTOMATIC_RULE_STATUS_ACTIVATED,
2229                 br.getExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, 0, 500));
2230         assertEquals(AUTOMATIC_RULE_STATUS_DEACTIVATED,
2231                 br.getExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, 1, 500));
2232         br.unregister();
2233     }
2234 
2235     @Test
testUnsnoozeRule_disableEnable()2236     public void testUnsnoozeRule_disableEnable() throws Exception {
2237         if (!Flags.modesApi()) {
2238             Log.d(TAG, "Skipping testUnsnoozeRule_disableEnable() " + Flags.modesApi()
2239                     + " " + Build.VERSION.SDK_INT);
2240             return;
2241         }
2242         NotificationManagerBroadcastReceiver br = new NotificationManagerBroadcastReceiver();
2243         br.register(mContext, ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED, 3);
2244 
2245         toggleNotificationPolicyAccess(mContext.getPackageName(),
2246                 InstrumentationRegistry.getInstrumentation(), true);
2247 
2248         // No broadcast expected on creation
2249         AutomaticZenRule ruleToCreate = createRule("testUnsnoozeRule_disableEnable");
2250         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
2251 
2252         // enable DND
2253         Condition condition =
2254                 new Condition(ruleToCreate.getConditionId(), "summary", Condition.STATE_TRUE);
2255         // triggers ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED: Enabled
2256         mNotificationManager.setAutomaticZenRuleState(id, condition);
2257 
2258         // snooze the rule by pretending the user turned off the mode from SystemUI
2259         // triggers ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED: Deactivated
2260         runAsSystemUi(() -> mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL));
2261         assertExpectedDndState(INTERRUPTION_FILTER_ALL);
2262 
2263         // disable the rule. should unsnooze.
2264         ruleToCreate.setEnabled(false);
2265         mNotificationManager.updateAutomaticZenRule(id, ruleToCreate);
2266 
2267         assertEquals(AUTOMATIC_RULE_STATUS_DISABLED,
2268                 br.getExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, 2, 500));
2269         br.unregister();
2270 
2271         br = new NotificationManagerBroadcastReceiver();
2272         br.register(mContext, ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED, 2);
2273 
2274         // re-enable and activate
2275         ruleToCreate.setEnabled(true);
2276         mNotificationManager.updateAutomaticZenRule(id, ruleToCreate);
2277         mNotificationManager.setAutomaticZenRuleState(id, condition);
2278         assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
2279 
2280         assertEquals(AUTOMATIC_RULE_STATUS_ENABLED,
2281                 br.getExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, 0, 500));
2282         if (CompatChanges.isChangeEnabled(308673617)) {
2283             assertEquals(AUTOMATIC_RULE_STATUS_ACTIVATED,
2284                     br.getExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, 1, 500));
2285         } else {
2286             assertEquals(AUTOMATIC_RULE_STATUS_UNKNOWN,
2287                     br.getExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, 1, 500));
2288         }
2289         br.unregister();
2290     }
2291 
2292     @Test
testGetAutomaticZenRules()2293     public void testGetAutomaticZenRules() {
2294         assertThat(mNotificationManager.getAutomaticZenRules()).isEmpty();
2295 
2296         AutomaticZenRule rule1 = createRule("One");
2297         AutomaticZenRule rule2 = createRule("Two");
2298         if (Flags.modesApi()) {
2299             rule1 = new AutomaticZenRule.Builder(rule1)
2300                     .setType(AutomaticZenRule.TYPE_DRIVING)
2301                     .setManualInvocationAllowed(true)
2302                     .build();
2303             rule2 = new AutomaticZenRule.Builder(rule2)
2304                     .setTriggerDescription("On the twelfth day of Christmas")
2305                     .setIconResId(R.drawable.icon_green)
2306                     .build();
2307         }
2308         String ruleId1 = mNotificationManager.addAutomaticZenRule(rule1);
2309         String ruleId2 = mNotificationManager.addAutomaticZenRule(rule2);
2310 
2311         Map<String, AutomaticZenRule> rules = mNotificationManager.getAutomaticZenRules();
2312 
2313         assertThat(rules).hasSize(2);
2314         assertRulesEqual(rules.get(ruleId1), rule1);
2315         assertRulesEqual(rules.get(ruleId2), rule2);
2316     }
2317 
assertRulesEqual(AutomaticZenRule r1, AutomaticZenRule r2)2318     private void assertRulesEqual(AutomaticZenRule r1, AutomaticZenRule r2) {
2319         // Cannot test for exact equality because some extra fields (e.g. packageName,
2320         // creationTime) come back. So we verify everything that the client app can set.
2321         assertThat(r1.getConditionId()).isEqualTo(r2.getConditionId());
2322         assertThat(r1.getConfigurationActivity()).isEqualTo(r2.getConfigurationActivity());
2323         assertThat(r1.getInterruptionFilter()).isEqualTo(r2.getInterruptionFilter());
2324         assertThat(r1.getName()).isEqualTo(r2.getName());
2325         assertThat(r1.getOwner()).isEqualTo(r2.getOwner());
2326         assertThat(r1.isEnabled()).isEqualTo(r2.isEnabled());
2327 
2328         if (Flags.modesApi()) {
2329             assertThat(r1.getDeviceEffects()).isEqualTo(r2.getDeviceEffects());
2330             assertThat(doPoliciesMatchWithDefaults(r1.getZenPolicy(), r2.getZenPolicy())).isTrue();
2331 
2332             assertThat(r1.getIconResId()).isEqualTo(r2.getIconResId());
2333             assertThat(r1.getTriggerDescription()).isEqualTo(r2.getTriggerDescription());
2334             assertThat(r1.getType()).isEqualTo(r2.getType());
2335             assertThat(r1.isManualInvocationAllowed()).isEqualTo(r2.isManualInvocationAllowed());
2336         } else {
2337             assertThat(r1.getZenPolicy()).isEqualTo(r2.getZenPolicy());
2338         }
2339     }
2340 
2341     // Checks that the priority categories in the provided NotificationManager.Policy match
2342     // those of the provided ZenPolicy. Does not check call/message/conversation senders or
2343     // visual effects.
assertPolicyCategoriesMatchZenPolicy( NotificationManager.Policy nmPolicy, ZenPolicy zenPolicy)2344     private void assertPolicyCategoriesMatchZenPolicy(
2345             NotificationManager.Policy nmPolicy, ZenPolicy zenPolicy) {
2346         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS) != 0)
2347                 .isEqualTo(zenPolicy.getPriorityCategoryAlarms() == ZenPolicy.STATE_ALLOW);
2348         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_CALLS) != 0)
2349                 .isEqualTo(zenPolicy.getPriorityCategoryCalls() == ZenPolicy.STATE_ALLOW);
2350         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) != 0)
2351                 .isEqualTo(zenPolicy.getPriorityCategoryConversations() == ZenPolicy.STATE_ALLOW);
2352         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_EVENTS) != 0)
2353                 .isEqualTo(zenPolicy.getPriorityCategoryEvents() == ZenPolicy.STATE_ALLOW);
2354         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_MEDIA) != 0)
2355                 .isEqualTo(zenPolicy.getPriorityCategoryMedia() == ZenPolicy.STATE_ALLOW);
2356         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_MESSAGES) != 0)
2357                 .isEqualTo(zenPolicy.getPriorityCategoryMessages() == ZenPolicy.STATE_ALLOW);
2358         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_REMINDERS) != 0)
2359                 .isEqualTo(zenPolicy.getPriorityCategoryReminders() == ZenPolicy.STATE_ALLOW);
2360         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_REPEAT_CALLERS) != 0)
2361                 .isEqualTo(zenPolicy.getPriorityCategoryRepeatCallers() == ZenPolicy.STATE_ALLOW);
2362         assertThat((nmPolicy.priorityCategories & PRIORITY_CATEGORY_SYSTEM) != 0)
2363                 .isEqualTo(zenPolicy.getPriorityCategorySystem() == ZenPolicy.STATE_ALLOW);
2364     }
2365 
2366     @Test
2367     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
addAutomaticZenRule_withInterruptionFilterAll_canBeUsed()2368     public void addAutomaticZenRule_withInterruptionFilterAll_canBeUsed()
2369             throws InterruptedException {
2370         AutomaticZenRule rule = createRule("Without filter", INTERRUPTION_FILTER_ALL);
2371         rule.setDeviceEffects(
2372                 new ZenDeviceEffects.Builder().setShouldDisplayGrayscale(true).build());
2373 
2374         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2375 
2376         AutomaticZenRule savedRule = mNotificationManager.getAutomaticZenRule(ruleId);
2377         assertThat(savedRule).isNotNull();
2378         assertThat(savedRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL);
2379 
2380         // Simple update, just to verify no validation errors.
2381         savedRule.setName("Still without filter");
2382         mNotificationManager.updateAutomaticZenRule(ruleId, savedRule);
2383 
2384         mNotificationManager.setAutomaticZenRuleState(ruleId,
2385                 new Condition(rule.getConditionId(), "summary", Condition.STATE_TRUE));
2386         assertThat(mNotificationManager.getCurrentInterruptionFilter()).isEqualTo(
2387                 INTERRUPTION_FILTER_ALL);
2388         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2389         assertThat(isColorDisplayManagerSaturationActivated()).isTrue();
2390 
2391         mNotificationManager.setAutomaticZenRuleState(ruleId,
2392                 new Condition(rule.getConditionId(), "summary", Condition.STATE_FALSE));
2393         assertThat(mNotificationManager.getCurrentInterruptionFilter()).isEqualTo(
2394                 INTERRUPTION_FILTER_ALL);
2395         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2396         assertThat(isColorDisplayManagerSaturationActivated()).isFalse();
2397 
2398         mNotificationManager.removeAutomaticZenRule(ruleId);
2399         assertThat(mNotificationManager.getAutomaticZenRules()).isEmpty();
2400     }
2401 
2402     @Test
2403     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
addAutomaticZenRule_fromUser_onlyAcceptedFromSystem()2404     public void addAutomaticZenRule_fromUser_onlyAcceptedFromSystem() {
2405         AutomaticZenRule newRule = createRule("Test");
2406 
2407         String rule1 = mNotificationManager.addAutomaticZenRule(newRule, /* fromUser= */ false);
2408 
2409         assertThrows(SecurityException.class,
2410                 () -> mNotificationManager.addAutomaticZenRule(newRule, /* fromUser= */ true));
2411 
2412         String rule2 = callAsSystemUi(
2413                 () -> mNotificationManager.addAutomaticZenRule(newRule, /* fromUser= */ true));
2414 
2415         assertThat(mNotificationManager.getAutomaticZenRule(rule1)).isNotNull();
2416         assertThat(mNotificationManager.getAutomaticZenRule(rule2)).isNotNull();
2417     }
2418 
2419     @Test
2420     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromUser_updatesRuleFully()2421     public void updateAutomaticZenRule_fromUser_updatesRuleFully() {
2422         AutomaticZenRule original = new AutomaticZenRule.Builder("Original", CONDITION_ID)
2423                 .setConfigurationActivity(CONFIG_ACTIVITY)
2424                 .setType(AutomaticZenRule.TYPE_IMMERSIVE)
2425                 .setIconResId(android.app.notification.current.cts.R.drawable.ic_android)
2426                 .setTriggerDescription("Immerse yourself")
2427                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2428                 .setZenPolicy(new ZenPolicy.Builder()
2429                         .allowRepeatCallers(false)
2430                         .allowAlarms(false)
2431                         .build())
2432                 .setDeviceEffects(new ZenDeviceEffects.Builder()
2433                         .setShouldDisplayGrayscale(true)
2434                         .build())
2435                 .build();
2436         String ruleId = mNotificationManager.addAutomaticZenRule(original);
2437         ZenPolicy combinedPolicy = original.getZenPolicy();
2438 
2439         // Update the rule "from user" once.
2440         // Set settings for events & calls that do not match the default so we're certain these
2441         // changes will reflect that the "user" actually changed the fields.
2442         AutomaticZenRule firstUserUpdate = new AutomaticZenRule.Builder(original)
2443                 .setName("First update")
2444                 .setZenPolicy(new ZenPolicy.Builder()
2445                         .allowEvents(
2446                                 mDefaultPolicy.getPriorityCategoryEvents() != ZenPolicy.STATE_ALLOW)
2447                         .allowCalls(mDefaultPolicy.getPriorityCallSenders()
2448                                 == ZenPolicy.PEOPLE_TYPE_ANYONE
2449                                         ? ZenPolicy.PEOPLE_TYPE_CONTACTS
2450                                         : ZenPolicy.PEOPLE_TYPE_ANYONE)
2451                         .build())
2452                 .build();
2453         runAsSystemUi(
2454                 () -> mNotificationManager.updateAutomaticZenRule(ruleId, firstUserUpdate,
2455                         /* fromUser= */ true));
2456 
2457         // Verify the update succeeded.
2458         combinedPolicy = combinedPolicy.overwrittenWith(firstUserUpdate.getZenPolicy());
2459         AutomaticZenRule firstUserUpdateResult = mNotificationManager.getAutomaticZenRule(ruleId);
2460         AutomaticZenRule expectedRuleAfterFirstUpdate =
2461                 new AutomaticZenRule.Builder(firstUserUpdate)
2462                         .setZenPolicy(combinedPolicy)
2463                         .build();
2464         assertRulesEqual(expectedRuleAfterFirstUpdate, firstUserUpdateResult);
2465 
2466         // Update the rule "from user" a second time.
2467         AutomaticZenRule secondUserUpdate = new AutomaticZenRule.Builder(original)
2468                 // User changes
2469                 .setName("Updated again")
2470                 .setEnabled(false)
2471                 .setZenPolicy(new ZenPolicy.Builder()
2472                         .allowMedia(true)
2473                         .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
2474                         .build())
2475                 .setDeviceEffects(new ZenDeviceEffects.Builder(original.getDeviceEffects())
2476                         .setShouldDimWallpaper(true)
2477                         .build())
2478                 // Technically nothing stops this API call from also updating fields that should be
2479                 // the purview of the app.
2480                 .setType(AutomaticZenRule.TYPE_DRIVING)
2481                 .setTriggerDescription("While driving")
2482                 .setIconResId(android.R.drawable.sym_def_app_icon)
2483                 .build();
2484         runAsSystemUi(
2485                 () -> mNotificationManager.updateAutomaticZenRule(ruleId, secondUserUpdate,
2486                         /* fromUser= */ true));
2487 
2488         // The second update succeeded as well.
2489         combinedPolicy = combinedPolicy.overwrittenWith(secondUserUpdate.getZenPolicy());
2490         AutomaticZenRule secondUserUpdateResult = mNotificationManager.getAutomaticZenRule(ruleId);
2491         AutomaticZenRule expectedRuleAfterSecondUpdate =
2492                 new AutomaticZenRule.Builder(secondUserUpdate)
2493                         .setZenPolicy(combinedPolicy)
2494                         .build();
2495         assertRulesEqual(expectedRuleAfterSecondUpdate, secondUserUpdateResult);
2496     }
2497 
2498     @Test
2499     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromApp_forNonUserModifiedRule_allFieldsUpdated()2500     public void updateAutomaticZenRule_fromApp_forNonUserModifiedRule_allFieldsUpdated() {
2501         AutomaticZenRule original = new AutomaticZenRule.Builder("Original", CONDITION_ID)
2502                 .setConfigurationActivity(CONFIG_ACTIVITY)
2503                 .setType(AutomaticZenRule.TYPE_IMMERSIVE)
2504                 .setIconResId(android.app.notification.current.cts.R.drawable.ic_android)
2505                 .setTriggerDescription("Immerse yourself")
2506                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2507                 .setZenPolicy(new ZenPolicy.Builder()
2508                         .allowRepeatCallers(false)
2509                         .allowAlarms(false)
2510                         .build())
2511                 .setDeviceEffects(new ZenDeviceEffects.Builder()
2512                         .setShouldDisplayGrayscale(true)
2513                         .build())
2514                 .build();
2515         String ruleId = mNotificationManager.addAutomaticZenRule(original);
2516 
2517         // Update the rule "from app".
2518         AutomaticZenRule appUpdate = new AutomaticZenRule.Builder(original)
2519                 .setName("Updated")
2520                 .setType(AutomaticZenRule.TYPE_DRIVING)
2521                 .setTriggerDescription("While driving")
2522                 .setIconResId(android.R.drawable.sym_def_app_icon)
2523                 .setEnabled(false)
2524                 .setZenPolicy(new ZenPolicy.Builder(original.getZenPolicy())
2525                         .allowMedia(true)
2526                         .allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE)
2527                         .build())
2528                 .setDeviceEffects(new ZenDeviceEffects.Builder(original.getDeviceEffects())
2529                         .setShouldDimWallpaper(true)
2530                         .build())
2531                 .build();
2532         mNotificationManager.updateAutomaticZenRule(ruleId, appUpdate);
2533 
2534         // Verify the update succeeded.
2535         AutomaticZenRule result = mNotificationManager.getAutomaticZenRule(ruleId);
2536         assertRulesEqual(appUpdate, result);
2537     }
2538 
2539     @Test
2540     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromApp_forUserModifiedRule_onlySomeFieldsUpdated()2541     public void updateAutomaticZenRule_fromApp_forUserModifiedRule_onlySomeFieldsUpdated() {
2542         AutomaticZenRule original = new AutomaticZenRule.Builder("Original", CONDITION_ID)
2543                 .setConfigurationActivity(CONFIG_ACTIVITY)
2544                 .setType(AutomaticZenRule.TYPE_IMMERSIVE)
2545                 .setIconResId(android.app.notification.current.cts.R.drawable.ic_android)
2546                 .setTriggerDescription("Immerse yourself")
2547                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2548                 .setZenPolicy(new ZenPolicy.Builder()
2549                         .allowRepeatCallers(false)
2550                         .allowAlarms(false)
2551                         .build())
2552                 .setDeviceEffects(new ZenDeviceEffects.Builder()
2553                         .setShouldDisplayGrayscale(true)
2554                         .build())
2555                 .build();
2556         String ruleId = mNotificationManager.addAutomaticZenRule(original);
2557 
2558         // Minimally update the rule "from user".
2559         AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(original)
2560                 // User changes
2561                 .setName("Updated by user")
2562                 .build();
2563         runAsSystemUi(
2564                 () -> mNotificationManager.updateAutomaticZenRule(ruleId, userUpdate,
2565                         /* fromUser= */ true));
2566 
2567         // Now try to update again "from app".
2568         AutomaticZenRule appUpdate = new AutomaticZenRule.Builder(original)
2569                 .setName("Updated")
2570                 .setType(AutomaticZenRule.TYPE_DRIVING)
2571                 .setTriggerDescription("While driving")
2572                 .setIconResId(android.R.drawable.sym_def_app_icon)
2573                 .setEnabled(false)
2574                 .setZenPolicy(new ZenPolicy.Builder(original.getZenPolicy())
2575                         .allowAlarms(true)
2576                         .allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE)
2577                         .build())
2578                 .setDeviceEffects(new ZenDeviceEffects.Builder(original.getDeviceEffects())
2579                         .setShouldDimWallpaper(true)
2580                         .build())
2581                 .build();
2582         mNotificationManager.updateAutomaticZenRule(ruleId, appUpdate);
2583 
2584         // The app-controlled fields should be updated.
2585         AutomaticZenRule result = mNotificationManager.getAutomaticZenRule(ruleId);
2586         assertThat(result.getType()).isEqualTo(appUpdate.getType());
2587         assertThat(result.getTriggerDescription()).isEqualTo(appUpdate.getTriggerDescription());
2588         if (!Flags.modesUi()) {
2589             assertThat(result.getIconResId()).isEqualTo(appUpdate.getIconResId());
2590         }
2591         assertThat(result.isEnabled()).isEqualTo(appUpdate.isEnabled());
2592 
2593         // ... but nothing else should (even though those fields were not _specifically_ modified by
2594         // the user).
2595         assertThat(result.getName()).isEqualTo(userUpdate.getName());
2596         if (Flags.modesUi()) {
2597             assertThat(result.getIconResId()).isEqualTo(userUpdate.getIconResId());
2598         }
2599         assertThat(doPoliciesMatchWithDefaults(result.getZenPolicy(), original.getZenPolicy()))
2600                 .isTrue();
2601         assertThat(result.getDeviceEffects()).isEqualTo(original.getDeviceEffects());
2602     }
2603 
2604     @Test
2605     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
addAutomaticZenRule_forDeletedAndPreviouslyUserModifiedRule_restoresRule()2606     public void addAutomaticZenRule_forDeletedAndPreviouslyUserModifiedRule_restoresRule() {
2607         AutomaticZenRule original = new AutomaticZenRule.Builder("Original", CONDITION_ID)
2608                 .setConfigurationActivity(CONFIG_ACTIVITY)
2609                 .setType(AutomaticZenRule.TYPE_IMMERSIVE)
2610                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2611                 .build();
2612         String ruleId = mNotificationManager.addAutomaticZenRule(original);
2613 
2614         // Rename it "from user".
2615         AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(original)
2616                 // User changes
2617                 .setName("Updated by user")
2618                 .build();
2619         runAsSystemUi(
2620                 () -> mNotificationManager.updateAutomaticZenRule(ruleId, userUpdate,
2621                         /* fromUser= */ true));
2622 
2623         // Now delete it "from app".
2624         mNotificationManager.removeAutomaticZenRule(ruleId);
2625         assertThat(mNotificationManager.getAutomaticZenRule(ruleId)).isNull();
2626 
2627         // Now create it "from app" again, with a new name.
2628         AutomaticZenRule reAddRule = new AutomaticZenRule.Builder(original)
2629                 .setName("Here we go again")
2630                 .build();
2631         String newRuleId = mNotificationManager.addAutomaticZenRule(reAddRule);
2632 
2633         // The rule was added, but the user's customization was restored.
2634         AutomaticZenRule finalRule = mNotificationManager.getAutomaticZenRule(newRuleId);
2635         assertThat(finalRule).isNotNull();
2636         assertThat(finalRule.getName()).isEqualTo("Updated by user");
2637     }
2638 
2639     @Test
2640     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
addAutomaticZenRule_withDeviceEffects_stored()2641     public void addAutomaticZenRule_withDeviceEffects_stored() {
2642         ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
2643                 .setShouldDisplayGrayscale(true)
2644                 .setShouldUseNightMode(true)
2645                 .build();
2646 
2647         AutomaticZenRule newRule = createRule("With effects");
2648         newRule.setDeviceEffects(effects);
2649 
2650         String ruleId = mNotificationManager.addAutomaticZenRule(newRule);
2651         AutomaticZenRule readRule = mNotificationManager.getAutomaticZenRule(ruleId);
2652 
2653         assertThat(readRule.getDeviceEffects()).isEqualTo(effects);
2654     }
2655 
2656     @Test
2657     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
addAutomaticZenRule_withDeviceExtraEffects_storedFromSystem()2658     public void addAutomaticZenRule_withDeviceExtraEffects_storedFromSystem() {
2659         ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
2660                 .setShouldDisplayGrayscale(true)
2661                 .setShouldUseNightMode(true)
2662                 .setExtraEffects(ImmutableSet.of("TIME_TRAVEL", "DINOSAUR_CLONING"))
2663                 .build();
2664         AutomaticZenRule newRule = createRule("With effects");
2665         newRule.setDeviceEffects(effects);
2666 
2667         String ruleId = callAsSystemUi(() -> mNotificationManager.addAutomaticZenRule(newRule));
2668 
2669         AutomaticZenRule readRule = mNotificationManager.getAutomaticZenRule(ruleId);
2670         assertThat(readRule.getDeviceEffects()).isEqualTo(effects);
2671     }
2672 
2673     @Test
2674     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
addAutomaticZenRule_withUnderspecifiedPolicies_filledIn()2675     public void addAutomaticZenRule_withUnderspecifiedPolicies_filledIn() {
2676         AutomaticZenRule noPolicy = new AutomaticZenRule.Builder("no policy", CONDITION_ID)
2677                 .setConfigurationActivity(CONFIG_ACTIVITY)
2678                 .setType(AutomaticZenRule.TYPE_IMMERSIVE)
2679                 .setIconResId(android.app.notification.current.cts.R.drawable.ic_android)
2680                 .setTriggerDescription("whatever")
2681                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2682                 .setZenPolicy(null)  // not really necessary, but doing so explicitly anyway.
2683                 .build();
2684         String noPolicyRuleId = mNotificationManager.addAutomaticZenRule(noPolicy);
2685 
2686         // The resulting actual policy on the rule should be equivalent to the default, with all
2687         // fields fully filled in (rather than being left as null).
2688         AutomaticZenRule readRule = mNotificationManager.getAutomaticZenRule(noPolicyRuleId);
2689         assertThat(readRule.getZenPolicy()).isEqualTo(mDefaultPolicy);
2690 
2691         AutomaticZenRule underspecified = new AutomaticZenRule.Builder("some policy", CONDITION_ID)
2692                 .setConfigurationActivity(CONFIG_ACTIVITY)
2693                 .setType(AutomaticZenRule.TYPE_IMMERSIVE)
2694                 .setIconResId(android.app.notification.current.cts.R.drawable.ic_android)
2695                 .setTriggerDescription("whatever")
2696                 .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
2697                 .setZenPolicy(new ZenPolicy.Builder()
2698                         .allowAlarms(true)
2699                         .allowMedia(false)
2700                         .build())
2701                 .build();
2702         String underspecRuleId = mNotificationManager.addAutomaticZenRule(underspecified);
2703 
2704         AutomaticZenRule readRule2 = mNotificationManager.getAutomaticZenRule(underspecRuleId);
2705         assertThat(readRule2.getZenPolicy()).isEqualTo(
2706                 mDefaultPolicy.overwrittenWith(underspecified.getZenPolicy()));
2707     }
2708 
2709     @Test
2710     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
getAutomaticZenRuleState_returnsRuleState()2711     public void getAutomaticZenRuleState_returnsRuleState() {
2712         AutomaticZenRule rule = createRule("Test");
2713 
2714         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2715         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(
2716                 Condition.STATE_FALSE);
2717 
2718         mNotificationManager.setAutomaticZenRuleState(ruleId,
2719                 new Condition(rule.getConditionId(), "", Condition.STATE_TRUE));
2720         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(
2721                 Condition.STATE_TRUE);
2722 
2723         mNotificationManager.setAutomaticZenRuleState(ruleId,
2724                 new Condition(rule.getConditionId(), "", Condition.STATE_FALSE));
2725         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(
2726                 Condition.STATE_FALSE);
2727 
2728         mNotificationManager.removeAutomaticZenRule(ruleId);
2729         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(
2730                 Condition.STATE_UNKNOWN);
2731     }
2732 
2733     @Test
2734     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
setAutomaticZenRuleState_ruleWithGrayscale_applied()2735     public void setAutomaticZenRuleState_ruleWithGrayscale_applied() throws Exception {
2736         assertThat(isColorDisplayManagerSaturationActivated()).isFalse();
2737 
2738         AutomaticZenRule rule = createRule("Grayscale");
2739         rule.setDeviceEffects(new ZenDeviceEffects.Builder()
2740                 .setShouldDisplayGrayscale(true)
2741                 .build());
2742         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2743 
2744         mNotificationManager.setAutomaticZenRuleState(ruleId,
2745                 new Condition(rule.getConditionId(), "yeah", Condition.STATE_TRUE));
2746         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2747         assertThat(isColorDisplayManagerSaturationActivated()).isTrue();
2748 
2749         mNotificationManager.setAutomaticZenRuleState(ruleId,
2750                 new Condition(rule.getConditionId(), "nope", Condition.STATE_FALSE));
2751         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2752         assertThat(isColorDisplayManagerSaturationActivated()).isFalse();
2753     }
2754 
2755     @Test
2756     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
setAutomaticZenRuleState_ruleWithDimWallpaper_applied()2757     public void setAutomaticZenRuleState_ruleWithDimWallpaper_applied() throws Exception {
2758         assumeTrue(mContext.getSystemService(WallpaperManager.class).isWallpaperSupported());
2759         assertThat(getWallpaperManagerDimAmount()).isZero();
2760 
2761         AutomaticZenRule rule = createRule("Dim wallpaper");
2762         rule.setDeviceEffects(new ZenDeviceEffects.Builder().setShouldDimWallpaper(true).build());
2763         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2764 
2765         mNotificationManager.setAutomaticZenRuleState(ruleId,
2766                 new Condition(rule.getConditionId(), "yeah", Condition.STATE_TRUE));
2767         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2768         assertThat(getWallpaperManagerDimAmount()).isNonZero();
2769 
2770         mNotificationManager.setAutomaticZenRuleState(ruleId,
2771                 new Condition(rule.getConditionId(), "nope", Condition.STATE_FALSE));
2772         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2773         assertThat(getWallpaperManagerDimAmount()).isZero();
2774     }
2775 
2776     @Test
2777     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
setAutomaticZenRuleState_ruleWithDisableAmbientDisplay_applied()2778     public void setAutomaticZenRuleState_ruleWithDisableAmbientDisplay_applied() throws Exception {
2779         assertThat(isPowerManagerAmbientDisplaySuppressed()).isFalse();
2780 
2781         AutomaticZenRule rule = createRule("Disable ambient display");
2782         rule.setDeviceEffects(new ZenDeviceEffects.Builder()
2783                 .setShouldSuppressAmbientDisplay(true)
2784                 .build());
2785         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2786 
2787         mNotificationManager.setAutomaticZenRuleState(ruleId,
2788                 new Condition(rule.getConditionId(), "yeah", Condition.STATE_TRUE));
2789         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2790         assertThat(isPowerManagerAmbientDisplaySuppressed()).isTrue();
2791 
2792         mNotificationManager.setAutomaticZenRuleState(ruleId,
2793                 new Condition(rule.getConditionId(), "nope", Condition.STATE_FALSE));
2794         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2795         assertThat(isPowerManagerAmbientDisplaySuppressed()).isFalse();
2796     }
2797 
2798     @Test
2799     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
setAutomaticZenRuleState_ruleWithNightMode_appliedImmediately()2800     public void setAutomaticZenRuleState_ruleWithNightMode_appliedImmediately() throws Exception {
2801         assertThat(isUiModeManagerThemeOverlayActive()).isFalse();
2802 
2803         AutomaticZenRule rule = createRule("Grayscale");
2804         rule.setDeviceEffects(new ZenDeviceEffects.Builder()
2805                 .setShouldUseNightMode(true)
2806                 .build());
2807         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2808 
2809         mNotificationManager.setAutomaticZenRuleState(ruleId,
2810                 new Condition(rule.getConditionId(), "yeah", Condition.STATE_TRUE,
2811                         Condition.SOURCE_USER_ACTION));
2812         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2813         assertThat(isUiModeManagerThemeOverlayActive()).isTrue();
2814 
2815         mNotificationManager.setAutomaticZenRuleState(ruleId,
2816                 new Condition(rule.getConditionId(), "nope", Condition.STATE_FALSE,
2817                         Condition.SOURCE_USER_ACTION));
2818         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2819         assertThat(isUiModeManagerThemeOverlayActive()).isFalse();
2820     }
2821 
2822     @RequireNotVisibleBackgroundUsers(reason =
2823             "Visible background user devices (primarily Android auto) currently don't support "
2824             + "per display interactiveness. So when the screen Off event is sent, "
2825             + "PowerManager#IsInteractive is still true while driver screen is off as passenger "
2826             + "screens are on. It also doesn't trigger the code path related to global "
2827             + "wakefulness in power manager. The test will be enabled once per display "
2828             + "interactiveness is supported on MUMD. relevant bugs: b/370631032")
2829     @Test
2830     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
setAutomaticZenRuleState_ruleWithNightMode_appliedOnScreenOff()2831     public void setAutomaticZenRuleState_ruleWithNightMode_appliedOnScreenOff() throws Exception {
2832         assertThat(isUiModeManagerThemeOverlayActive()).isFalse();
2833 
2834         AutomaticZenRule rule = createRule("Grayscale");
2835         rule.setDeviceEffects(new ZenDeviceEffects.Builder()
2836                 .setShouldUseNightMode(true)
2837                 .build());
2838         String ruleId = mNotificationManager.addAutomaticZenRule(rule);
2839 
2840         mNotificationManager.setAutomaticZenRuleState(ruleId,
2841                 new Condition(rule.getConditionId(), "yeah", Condition.STATE_TRUE,
2842                         Condition.SOURCE_SCHEDULE));
2843         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2844 
2845         assertThat(isUiModeManagerThemeOverlayActive()).isFalse(); // Not yet applied.
2846 
2847         // Have you tried turning it off and on again?
2848         turnScreenOffAndOn();
2849         assertThat(isUiModeManagerThemeOverlayActive()).isTrue();
2850 
2851         mNotificationManager.setAutomaticZenRuleState(ruleId,
2852                 new Condition(rule.getConditionId(), "nope", Condition.STATE_FALSE,
2853                         Condition.SOURCE_SCHEDULE));
2854         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2855 
2856         assertThat(isUiModeManagerThemeOverlayActive()).isTrue(); // Not yet applied.
2857 
2858         turnScreenOffAndOn();
2859         assertThat(isUiModeManagerThemeOverlayActive()).isFalse();
2860     }
2861 
2862     @Test
2863     @RequiresFlagsEnabled(Flags.FLAG_MODES_API)
setAutomaticZenRuleState_multipleRulesWithDeviceEffects_effectsMerged()2864     public void setAutomaticZenRuleState_multipleRulesWithDeviceEffects_effectsMerged()
2865             throws Exception {
2866         AutomaticZenRule withDisableAmbientDisplay = createRule("Disable ambient display");
2867         withDisableAmbientDisplay.setDeviceEffects(new ZenDeviceEffects.Builder()
2868                 .setShouldSuppressAmbientDisplay(true)
2869                 .build());
2870         String withDisableAmbientDisplayId = mNotificationManager.addAutomaticZenRule(
2871                 withDisableAmbientDisplay);
2872 
2873         AutomaticZenRule withGrayscale = createRule("With grayscale");
2874         withGrayscale.setDeviceEffects(new ZenDeviceEffects.Builder()
2875                 .setShouldDisplayGrayscale(true)
2876                 .build());
2877         String withGrayscaleId = mNotificationManager.addAutomaticZenRule(withGrayscale);
2878 
2879         mNotificationManager.setAutomaticZenRuleState(withDisableAmbientDisplayId,
2880                 new Condition(withDisableAmbientDisplay.getConditionId(), "ad",
2881                         Condition.STATE_TRUE));
2882         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2883         assertThat(isPowerManagerAmbientDisplaySuppressed()).isTrue();
2884         assertThat(isColorDisplayManagerSaturationActivated()).isFalse();
2885 
2886         mNotificationManager.setAutomaticZenRuleState(withGrayscaleId,
2887                 new Condition(withGrayscale.getConditionId(), "gs", Condition.STATE_TRUE));
2888         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2889         assertThat(isPowerManagerAmbientDisplaySuppressed()).isTrue();
2890         assertThat(isColorDisplayManagerSaturationActivated()).isTrue();
2891 
2892         mNotificationManager.setAutomaticZenRuleState(withDisableAmbientDisplayId,
2893                 new Condition(withDisableAmbientDisplay.getConditionId(), "ad",
2894                         Condition.STATE_FALSE));
2895         Thread.sleep(ZEN_EFFECTS_WAIT_MS); // Effects are applied asynchronously.
2896         assertThat(isPowerManagerAmbientDisplaySuppressed()).isFalse();
2897         assertThat(isColorDisplayManagerSaturationActivated()).isTrue();
2898     }
2899 
getWallpaperManagerDimAmount()2900     private float getWallpaperManagerDimAmount() {
2901         WallpaperManager wallpaperManager = checkNotNull(
2902                 mContext.getSystemService(WallpaperManager.class));
2903         return SystemUtil.runWithShellPermissionIdentity(
2904                 () -> wallpaperManager.getWallpaperDimAmount(),
2905                 Manifest.permission.SET_WALLPAPER_DIM_AMOUNT);
2906     }
2907 
isPowerManagerAmbientDisplaySuppressed()2908     private boolean isPowerManagerAmbientDisplaySuppressed() {
2909         PowerManager powerManager = checkNotNull(mContext.getSystemService(PowerManager.class));
2910         return SystemUtil.runWithShellPermissionIdentity(
2911                 () -> powerManager.isAmbientDisplaySuppressed(),
2912                 Manifest.permission.READ_DREAM_STATE);
2913     }
2914 
isColorDisplayManagerSaturationActivated()2915     private boolean isColorDisplayManagerSaturationActivated() {
2916         ColorDisplayManager colorDisplayManager = checkNotNull(
2917                 mContext.getSystemService(ColorDisplayManager.class));
2918         return SystemUtil.runWithShellPermissionIdentity(
2919                 () -> colorDisplayManager.isSaturationActivated(),
2920                 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS);
2921     }
2922 
isUiModeManagerThemeOverlayActive()2923     private boolean isUiModeManagerThemeOverlayActive() {
2924         UiModeManager uiModeManager = checkNotNull(mContext.getSystemService(UiModeManager.class));
2925         return SystemUtil.runWithShellPermissionIdentity(
2926                 () -> uiModeManager.getAttentionModeThemeOverlay()
2927                         == UiModeManager.MODE_ATTENTION_THEME_OVERLAY_NIGHT,
2928                 Manifest.permission.MODIFY_DAY_NIGHT_MODE);
2929     }
2930 
turnScreenOffAndOn()2931     private void turnScreenOffAndOn() throws Exception {
2932         ScreenUtils.setScreenOn(false);
2933         CtsAppTestUtils.turnScreenOn(mInstrumentation, mContext);
2934     }
2935 
2936     @Test
testSetInterruptionFilter_usesAutomaticZenRule()2937     public void testSetInterruptionFilter_usesAutomaticZenRule() throws Exception {
2938         // NMS: MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES
2939         if (!android.app.Flags.modesApi() || !CompatChanges.isChangeEnabled(308670109L)) {
2940             return;
2941         }
2942         assertThat(mNotificationManager.getAutomaticZenRules()).isEmpty();
2943 
2944         mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
2945 
2946         // The filter was applied, but through a rule.
2947         assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
2948         Map<String, AutomaticZenRule> zenRules = mNotificationManager.getAutomaticZenRules();
2949         assertThat(zenRules).hasSize(1);
2950         AutomaticZenRule rule = Iterables.getOnlyElement(zenRules.values());
2951         assertThat(rule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
2952     }
2953 
2954     @Test
testSetNotificationPolicy_usesAutomaticZenRule()2955     public void testSetNotificationPolicy_usesAutomaticZenRule() {
2956         // NMS: MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES
2957         if (!android.app.Flags.modesApi() || !CompatChanges.isChangeEnabled(308670109L)) {
2958             return;
2959         }
2960         assertThat(mNotificationManager.getAutomaticZenRules()).isEmpty();
2961 
2962         NotificationManager.Policy policy = new NotificationManager.Policy(
2963                 PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_REPEAT_CALLERS,
2964                 0, 0);
2965         mNotificationManager.setNotificationPolicy(policy);
2966 
2967         // The policy was mapped to a rule.
2968         Map<String, AutomaticZenRule> zenRules = mNotificationManager.getAutomaticZenRules();
2969         assertThat(zenRules).hasSize(1);
2970         ZenPolicy ruleZen = Iterables.getOnlyElement(zenRules.values()).getZenPolicy();
2971         assertThat(ruleZen).isNotNull();
2972 
2973         assertThat(ruleZen.getPriorityCategoryAlarms()).isEqualTo(ZenPolicy.STATE_ALLOW);
2974         assertThat(ruleZen.getPriorityCategoryRepeatCallers()).isEqualTo(ZenPolicy.STATE_ALLOW);
2975         assertThat(ruleZen.getPriorityCategoryCalls()).isEqualTo(ZenPolicy.STATE_DISALLOW);
2976         assertThat(ruleZen.getPriorityCategoryMedia()).isEqualTo(ZenPolicy.STATE_DISALLOW);
2977         assertThat(ruleZen.getPriorityCategorySystem()).isEqualTo(ZenPolicy.STATE_DISALLOW);
2978     }
2979 
2980     @Test
testSetInterruptionFilter_withSetNotificationPolicy_sharesAutomaticZenRule()2981     public void testSetInterruptionFilter_withSetNotificationPolicy_sharesAutomaticZenRule() {
2982         // NMS: MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES
2983         if (!android.app.Flags.modesApi() || !CompatChanges.isChangeEnabled(308670109L)) {
2984             return;
2985         }
2986         assertThat(mNotificationManager.getAutomaticZenRules()).isEmpty();
2987 
2988         NotificationManager.Policy policy = new NotificationManager.Policy(
2989                 PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_REPEAT_CALLERS,
2990                 0, 0);
2991         mNotificationManager.setNotificationPolicy(policy);
2992         mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
2993 
2994         // The policy and interruption filter were mapped to the same rule.
2995         Map<String, AutomaticZenRule> zenRules = mNotificationManager.getAutomaticZenRules();
2996         assertThat(zenRules).hasSize(1);
2997         AutomaticZenRule rule = Iterables.getOnlyElement(zenRules.values());
2998         assertThat(rule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
2999         ZenPolicy ruleZen = rule.getZenPolicy();
3000         assertThat(ruleZen).isNotNull();
3001         assertThat(ruleZen.getPriorityCategoryAlarms()).isEqualTo(ZenPolicy.STATE_ALLOW);
3002         assertThat(ruleZen.getPriorityCategoryCalls()).isEqualTo(ZenPolicy.STATE_DISALLOW);
3003 
3004         // The rule was turned on, and is working.
3005         assertThat(mNotificationManager.getCurrentInterruptionFilter()).isEqualTo(
3006                 INTERRUPTION_FILTER_PRIORITY);
3007         NotificationManager.Policy activePolicy =
3008                 mNotificationManager.getConsolidatedNotificationPolicy();
3009         assertThat(activePolicy.priorityCategories & PRIORITY_CATEGORY_ALARMS).isNotEqualTo(0);
3010         assertThat(activePolicy.priorityCategories & PRIORITY_CATEGORY_CALLS).isEqualTo(0);
3011     }
3012 
3013     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
3014     @Test
testIndividualRuleIntent_resolvesToActivity()3015     public void testIndividualRuleIntent_resolvesToActivity() {
3016         assumeTrue(mNotificationManager.areAutomaticZenRulesUserManaged());
3017 
3018         AutomaticZenRule ruleToCreate = createRule("testIndividualRuleIntent_resolvesToActivity");
3019         String id = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3020         final PackageManager pm = mContext.getPackageManager();
3021         final Intent intent = new Intent(Settings.ACTION_AUTOMATIC_ZEN_RULE_SETTINGS);
3022         intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id);
3023 
3024         final ResolveInfo resolveInfo = pm.resolveActivity(intent, MATCH_DEFAULT_ONLY);
3025         assertNotNull(resolveInfo);
3026     }
3027 
3028     @Test
3029     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_TEST})
setAutomaticZenRuleState_manualActivation()3030     public void setAutomaticZenRuleState_manualActivation() {
3031         AutomaticZenRule ruleToCreate = createRule("rule");
3032         String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3033         Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-on",
3034                 STATE_TRUE, Condition.SOURCE_USER_ACTION);
3035         Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3036                 STATE_FALSE, Condition.SOURCE_USER_ACTION);
3037         Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on",
3038                 STATE_TRUE);
3039         Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off",
3040                 STATE_FALSE);
3041 
3042         // User manually activates -> it's active.
3043         runAsSystemUi(
3044                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate));
3045         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3046 
3047         // User manually deactivates -> it's inactive.
3048         runAsSystemUi(
3049                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate));
3050         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3051 
3052         // And app can activate and deactivate.
3053         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3054         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3055         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3056         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3057     }
3058 
3059     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_TEST})
3060     @Test
setAutomaticZenRuleState_manualDeactivation()3061     public void setAutomaticZenRuleState_manualDeactivation() {
3062         AutomaticZenRule ruleToCreate = createRule("rule");
3063         String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3064         Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-on",
3065                 STATE_TRUE, Condition.SOURCE_USER_ACTION);
3066         Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3067                 STATE_FALSE, Condition.SOURCE_USER_ACTION);
3068         Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on",
3069                 STATE_TRUE);
3070         Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off",
3071                 STATE_FALSE);
3072 
3073         // App activates rule.
3074         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3075         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3076 
3077         // User manually deactivates -> it's inactive.
3078         runAsSystemUi(
3079                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate));
3080         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3081 
3082         // User manually reactivates -> it's active.
3083         runAsSystemUi(
3084                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate));
3085         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3086 
3087         // That manual activation removed the override-deactivate, but didn't put an
3088         // override-activate, so app can deactivate when its natural schedule ends.
3089         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3090         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3091     }
3092 
3093     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_TEST})
3094     @Test
setAutomaticZenRuleState_respectsManuallyActivated()3095     public void setAutomaticZenRuleState_respectsManuallyActivated() {
3096         AutomaticZenRule ruleToCreate = createRule("rule");
3097         String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3098         Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-on",
3099                 STATE_TRUE, Condition.SOURCE_USER_ACTION);
3100         Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on",
3101                 STATE_TRUE);
3102         Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off",
3103                 STATE_FALSE);
3104 
3105         // App thinks rule should be inactive.
3106         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3107         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3108 
3109         // Manually activate -> it's active.
3110         runAsSystemUi(() -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate));
3111         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3112 
3113         // App says it should be inactive, but it's ignored.
3114         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3115         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3116 
3117         // App says it should be active. No change now...
3118         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3119         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3120 
3121         // ... but when the app wants to deactivate next time, it works.
3122         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3123         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3124     }
3125 
3126     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_TEST})
3127     @Test
setAutomaticZenRuleState_respectsManuallyDeactivated()3128     public void setAutomaticZenRuleState_respectsManuallyDeactivated() {
3129         AutomaticZenRule ruleToCreate = createRule("rule");
3130         String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3131         Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3132                 STATE_FALSE, Condition.SOURCE_USER_ACTION);
3133         Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on",
3134                 STATE_TRUE);
3135         Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off",
3136                 STATE_FALSE);
3137 
3138         // App activates rule.
3139         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3140         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3141 
3142         // User manually deactivates -> it's inactive.
3143         runAsSystemUi(
3144                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate));
3145         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3146 
3147         // App says it should be active, but it's ignored.
3148         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3149         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3150 
3151         // App says it should be inactive. No change now...
3152         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3153         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3154 
3155         // ... but when the app wants to activate next time, it works.
3156         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3157         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3158     }
3159 
3160     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_TEST})
3161     @Test
setAutomaticZenRuleState_manualActivationFromApp()3162     public void setAutomaticZenRuleState_manualActivationFromApp() {
3163         AutomaticZenRule ruleToCreate = createRule("rule");
3164         String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3165         Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3166                 STATE_TRUE, Condition.SOURCE_USER_ACTION);
3167         Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3168                 STATE_FALSE, Condition.SOURCE_USER_ACTION);
3169         Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on",
3170                 STATE_TRUE);
3171         Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off",
3172                 STATE_FALSE);
3173 
3174         // App activates rule.
3175         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3176         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3177 
3178         // User manually deactivates from SysUI -> it's inactive.
3179         runAsSystemUi(
3180                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate));
3181         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3182 
3183         // User manually activates from App -> it's active.
3184         mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate);
3185         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3186 
3187         // And app can automatically deactivate it later.
3188         mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate);
3189         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3190     }
3191 
3192     @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_TEST})
3193     @Test
setAutomaticZenRuleState_manualDeactivationFromApp()3194     public void setAutomaticZenRuleState_manualDeactivationFromApp() {
3195         AutomaticZenRule ruleToCreate = createRule("rule");
3196         String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
3197         Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3198                 STATE_TRUE, Condition.SOURCE_USER_ACTION);
3199         Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off",
3200                 STATE_FALSE, Condition.SOURCE_USER_ACTION);
3201         Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on",
3202                 STATE_TRUE);
3203 
3204         // User manually activates from SysUI -> it's active.
3205         runAsSystemUi(
3206                 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate));
3207         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3208 
3209         // User manually deactivates from App -> it's inactive.
3210         mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate);
3211         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
3212 
3213         // And app can automatically activate it later.
3214         mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate);
3215         assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
3216     }
3217 
3218 }
3219