• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.notification;
18 
19 import static android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS;
20 import static android.Manifest.permission.STATUS_BAR_SERVICE;
21 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
22 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
23 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
24 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
25 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
26 import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
27 import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME;
28 import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
29 import static android.app.Notification.EXTRA_PICTURE;
30 import static android.app.Notification.EXTRA_PICTURE_ICON;
31 import static android.app.Notification.EXTRA_TEXT;
32 import static android.app.Notification.FLAG_AUTO_CANCEL;
33 import static android.app.Notification.FLAG_BUBBLE;
34 import static android.app.Notification.FLAG_CAN_COLORIZE;
35 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
36 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
37 import static android.app.Notification.FLAG_NO_CLEAR;
38 import static android.app.Notification.FLAG_NO_DISMISS;
39 import static android.app.Notification.FLAG_ONGOING_EVENT;
40 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
41 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
42 import static android.app.Notification.VISIBILITY_PRIVATE;
43 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
44 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
45 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
46 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
47 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
48 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
49 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
50 import static android.app.NotificationManager.IMPORTANCE_HIGH;
51 import static android.app.NotificationManager.IMPORTANCE_LOW;
52 import static android.app.NotificationManager.IMPORTANCE_MAX;
53 import static android.app.NotificationManager.IMPORTANCE_NONE;
54 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
55 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
56 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
57 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
58 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
59 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
60 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
61 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
62 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
63 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
64 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
65 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
66 import static android.app.PendingIntent.FLAG_IMMUTABLE;
67 import static android.app.PendingIntent.FLAG_MUTABLE;
68 import static android.app.PendingIntent.FLAG_ONE_SHOT;
69 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED;
70 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED;
71 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
72 import static android.content.pm.PackageManager.FEATURE_TELECOM;
73 import static android.content.pm.PackageManager.FEATURE_WATCH;
74 import static android.content.pm.PackageManager.PERMISSION_DENIED;
75 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
76 import static android.media.AudioAttributes.USAGE_MEDIA;
77 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
78 import static android.os.Build.VERSION_CODES.O_MR1;
79 import static android.os.Build.VERSION_CODES.P;
80 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
81 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
82 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
83 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
84 import static android.os.UserHandle.USER_SYSTEM;
85 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
86 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
87 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
88 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
89 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
90 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
91 import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
92 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
93 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
94 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
95 import static android.service.notification.Condition.SOURCE_CONTEXT;
96 import static android.service.notification.Condition.SOURCE_USER_ACTION;
97 import static android.service.notification.Condition.STATE_TRUE;
98 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
99 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
100 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
101 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
102 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
103 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
104 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
105 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
106 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
107 import static android.view.Display.DEFAULT_DISPLAY;
108 import static android.view.Display.INVALID_DISPLAY;
109 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
110 
111 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
112 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
113 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
114 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
115 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL;
116 import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS;
117 import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
118 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
119 import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL;
120 import static com.android.server.notification.NotificationManagerService.TAG;
121 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
122 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
123 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
124 
125 import static com.google.common.collect.Iterables.getOnlyElement;
126 import static com.google.common.truth.Truth.assertThat;
127 import static com.google.common.truth.Truth.assertWithMessage;
128 
129 import static junit.framework.Assert.assertEquals;
130 import static junit.framework.Assert.assertFalse;
131 import static junit.framework.Assert.assertNotNull;
132 import static junit.framework.Assert.assertNotSame;
133 import static junit.framework.Assert.assertNull;
134 import static junit.framework.Assert.assertSame;
135 import static junit.framework.Assert.assertTrue;
136 import static junit.framework.Assert.fail;
137 
138 import static org.junit.Assert.assertNotEquals;
139 import static org.junit.Assert.assertThrows;
140 import static org.mockito.ArgumentMatchers.isNull;
141 import static org.mockito.Matchers.anyBoolean;
142 import static org.mockito.Matchers.anyLong;
143 import static org.mockito.Matchers.anyString;
144 import static org.mockito.Matchers.eq;
145 import static org.mockito.Mockito.any;
146 import static org.mockito.Mockito.anyInt;
147 import static org.mockito.Mockito.atLeastOnce;
148 import static org.mockito.Mockito.clearInvocations;
149 import static org.mockito.Mockito.doAnswer;
150 import static org.mockito.Mockito.doNothing;
151 import static org.mockito.Mockito.doReturn;
152 import static org.mockito.Mockito.doThrow;
153 import static org.mockito.Mockito.inOrder;
154 import static org.mockito.Mockito.mock;
155 import static org.mockito.Mockito.never;
156 import static org.mockito.Mockito.reset;
157 import static org.mockito.Mockito.spy;
158 import static org.mockito.Mockito.timeout;
159 import static org.mockito.Mockito.times;
160 import static org.mockito.Mockito.verify;
161 import static org.mockito.Mockito.verifyNoMoreInteractions;
162 import static org.mockito.Mockito.when;
163 
164 import static java.util.Collections.emptyList;
165 import static java.util.Collections.singletonList;
166 
167 import android.Manifest;
168 import android.annotation.Nullable;
169 import android.annotation.SuppressLint;
170 import android.annotation.UserIdInt;
171 import android.app.ActivityManager;
172 import android.app.ActivityManagerInternal;
173 import android.app.AlarmManager;
174 import android.app.AppOpsManager;
175 import android.app.AutomaticZenRule;
176 import android.app.IActivityManager;
177 import android.app.ICallNotificationEventCallback;
178 import android.app.INotificationManager;
179 import android.app.ITransientNotification;
180 import android.app.IUriGrantsManager;
181 import android.app.Notification;
182 import android.app.Notification.MessagingStyle.Message;
183 import android.app.NotificationChannel;
184 import android.app.NotificationChannelGroup;
185 import android.app.NotificationManager;
186 import android.app.PendingIntent;
187 import android.app.Person;
188 import android.app.RemoteInput;
189 import android.app.RemoteInputHistoryItem;
190 import android.app.StatsManager;
191 import android.app.admin.DevicePolicyManagerInternal;
192 import android.app.job.JobScheduler;
193 import android.app.role.RoleManager;
194 import android.app.usage.UsageStatsManagerInternal;
195 import android.companion.AssociationInfo;
196 import android.companion.AssociationRequest;
197 import android.companion.ICompanionDeviceManager;
198 import android.compat.testing.PlatformCompatChangeRule;
199 import android.content.BroadcastReceiver;
200 import android.content.ComponentName;
201 import android.content.ContentUris;
202 import android.content.Context;
203 import android.content.IIntentSender;
204 import android.content.Intent;
205 import android.content.IntentFilter;
206 import android.content.pm.ActivityInfo;
207 import android.content.pm.ApplicationInfo;
208 import android.content.pm.IPackageManager;
209 import android.content.pm.LauncherApps;
210 import android.content.pm.ModuleInfo;
211 import android.content.pm.PackageInfo;
212 import android.content.pm.PackageManager;
213 import android.content.pm.PackageManagerInternal;
214 import android.content.pm.ParceledListSlice;
215 import android.content.pm.ResolveInfo;
216 import android.content.pm.ShortcutInfo;
217 import android.content.pm.ShortcutServiceInternal;
218 import android.content.pm.UserInfo;
219 import android.content.pm.VersionedPackage;
220 import android.content.res.Resources;
221 import android.graphics.Bitmap;
222 import android.graphics.Color;
223 import android.graphics.drawable.Icon;
224 import android.media.AudioAttributes;
225 import android.media.AudioManager;
226 import android.media.session.MediaSession;
227 import android.net.Uri;
228 import android.os.Binder;
229 import android.os.Build;
230 import android.os.Bundle;
231 import android.os.IBinder;
232 import android.os.Looper;
233 import android.os.Parcel;
234 import android.os.Parcelable;
235 import android.os.PowerManager;
236 import android.os.PowerManager.WakeLock;
237 import android.os.Process;
238 import android.os.RemoteException;
239 import android.os.SystemClock;
240 import android.os.UserHandle;
241 import android.os.UserManager;
242 import android.os.WorkSource;
243 import android.permission.PermissionManager;
244 import android.platform.test.annotations.DisableFlags;
245 import android.platform.test.annotations.EnableFlags;
246 import android.platform.test.flag.junit.FlagsParameterization;
247 import android.platform.test.flag.junit.SetFlagsRule;
248 import android.platform.test.rule.LimitDevicesRule;
249 import android.provider.MediaStore;
250 import android.provider.Settings;
251 import android.service.notification.Adjustment;
252 import android.service.notification.Condition;
253 import android.service.notification.ConversationChannelWrapper;
254 import android.service.notification.DeviceEffectsApplier;
255 import android.service.notification.INotificationListener;
256 import android.service.notification.NotificationListenerFilter;
257 import android.service.notification.NotificationListenerService;
258 import android.service.notification.NotificationRankingUpdate;
259 import android.service.notification.NotificationStats;
260 import android.service.notification.StatusBarNotification;
261 import android.service.notification.ZenModeConfig;
262 import android.service.notification.ZenPolicy;
263 import android.telecom.TelecomManager;
264 import android.testing.TestWithLooperRule;
265 import android.testing.TestableContentResolver;
266 import android.testing.TestableLooper;
267 import android.testing.TestableLooper.RunWithLooper;
268 import android.testing.TestablePermissions;
269 import android.testing.TestableResources;
270 import android.text.Html;
271 import android.text.TextUtils;
272 import android.util.ArrayMap;
273 import android.util.ArraySet;
274 import android.util.AtomicFile;
275 import android.util.Log;
276 import android.util.Pair;
277 import android.util.Xml;
278 import android.view.accessibility.AccessibilityManager;
279 import android.widget.RemoteViews;
280 
281 import androidx.test.InstrumentationRegistry;
282 import androidx.test.filters.SmallTest;
283 
284 import com.android.internal.R;
285 import com.android.internal.config.sysui.TestableFlagResolver;
286 import com.android.internal.logging.InstanceIdSequence;
287 import com.android.internal.logging.InstanceIdSequenceFake;
288 import com.android.internal.messages.nano.SystemMessageProto;
289 import com.android.internal.statusbar.NotificationVisibility;
290 import com.android.internal.widget.LockPatternUtils;
291 import com.android.modules.utils.TypedXmlPullParser;
292 import com.android.modules.utils.TypedXmlSerializer;
293 import com.android.server.DeviceIdleInternal;
294 import com.android.server.LocalServices;
295 import com.android.server.SystemService;
296 import com.android.server.SystemService.TargetUser;
297 import com.android.server.UiServiceTestCase;
298 import com.android.server.job.JobSchedulerInternal;
299 import com.android.server.lights.LightsManager;
300 import com.android.server.lights.LogicalLight;
301 import com.android.server.notification.GroupHelper.NotificationAttributes;
302 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
303 import com.android.server.notification.NotificationManagerService.NotificationListeners;
304 import com.android.server.notification.NotificationManagerService.PostNotificationTracker;
305 import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory;
306 import com.android.server.pm.PackageManagerService;
307 import com.android.server.pm.UserManagerInternal;
308 import com.android.server.policy.PermissionPolicyInternal;
309 import com.android.server.statusbar.StatusBarManagerInternal;
310 import com.android.server.uri.UriGrantsManagerInternal;
311 import com.android.server.utils.quota.MultiRateLimiter;
312 import com.android.server.wm.ActivityTaskManagerInternal;
313 import com.android.server.wm.WindowManagerInternal;
314 
315 import com.google.android.collect.Lists;
316 import com.google.common.collect.ImmutableList;
317 
318 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
319 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
320 
321 import org.junit.After;
322 import org.junit.Assert;
323 import org.junit.Before;
324 import org.junit.ClassRule;
325 import org.junit.Rule;
326 import org.junit.Test;
327 import org.junit.rules.TestRule;
328 import org.junit.runner.RunWith;
329 import org.mockito.ArgumentCaptor;
330 import org.mockito.ArgumentMatcher;
331 import org.mockito.ArgumentMatchers;
332 import org.mockito.InOrder;
333 import org.mockito.Mock;
334 import org.mockito.Mockito;
335 import org.mockito.MockitoAnnotations;
336 import org.mockito.invocation.InvocationOnMock;
337 import org.mockito.stubbing.Answer;
338 
339 import java.io.BufferedInputStream;
340 import java.io.BufferedOutputStream;
341 import java.io.ByteArrayInputStream;
342 import java.io.ByteArrayOutputStream;
343 import java.io.File;
344 import java.io.FileOutputStream;
345 import java.time.Duration;
346 import java.util.ArrayList;
347 import java.util.Arrays;
348 import java.util.List;
349 import java.util.Map;
350 import java.util.concurrent.CountDownLatch;
351 import java.util.function.Consumer;
352 
353 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
354 import platform.test.runner.parameterized.Parameters;
355 
356 @SmallTest
357 @RunWith(ParameterizedAndroidJunit4.class)
358 @RunWithLooper
359 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
360 public class NotificationManagerServiceTest extends UiServiceTestCase {
361     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
362     private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package";
363     private static final String PKG_NO_CHANNELS = "com.example.no.channels";
364     private static final int TEST_TASK_ID = 1;
365     private static final int UID_HEADLESS = 1_000_000;
366     private static final int TOAST_DURATION = 2_000;
367     private static final int SECONDARY_DISPLAY_ID = 42;
368     private static final int TEST_PROFILE_USERHANDLE = 12;
369 
370     private static final String ACTION_NOTIFICATION_TIMEOUT =
371             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
372     private static final String EXTRA_KEY = "key";
373     private static final String SCHEME_TIMEOUT = "timeout";
374     private static final String REDACTED_TEXT = "redacted text";
375 
376     private static final AutomaticZenRule SOME_ZEN_RULE =
377             new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
378                     .setOwner(new ComponentName("pkg", "cls"))
379                     .build();
380 
381     @ClassRule
382     public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule();
383 
384     @Rule
385     public TestRule compatChangeRule = new PlatformCompatChangeRule();
386 
387     private TestableNotificationManagerService mService;
388     private INotificationManager mBinderService;
389     private NotificationManagerInternal mInternalService;
390     private ShortcutHelper mShortcutHelper;
391     @Mock
392     private IPackageManager mPackageManager;
393     @Mock
394     private PackageManager mPackageManagerClient;
395     @Mock
396     private PackageManagerInternal mPackageManagerInternal;
397     @Mock
398     private PermissionPolicyInternal mPermissionPolicyInternal;
399     @Mock
400     private WindowManagerInternal mWindowManagerInternal;
401     @Mock
402     private PermissionHelper mPermissionHelper;
403     private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
404     @Rule(order = Integer.MAX_VALUE)
405     public TestWithLooperRule mlooperRule = new TestWithLooperRule();
406     private TestableLooper mTestableLooper;
407     @Mock
408     private RankingHelper mRankingHelper;
409     @Mock private PreferencesHelper mPreferencesHelper;
410     AtomicFile mPolicyFile;
411     File mFile;
412     @Mock
413     private NotificationUsageStats mUsageStats;
414     @Mock
415     private UsageStatsManagerInternal mAppUsageStats;
416     @Mock
417     private AudioManager mAudioManager;
418     @Mock
419     private LauncherApps mLauncherApps;
420     @Mock
421     private ShortcutServiceInternal mShortcutServiceInternal;
422     @Mock
423     private UserManager mUserManager;
424     @Mock
425     ActivityManager mActivityManager;
426     @Mock
427     TelecomManager mTelecomManager;
428     @Mock
429     Resources mResources;
430     @Mock
431     RankingHandler mRankingHandler;
432     @Mock
433     ActivityManagerInternal mAmi;
434     @Mock
435     JobSchedulerInternal mJsi;
436     @Mock
437     private Looper mMainLooper;
438     @Mock
439     private NotificationManager mMockNm;
440     @Mock
441     private PermissionManager mPermissionManager;
442     @Mock
443     private DevicePolicyManagerInternal mDevicePolicyManager;
444     @Mock
445     private PowerManager mPowerManager;
446     @Mock
447     private LightsManager mLightsManager;
448     private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>();
449     private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory =
450             new TestPostNotificationTrackerFactory();
451 
452     private PendingIntent mActivityIntent;
453     private PendingIntent mActivityIntentImmutable;
454 
455     private static final int MAX_POST_DELAY = 1000;
456 
457     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
458             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
459 
460     NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW);
461 
462     private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
463 
464     private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
465     private static final String SEARCH_SELECTOR_PKG = "searchSelector";
466     private static final String ADSERVICES_MODULE_PKG = "com.android.adservices";
467     private static final String ADSERVICES_APK_PKG = "com.android.adservices.api";
468 
469     @Mock
470     private NotificationListeners mListeners;
471     @Mock
472     private NotificationListenerFilter mNlf;
473     @Mock private NotificationAssistants mAssistants;
474     @Mock private ConditionProviders mConditionProviders;
475     private ManagedServices.ManagedServiceInfo mListener;
476     @Mock private ICompanionDeviceManager mCompanionMgr;
477     @Mock SnoozeHelper mSnoozeHelper;
478     @Mock GroupHelper mGroupHelper;
479     @Mock
480     IBinder mPermOwner;
481     @Mock
482     IActivityManager mAm;
483     @Mock
484     ActivityTaskManagerInternal mAtm;
485     @Mock
486     IUriGrantsManager mUgm;
487     @Mock
488     UriGrantsManagerInternal mUgmInternal;
489     @Mock
490     AppOpsManager mAppOpsManager;
491     private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener;
492     @Mock
493     private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
494             mNotificationAssistantAccessGrantedCallback;
495     @Mock
496     UserManager mUm;
497     @Mock
498     UserManagerInternal mUmInternal;
499     @Mock
500     NotificationHistoryManager mHistoryManager;
501     @Mock
502     StatsManager mStatsManager;
503     @Mock
504     AlarmManager mAlarmManager;
505     @Mock JobScheduler mJobScheduler;
506     @Mock
507     MultiRateLimiter mToastRateLimiter;
508     BroadcastReceiver mPackageIntentReceiver;
509     BroadcastReceiver mUserIntentReceiver;
510     BroadcastReceiver mNotificationTimeoutReceiver;
511     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
512     TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
513 
514     TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
515     @Rule
516     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
517     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
518             1 << 30);
519     @Mock
520     StatusBarManagerInternal mStatusBar;
521 
522     @Mock
523     NotificationAttentionHelper mAttentionHelper;
524 
525     private NotificationManagerService.WorkerHandler mWorkerHandler;
526 
527     private class TestableToastCallback extends ITransientNotification.Stub {
528         @Override
show(IBinder windowToken)529         public void show(IBinder windowToken) {
530         }
531 
532         @Override
hide()533         public void hide() {
534         }
535     }
536 
537     private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory {
538 
539         private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>();
540 
541         @Override
newTracker(@ullable WakeLock optionalWakeLock)542         public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) {
543             PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker(
544                     optionalWakeLock);
545             mCreatedTrackers.add(tracker);
546             return tracker;
547         }
548     }
549 
550     @Parameters(name = "{0}")
getParams()551     public static List<FlagsParameterization> getParams() {
552         return FlagsParameterization.allCombinationsOf(
553                 FLAG_ALL_NOTIFS_NEED_TTL);
554     }
555 
NotificationManagerServiceTest(FlagsParameterization flags)556     public NotificationManagerServiceTest(FlagsParameterization flags) {
557         mSetFlagsRule.setFlagsParameterization(flags);
558     }
559 
560     @Before
setUp()561     public void setUp() throws Exception {
562         // Shell permisssions will override permissions of our app, so add all necessary permissions
563         // for this test here:
564         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
565                 "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG",
566                 "android.permission.READ_DEVICE_CONFIG",
567                 "android.permission.READ_CONTACTS");
568 
569         MockitoAnnotations.initMocks(this);
570 
571         DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
572         when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
573 
574         LocalServices.removeServiceForTest(UserManagerInternal.class);
575         LocalServices.addService(UserManagerInternal.class, mUmInternal);
576         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
577         LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
578         LocalServices.removeServiceForTest(WindowManagerInternal.class);
579         LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
580         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
581         LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
582         LocalServices.removeServiceForTest(DeviceIdleInternal.class);
583         LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
584         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
585         LocalServices.addService(ActivityManagerInternal.class, mAmi);
586         LocalServices.removeServiceForTest(JobSchedulerInternal.class);
587         LocalServices.addService(JobSchedulerInternal.class, mJsi);
588         LocalServices.removeServiceForTest(PackageManagerInternal.class);
589         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
590         LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
591         LocalServices.addService(PermissionPolicyInternal.class, mPermissionPolicyInternal);
592         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
593         LocalServices.addService(ShortcutServiceInternal.class, mShortcutServiceInternal);
594         mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
595         mContext.addMockSystemService(NotificationManager.class, mMockNm);
596         mContext.addMockSystemService(RoleManager.class, mock(RoleManager.class));
597         mContext.addMockSystemService(Context.LAUNCHER_APPS_SERVICE, mLauncherApps);
598         mContext.addMockSystemService(Context.USER_SERVICE, mUm);
599         mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE,
600                 mock(AccessibilityManager.class));
601 
602         doNothing().when(mContext).sendBroadcast(any(), anyString());
603         doNothing().when(mContext).sendBroadcastAsUser(any(), any());
604         doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
605         TestableContentResolver cr = mock(TestableContentResolver.class);
606         when(mContext.getContentResolver()).thenReturn(cr);
607         doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt());
608 
609         when(mAppOpsManager.checkOpNoThrow(
610                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
611                 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED);
612 
613         // Use this testable looper.
614         mTestableLooper = TestableLooper.get(this);
615         // MockPackageManager - default returns ApplicationInfo with matching calling UID
616         mContext.setMockPackageManager(mPackageManagerClient);
617 
618         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
619                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
620                     Object[] args = invocation.getArguments();
621                     return getApplicationInfo((String) args[0], mUid);
622                 });
623         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
624                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
625                     Object[] args = invocation.getArguments();
626                     return getApplicationInfo((String) args[0], mUid);
627                 });
628         when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
629         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer(
630                 (Answer<Boolean>) invocation -> {
631                     // TODO: b/317957802 - This is overly broad and basically makes ANY
632                     //  isSameApp() check pass,  requiring Mockito.reset() for meaningful
633                     //  tests! Make it more precise.
634                     Object[] args = invocation.getArguments();
635                     return (int) args[1] == mUid;
636                 });
637         when(mLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
638         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
639         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
640         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
641         when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{mPkg});
642         when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{mPkg});
643         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt()))
644                 .thenReturn(INVALID_TASK_ID);
645         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
646         when(mUm.getProfileIds(eq(mUserId), eq(false))).thenReturn(new int[] { mUserId });
647         when(mAmi.getCurrentUserId()).thenReturn(mUserId);
648 
649         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true);
650 
651         ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
652         List<ActivityManager.AppTask> taskList = new ArrayList<>();
653         ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo();
654         taskInfo.taskId = TEST_TASK_ID;
655         when(task.getTaskInfo()).thenReturn(taskInfo);
656         taskList.add(task);
657         when(mAtm.getAppTasks(anyString(), anyInt())).thenReturn(taskList);
658 
659         // write to a test file; the system file isn't readable from tests
660         mFile = new File(mContext.getCacheDir(), "test.xml");
661         mFile.createNewFile();
662         final String preupgradeXml = "<notification-policy></notification-policy>";
663         mPolicyFile = new AtomicFile(mFile);
664         FileOutputStream fos = mPolicyFile.startWrite();
665         fos.write(preupgradeXml.getBytes());
666         mPolicyFile.finishWrite(fos);
667 
668         // Setup managed services
669         when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
670         when(mNlf.isPackageAllowed(any())).thenReturn(true);
671         when(mNlf.isPackageAllowed(null)).thenReturn(true);
672         when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
673         mListener = mListeners.new ManagedServiceInfo(
674                 null, new ComponentName(mPkg, "test_class"),
675                 mUserId, true, null, 0, 123);
676         ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
677         ArraySet<ComponentName> components = new ArraySet<>();
678         components.add(defaultComponent);
679         when(mListeners.getDefaultComponents()).thenReturn(components);
680         when(mConditionProviders.getDefaultPackages())
681                 .thenReturn(new ArraySet<>(Arrays.asList("config")));
682         when(mAssistants.getDefaultComponents()).thenReturn(components);
683         when(mAssistants.queryPackageForServices(
684                 anyString(), anyInt(), anyInt())).thenReturn(components);
685         when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
686         ManagedServices.Config listenerConfig = new ManagedServices.Config();
687         listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
688         when(mListeners.getConfig()).thenReturn(listenerConfig);
689         ManagedServices.Config assistantConfig = new ManagedServices.Config();
690         assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS;
691         when(mAssistants.getConfig()).thenReturn(assistantConfig);
692         ManagedServices.Config dndConfig = new ManagedServices.Config();
693         dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS;
694         when(mConditionProviders.getConfig()).thenReturn(dndConfig);
695 
696         when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
697 
698         // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks.
699         // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks,
700         // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't
701         // call release twice, etc) and we want the test to fail if such misuse happens, too.
702         PowerManager realPowerManager = mContext.getSystemService(PowerManager.class);
703         when(mPowerManager.newWakeLock(anyInt(), anyString())).then(
704                 (Answer<WakeLock>) invocation -> {
705                     WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0),
706                             invocation.getArgument(1));
707                     mAcquiredWakeLocks.add(wl);
708                     return wl;
709                 });
710 
711         // TODO (b/291907312): remove feature flag
712         // NOTE: Prefer using the @EnableFlags annotation where possible. Do not add any android.app
713         //  flags here.
714         mSetFlagsRule.disableFlags(
715                 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE);
716 
717         mActivityIntent = spy(PendingIntent.getActivity(mContext, 0,
718                 new Intent().setPackage(mPkg), PendingIntent.FLAG_MUTABLE));
719         mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0,
720                 new Intent().setPackage(mPkg), FLAG_IMMUTABLE));
721 
722         initNMS();
723     }
724 
initNMS()725     private void initNMS() throws Exception {
726         initNMS(SystemService.PHASE_BOOT_COMPLETED);
727     }
728 
initNMS(int upToBootPhase)729     private void initNMS(int upToBootPhase) throws Exception {
730         mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
731                 mNotificationInstanceIdSequence);
732 
733         // apps allowed as convos
734         mService.setStringArrayResourceValue(PKG_O);
735 
736         TestableResources tr = mContext.getOrCreateTestableResources();
737         tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName,
738                 SEARCH_SELECTOR_PKG);
739 
740         doAnswer(invocation -> {
741             mOnPermissionChangeListener = invocation.getArgument(2);
742             return null;
743         }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(),
744                 any());
745         when(mUmInternal.isUserInitialized(anyInt())).thenReturn(true);
746 
747         mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
748         mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
749                 mLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
750                 mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
751                 mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal,
752                 mAppOpsManager, mUm, mHistoryManager, mStatsManager,
753                 mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
754                 mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
755                 mPowerManager, mPostNotificationTrackerFactory);
756 
757         mService.setAttentionHelper(mAttentionHelper);
758         mService.setLockPatternUtils(mock(LockPatternUtils.class));
759 
760         // Return first true for RoleObserver main-thread check
761         when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
762         ModuleInfo moduleInfo = new ModuleInfo();
763         moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG);
764         moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG));
765         when(mPackageManagerClient.getInstalledModules(anyInt()))
766                 .thenReturn(List.of(moduleInfo));
767         if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) {
768             mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
769         }
770 
771         Mockito.reset(mHistoryManager);
772         verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
773 
774         if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
775             mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
776             verify(mHistoryManager).onBootPhaseAppsCanStart();
777         }
778 
779         mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
780         mService.setStrongAuthTracker(mStrongAuthTracker);
781 
782         mShortcutHelper = mService.getShortcutHelper();
783         mShortcutHelper.setLauncherApps(mLauncherApps);
784         mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
785         mShortcutHelper.setUserManager(mUserManager);
786 
787         // Capture PackageIntentReceiver
788         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
789                 ArgumentCaptor.forClass(BroadcastReceiver.class);
790         ArgumentCaptor<IntentFilter> intentFilterCaptor =
791                 ArgumentCaptor.forClass(IntentFilter.class);
792 
793         verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
794                 any(), intentFilterCaptor.capture(), any(), any());
795         verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
796                 intentFilterCaptor.capture(), anyInt());
797         verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
798                 intentFilterCaptor.capture());
799         List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
800         List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues();
801 
802         for (int i = 0; i < intentFilters.size(); i++) {
803             final IntentFilter filter = intentFilters.get(i);
804             if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)
805                     && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED)
806                     && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
807                 mPackageIntentReceiver = broadcastReceivers.get(i);
808             }
809             if (filter.hasAction(Intent.ACTION_USER_SWITCHED)
810                     || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)
811                     || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
812                 // There may be multiple receivers, get the NMS one
813                 if (broadcastReceivers.get(i).toString().contains(
814                         NotificationManagerService.class.getName())) {
815                     mUserIntentReceiver = broadcastReceivers.get(i);
816                 }
817             }
818             if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT)
819                     && filter.hasDataScheme(SCHEME_TIMEOUT)) {
820                 mNotificationTimeoutReceiver = broadcastReceivers.get(i);
821             }
822         }
823         assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
824         assertNotNull("User receiver should exist", mUserIntentReceiver);
825         if (!Flags.allNotifsNeedTtl()) {
826             assertNotNull("Notification timeout receiver should exist",
827                     mNotificationTimeoutReceiver);
828         }
829 
830         // Pretend the shortcut exists
831         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
832         ShortcutInfo info = mock(ShortcutInfo.class);
833         when(info.getPackage()).thenReturn(mPkg);
834         when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
835         when(info.getUserId()).thenReturn(USER_SYSTEM);
836         when(info.isLongLived()).thenReturn(true);
837         when(info.isEnabled()).thenReturn(true);
838         shortcutInfos.add(info);
839         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
840         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
841                 anyString(), anyInt(), any())).thenReturn(true);
842         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
843         mockIsUserVisible(DEFAULT_DISPLAY, true);
844         mockIsVisibleBackgroundUsersSupported(false);
845 
846         // Set the testable bubble extractor
847         RankingHelper rankingHelper = mService.getRankingHelper();
848         BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
849         extractor.setActivityManager(mActivityManager);
850 
851         // Tests call directly into the Binder.
852         mBinderService = mService.getBinderService();
853         mInternalService = mService.getInternalService();
854 
855         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(
856                 Arrays.asList(mTestNotificationChannel, mSilentChannel)));
857         mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice(
858                 Arrays.asList(mTestNotificationChannel, mSilentChannel)));
859         mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
860                 Arrays.asList(mTestNotificationChannel, mSilentChannel)));
861         assertNotNull(mBinderService.getNotificationChannel(
862                 mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID));
863         assertNotNull(mBinderService.getNotificationChannel(
864                 mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId()));
865         clearInvocations(mRankingHandler);
866         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
867 
868         var checker = mock(TestableNotificationManagerService.ComponentPermissionChecker.class);
869         mService.permissionChecker = checker;
870         when(checker.check(anyString(), anyInt(), anyInt(), anyBoolean()))
871                 .thenReturn(PackageManager.PERMISSION_DENIED);
872     }
873 
874     @After
assertNotificationRecordLoggerCallsValid()875     public void assertNotificationRecordLoggerCallsValid() {
876         waitForIdle(); // Finish async work, including all logging calls done by Runnables.
877         for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) {
878             if (call.wasLogged) {
879                 assertNotNull(call.event);
880                 if (call.event == NOTIFICATION_POSTED || call.event == NOTIFICATION_UPDATED) {
881                     assertThat(call.postDurationMillisLogged).isGreaterThan(0);
882                 } else {
883                     assertThat(call.postDurationMillisLogged).isNull();
884                 }
885             }
886         }
887         assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty();
888     }
889 
890     @After
assertAllTrackersFinishedOrCancelled()891     public void assertAllTrackersFinishedOrCancelled() {
892         waitForIdle(); // Finish async work.
893         // Verify that no trackers were left dangling.
894         for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) {
895             assertThat(tracker.isOngoing()).isFalse();
896         }
897         mPostNotificationTrackerFactory.mCreatedTrackers.clear();
898     }
899 
900     @After
assertAllWakeLocksReleased()901     public void assertAllWakeLocksReleased() {
902         waitForIdle(); // Finish async work.
903         for (WakeLock wakeLock : mAcquiredWakeLocks) {
904             assertThat(wakeLock.isHeld()).isFalse();
905         }
906     }
907 
908     @After
tearDown()909     public void tearDown() throws Exception {
910         if (mFile != null) mFile.delete();
911 
912         if (mActivityIntent != null) {
913             mActivityIntent.cancel();
914         }
915 
916         mService.clearNotifications();
917         if (mTestableLooper != null) {
918             mTestableLooper.processAllMessages();
919         }
920 
921         try {
922             mService.onDestroy();
923         } catch (IllegalStateException | IllegalArgumentException e) {
924             Log.e(TAG, "failed to destroy", e);
925             // can throw if a broadcast receiver was never registered
926         }
927 
928         InstrumentationRegistry.getInstrumentation()
929                 .getUiAutomation().dropShellPermissionIdentity();
930         if (mWorkerHandler != null) {
931             // Remove scheduled messages that would be processed when the test is already done, and
932             // could cause issues, for example, messages that remove/cancel shown toasts (this causes
933             // problematic interactions with mocks when they're no longer working as expected).
934             mWorkerHandler.removeCallbacksAndMessages(null);
935         }
936 
937         if (mTestableLooper != null) {
938             // Must remove static reference to this test object to prevent leak (b/261039202)
939             mTestableLooper.remove(this);
940         }
941     }
942 
simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid)943     private void simulatePackageSuspendBroadcast(boolean suspend, String pkg,
944             int uid) {
945         // mimics receive broadcast that package is (un)suspended
946         // but does not actually (un)suspend the package
947         final Bundle extras = new Bundle();
948         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
949                 new String[]{pkg});
950         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid});
951 
952         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
953                 : Intent.ACTION_PACKAGES_UNSUSPENDED;
954         final Intent intent = new Intent(action);
955         intent.putExtras(extras);
956 
957         mPackageIntentReceiver.onReceive(getContext(), intent);
958     }
959 
simulatePackageRemovedBroadcast(String pkg, int uid)960     private void simulatePackageRemovedBroadcast(String pkg, int uid) {
961         // mimics receive broadcast that package is removed, but doesn't remove the package.
962         final Bundle extras = new Bundle();
963         extras.putInt(Intent.EXTRA_UID, uid);
964 
965         final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
966         intent.setData(Uri.parse("package:" + pkg));
967         intent.putExtras(extras);
968 
969         mPackageIntentReceiver.onReceive(getContext(), intent);
970     }
971 
simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids)972     private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) {
973         // mimics receive broadcast that package is (un)distracting
974         // but does not actually register that info with packagemanager
975         final Bundle extras = new Bundle();
976         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
977         extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
978         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids);
979 
980         final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
981         intent.putExtras(extras);
982 
983         mPackageIntentReceiver.onReceive(getContext(), intent);
984     }
985 
simulateProfileAvailabilityActions(String intentAction)986     private void simulateProfileAvailabilityActions(String intentAction) {
987         final Intent intent = new Intent(intentAction);
988         intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
989         mUserIntentReceiver.onReceive(mContext, intent);
990     }
991 
generateResetComponentValues()992     private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() {
993         ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>();
994         changed.put(true, new ArrayList<>());
995         changed.put(false, new ArrayList<>());
996         return changed;
997     }
getApplicationInfo(String pkg, int uid)998     private ApplicationInfo getApplicationInfo(String pkg, int uid) {
999         final ApplicationInfo applicationInfo = new ApplicationInfo();
1000         applicationInfo.packageName = pkg;
1001         applicationInfo.uid = uid;
1002         applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir;
1003         switch (pkg) {
1004             case PKG_N_MR1:
1005                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
1006                 break;
1007             case PKG_O:
1008                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
1009                 break;
1010             case PKG_P:
1011                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
1012                 break;
1013             default:
1014                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
1015                 break;
1016         }
1017         return applicationInfo;
1018     }
1019 
waitForIdle()1020     public void waitForIdle() {
1021         if (mTestableLooper != null) {
1022             mTestableLooper.processAllMessages();
1023         }
1024     }
1025 
setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, int pkgPref, boolean channelEnabled)1026     private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled,
1027             int pkgPref, boolean channelEnabled) {
1028         Settings.Secure.putInt(mContext.getContentResolver(),
1029                 Settings.Secure.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0);
1030         mService.mPreferencesHelper.updateBubblesEnabled();
1031         assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled(
1032                 mock(UserHandle.class)));
1033         try {
1034             mBinderService.setBubblesAllowed(pkg, uid, pkgPref);
1035         } catch (RemoteException e) {
1036             e.printStackTrace();
1037         }
1038         mTestNotificationChannel.setAllowBubbles(channelEnabled);
1039     }
1040 
setUpPrefsForHistory(@serIdInt int userId, boolean globalEnabled)1041     private void setUpPrefsForHistory(@UserIdInt int userId, boolean globalEnabled)
1042             throws Exception {
1043         initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY);
1044 
1045         // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
1046         Settings.Secure.putIntForUser(mContext.getContentResolver(),
1047                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, userId);
1048         // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0
1049         Settings.Secure.putInt(mContext.getContentResolver(),
1050                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0);
1051         setUsers(new int[] {0, userId});
1052 
1053         // Forces an update by calling observe on mSettingsObserver, which picks up the settings
1054         // changes above.
1055         mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
1056 
1057         assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(),
1058                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, userId) != 0);
1059     }
1060 
generateSbn(String pkg, int uid, long postTime, int userId)1061     private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) {
1062         Notification.Builder nb = new Notification.Builder(mContext, "a")
1063                 .setContentTitle("foo")
1064                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1065         StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid,
1066                 "tag" + System.currentTimeMillis(), uid, 0,
1067                 nb.build(), new UserHandle(userId), null, postTime);
1068         return sbn;
1069     }
1070 
generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary)1071     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1072             String groupKey, boolean isSummary) {
1073         return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey,
1074                 isSummary);
1075     }
1076 
generateNotificationRecord(NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary)1077     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1078             String tag, String groupKey, boolean isSummary) {
1079         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1080                 .setContentTitle("foo")
1081                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1082                 .setGroup(groupKey)
1083                 .setGroupSummary(isSummary);
1084         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id,
1085                 tag, mUid, 0,
1086                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1087         return new NotificationRecord(mContext, sbn, channel);
1088     }
1089 
generateNotificationRecord(NotificationChannel channel)1090     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
1091         return generateNotificationRecord(channel, null);
1092     }
1093 
generateNotificationRecord(NotificationChannel channel, Notification.TvExtender extender)1094     private NotificationRecord generateNotificationRecord(NotificationChannel channel,
1095             Notification.TvExtender extender) {
1096         if (channel == null) {
1097             channel = mTestNotificationChannel;
1098         }
1099         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1100                 .setContentTitle("foo")
1101                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1102                 .addAction(new Notification.Action.Builder(null, "test", mActivityIntent).build())
1103                 .addAction(new Notification.Action.Builder(
1104                         null, "test", mActivityIntentImmutable).build());
1105         if (extender != null) {
1106             nb.extend(extender);
1107         }
1108         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
1109                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1110         return new NotificationRecord(mContext, sbn, channel);
1111     }
1112 
generateNotificationRecord(NotificationChannel channel, long postTime)1113     private NotificationRecord generateNotificationRecord(NotificationChannel channel,
1114             long postTime) {
1115         final StatusBarNotification sbn = generateSbn(mPkg, mUid, postTime, mUserId);
1116         return new NotificationRecord(mContext, sbn, channel);
1117     }
1118 
generateNotificationRecord(NotificationChannel channel, int userId)1119     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) {
1120         return generateNotificationRecord(channel, 1, userId);
1121     }
1122 
generateNotificationRecord(NotificationChannel channel, int id, int userId)1123     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1124             int userId) {
1125         return generateNotificationRecord(channel, id, userId, "foo");
1126     }
1127 
generateNotificationRecord(NotificationChannel channel, int id, int userId, String title)1128     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1129             int userId, String title) {
1130         if (channel == null) {
1131             channel = mTestNotificationChannel;
1132         }
1133         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1134                 .setContentTitle(title)
1135                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1136         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0,
1137                 nb.build(), new UserHandle(userId), null, 0);
1138         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
1139         return r;
1140     }
1141 
generateMessageBubbleNotifRecord(NotificationChannel channel, String tag)1142     private NotificationRecord generateMessageBubbleNotifRecord(NotificationChannel channel,
1143             String tag) {
1144         return generateMessageBubbleNotifRecord(true, channel, 1, tag, null, false, true);
1145     }
1146 
generateMessageBubbleNotifRecord(boolean addMetadata, NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, boolean mutable)1147     private NotificationRecord generateMessageBubbleNotifRecord(boolean addMetadata,
1148             NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary,
1149             boolean mutable) {
1150         if (channel == null) {
1151             channel = mTestNotificationChannel;
1152         }
1153         if (tag == null) {
1154             tag = "tag";
1155         }
1156         Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey,
1157                 isSummary, mutable);
1158         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id,
1159                 tag, mUid, 0,
1160                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1161         return new NotificationRecord(mContext, sbn, channel);
1162     }
1163 
generateRedactedSbn(NotificationChannel channel, int id, int userId)1164     private StatusBarNotification generateRedactedSbn(NotificationChannel channel, int id,
1165             int userId) {
1166         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1167                 .setContentTitle("foo")
1168                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1169                 .setContentText(REDACTED_TEXT);
1170         return new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0,
1171                 nb.build(), new UserHandle(userId), null, 0);
1172     }
1173 
getSignalExtractorSideEffects()1174     private Map<String, Answer> getSignalExtractorSideEffects() {
1175         Map<String, Answer> answers = new ArrayMap<>();
1176 
1177         answers.put("override group key", invocationOnMock -> {
1178             ((NotificationRecord) invocationOnMock.getArguments()[0])
1179                     .setOverrideGroupKey("bananas");
1180             return null;
1181         });
1182         answers.put("override people", invocationOnMock -> {
1183             ((NotificationRecord) invocationOnMock.getArguments()[0])
1184                     .setPeopleOverride(new ArrayList<>());
1185             return null;
1186         });
1187         answers.put("snooze criteria", invocationOnMock -> {
1188             ((NotificationRecord) invocationOnMock.getArguments()[0])
1189                     .setSnoozeCriteria(new ArrayList<>());
1190             return null;
1191         });
1192         answers.put("notification channel", invocationOnMock -> {
1193             ((NotificationRecord) invocationOnMock.getArguments()[0])
1194                     .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW));
1195             return null;
1196         });
1197         answers.put("badging", invocationOnMock -> {
1198             NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
1199             r.setShowBadge(!r.canShowBadge());
1200             return null;
1201         });
1202         answers.put("bubbles", invocationOnMock -> {
1203             NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
1204             r.setAllowBubble(!r.canBubble());
1205             return null;
1206         });
1207         answers.put("package visibility", invocationOnMock -> {
1208             ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride(
1209                     Notification.VISIBILITY_SECRET);
1210             return null;
1211         });
1212 
1213         return answers;
1214     }
1215 
getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary, boolean mutable)1216     private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata,
1217             String groupKey, boolean isSummary, boolean mutable) {
1218         // Give it a person
1219         Person person = new Person.Builder()
1220                 .setName("bubblebot")
1221                 .build();
1222         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
1223         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
1224         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
1225                 mutable ? mActivityIntent : mActivityIntentImmutable).addRemoteInput(remoteInput)
1226                 .build();
1227         // Make it messaging style
1228         Notification.Builder nb = new Notification.Builder(mContext,
1229                 mTestNotificationChannel.getId())
1230                 .setContentTitle("foo")
1231                 .setStyle(new Notification.MessagingStyle(person)
1232                         .setConversationTitle("Bubble Chat")
1233                         .addMessage("Hello?",
1234                                 SystemClock.currentThreadTimeMillis() - 300000, person)
1235                         .addMessage("Is it me you're looking for?",
1236                                 SystemClock.currentThreadTimeMillis(), person)
1237                 )
1238                 .setActions(replyAction)
1239                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1240                 .setShortcutId(VALID_CONVO_SHORTCUT_ID)
1241                 .setGroupSummary(isSummary);
1242         if (groupKey != null) {
1243             nb.setGroup(groupKey);
1244         }
1245         if (addBubbleMetadata) {
1246             nb.setBubbleMetadata(getBubbleMetadata());
1247         }
1248         return nb;
1249     }
1250 
getBubbleMetadata()1251     private Notification.BubbleMetadata getBubbleMetadata() {
1252         ActivityInfo info = new ActivityInfo();
1253         info.resizeMode = RESIZE_MODE_RESIZEABLE;
1254         ResolveInfo ri = new ResolveInfo();
1255         ri.activityInfo = info;
1256         when(mPackageManagerClient.resolveActivity(any(), anyInt())).thenReturn(ri);
1257 
1258         return new Notification.BubbleMetadata.Builder(
1259                 mActivityIntent,
1260                 Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon))
1261                 .build();
1262     }
1263 
addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)1264     private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)
1265             throws RemoteException {
1266 
1267         String groupKey = "BUBBLE_GROUP";
1268 
1269         // Notification that has bubble metadata
1270         NotificationRecord nrBubble = generateMessageBubbleNotifRecord(true /* addMetadata */,
1271                 mTestNotificationChannel, 1 /* id */, "tag", groupKey, false /* isSummary */,
1272                 true);
1273 
1274         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrBubble.getSbn().getTag(),
1275                 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(),
1276                 nrBubble.getSbn().getUserId());
1277         waitForIdle();
1278 
1279         // Make sure we are a bubble
1280         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
1281         assertEquals(1, notifsAfter.length);
1282         assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
1283 
1284         // Notification without bubble metadata
1285         NotificationRecord nrPlain = generateMessageBubbleNotifRecord(false /* addMetadata */,
1286                 mTestNotificationChannel, 2 /* id */, "tag", groupKey, false /* isSummary */,
1287                 true);
1288 
1289         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrPlain.getSbn().getTag(),
1290                 nrPlain.getSbn().getId(), nrPlain.getSbn().getNotification(),
1291                 nrPlain.getSbn().getUserId());
1292         waitForIdle();
1293 
1294         notifsAfter = mBinderService.getActiveNotifications(mPkg);
1295         assertEquals(2, notifsAfter.length);
1296 
1297         // Summary notification for both of those
1298         NotificationRecord nrSummary = generateMessageBubbleNotifRecord(false /* addMetadata */,
1299                 mTestNotificationChannel, 3 /* id */, "tag", groupKey, true /* isSummary */,
1300                 true);
1301 
1302         if (summaryAutoCancel) {
1303             nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL;
1304         }
1305         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrSummary.getSbn().getTag(),
1306                 nrSummary.getSbn().getId(), nrSummary.getSbn().getNotification(),
1307                 nrSummary.getSbn().getUserId());
1308         waitForIdle();
1309 
1310         notifsAfter = mBinderService.getActiveNotifications(mPkg);
1311         assertEquals(3, notifsAfter.length);
1312 
1313         return nrSummary;
1314     }
1315 
createAndPostCallStyleNotification(String packageName, UserHandle userHandle, String testName)1316     private NotificationRecord createAndPostCallStyleNotification(String packageName,
1317             UserHandle userHandle, String testName) throws Exception {
1318         Person person = new Person.Builder().setName("caller").build();
1319         Notification.Builder nb = new Notification.Builder(mContext,
1320                 mTestNotificationChannel.getId())
1321                 .setFlag(FLAG_USER_INITIATED_JOB, true)
1322                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
1323                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1324         StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1,
1325                 testName, mUid, 0, nb.build(), userHandle, null, 0);
1326         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
1327 
1328         mService.addEnqueuedNotification(r);
1329         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1330                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run();
1331         waitForIdle();
1332 
1333         return mService.findNotificationLocked(
1334                 packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId());
1335     }
1336 
createAndPostNotification(Notification.Builder nb, String testName)1337     private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
1338             throws RemoteException {
1339         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0,
1340                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1341         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
1342 
1343         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1344                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1345         waitForIdle();
1346 
1347         return mService.findNotificationLocked(
1348                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
1349     }
1350 
parcelAndUnparcel(T source, Parcelable.Creator<T> creator)1351     private static <T extends Parcelable> T parcelAndUnparcel(T source,
1352             Parcelable.Creator<T> creator) {
1353         Parcel parcel = Parcel.obtain();
1354         source.writeToParcel(parcel, 0);
1355         parcel.setDataPosition(0);
1356         return creator.createFromParcel(parcel);
1357     }
1358 
createPendingIntent(String action)1359     private PendingIntent createPendingIntent(String action) {
1360         return PendingIntent.getActivity(mContext, 0,
1361                 new Intent(action).setPackage(mContext.getPackageName()),
1362                 PendingIntent.FLAG_MUTABLE);
1363     }
1364 
allowTestPackageToToast()1365     private void allowTestPackageToToast() throws Exception {
1366         assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty();
1367         mService.isSystemUid = false;
1368         mService.isSystemAppId = false;
1369         setToastRateIsWithinQuota(true);
1370         setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false);
1371         // package is not suspended
1372         when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId))
1373                 .thenReturn(false);
1374     }
1375 
enqueueToast(String testPackage, ITransientNotification callback)1376     private boolean enqueueToast(String testPackage, ITransientNotification callback)
1377             throws RemoteException {
1378         return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(),
1379                 callback);
1380     }
1381 
enqueueToast(INotificationManager service, String testPackage, IBinder token, ITransientNotification callback)1382     private boolean enqueueToast(INotificationManager service, String testPackage,
1383             IBinder token, ITransientNotification callback) throws RemoteException {
1384         return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */
1385                 true, DEFAULT_DISPLAY);
1386     }
1387 
enqueueTextToast(String testPackage, CharSequence text)1388     private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException {
1389         return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY);
1390     }
1391 
enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, int displayId)1392     private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext,
1393             int displayId) throws RemoteException {
1394         return ((INotificationManager) mService.mService).enqueueTextToast(testPackage,
1395                 new Binder(), text, TOAST_DURATION, isUiContext, displayId,
1396                 /* textCallback= */ null);
1397     }
1398 
mockIsVisibleBackgroundUsersSupported(boolean supported)1399     private void mockIsVisibleBackgroundUsersSupported(boolean supported) {
1400         when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported);
1401     }
1402 
mockIsUserVisible(int displayId, boolean visible)1403     private void mockIsUserVisible(int displayId, boolean visible) {
1404         when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible);
1405     }
1406 
mockDisplayAssignedToUser(int displayId)1407     private void mockDisplayAssignedToUser(int displayId) {
1408         when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId);
1409     }
1410 
verifyToastShownForTestPackage(String text, int displayId)1411     private void verifyToastShownForTestPackage(String text, int displayId) {
1412         verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(),
1413                 eq(TOAST_DURATION), any(), eq(displayId));
1414     }
1415 
1416     @Test
1417     @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
testLimitTimeOutBroadcast()1418     public void testLimitTimeOutBroadcast() {
1419         NotificationChannel channel = new NotificationChannel("id", "name",
1420                 NotificationManager.IMPORTANCE_HIGH);
1421         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1422                 .setContentTitle("foo")
1423                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1424                 .setTimeoutAfter(1);
1425 
1426         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
1427                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1428         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
1429 
1430         mService.scheduleTimeoutLocked(r);
1431         ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
1432         verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture());
1433         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
1434                 captor.getValue().getIntent().getPackage());
1435 
1436         mService.cancelScheduledTimeoutLocked(r);
1437         verify(mAlarmManager).cancel(captor.capture());
1438         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
1439                 captor.getValue().getIntent().getPackage());
1440     }
1441 
1442     @Test
testDefaultAssistant_overrideDefault()1443     public void testDefaultAssistant_overrideDefault() {
1444         final int userId = mContext.getUserId();
1445         final String testComponent = "package/class";
1446         final List<UserInfo> userInfos = new ArrayList<>();
1447         userInfos.add(new UserInfo(userId, "", 0));
1448         final ArraySet<ComponentName> validAssistants = new ArraySet<>();
1449         validAssistants.add(ComponentName.unflattenFromString(testComponent));
1450         when(mActivityManager.isLowRamDevice()).thenReturn(false);
1451         when(mAssistants.queryPackageForServices(isNull(), anyInt(), anyInt()))
1452                 .thenReturn(validAssistants);
1453         when(mAssistants.getDefaultComponents()).thenReturn(validAssistants);
1454         when(mUm.getEnabledProfiles(anyInt())).thenReturn(userInfos);
1455 
1456         mService.setDefaultAssistantForUser(userId);
1457 
1458         verify(mAssistants).setPackageOrComponentEnabled(
1459                 eq(testComponent), eq(userId), eq(true), eq(true), eq(false));
1460     }
1461 
1462     @Test
testCreateNotificationChannels_SingleChannel()1463     public void testCreateNotificationChannels_SingleChannel() throws Exception {
1464         final NotificationChannel channel =
1465                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1466         mBinderService.createNotificationChannels(mPkg,
1467                 new ParceledListSlice(Arrays.asList(channel)));
1468         final NotificationChannel createdChannel =
1469                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1470         assertTrue(createdChannel != null);
1471     }
1472 
1473     @Test
testCreateNotificationChannels_NullChannelThrowsException()1474     public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
1475         try {
1476             mBinderService.createNotificationChannels(mPkg,
1477                     new ParceledListSlice(Arrays.asList((Object[])null)));
1478             fail("Exception should be thrown immediately.");
1479         } catch (NullPointerException e) {
1480             // pass
1481         }
1482     }
1483 
1484     @Test
testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()1485     public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()
1486             throws Exception {
1487         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1488         final NotificationChannel channel =
1489                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1490         mBinderService.createNotificationChannels(PKG_NO_CHANNELS,
1491                 new ParceledListSlice(Arrays.asList(channel)));
1492         verify(mWorkerHandler).post(eq(new NotificationManagerService
1493                 .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS,
1494                 mUserId, TEST_TASK_ID, mPermissionPolicyInternal)));
1495     }
1496 
1497     @Test
testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()1498     public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()
1499             throws Exception {
1500         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1501         assertTrue(mBinderService.getNumNotificationChannelsForPackage(mPkg, mUid, true) > 0);
1502 
1503         final NotificationChannel channel =
1504                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1505         mBinderService.createNotificationChannels(mPkg,
1506                 new ParceledListSlice(Arrays.asList(channel)));
1507         verify(mWorkerHandler, never()).post(any(
1508                 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class));
1509     }
1510 
1511     @Test
testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()1512     public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()
1513             throws Exception {
1514         reset(mPermissionPolicyInternal);
1515         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1516 
1517         final NotificationChannel channel =
1518                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1519         mBinderService.createNotificationChannels(mPkg,
1520                 new ParceledListSlice(Arrays.asList(channel)));
1521 
1522         verify(mWorkerHandler, never()).post(any(
1523                 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class));
1524     }
1525 
1526     @Test
testCreateNotificationChannels_TwoChannels()1527     public void testCreateNotificationChannels_TwoChannels() throws Exception {
1528         final NotificationChannel channel1 =
1529                 new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT);
1530         final NotificationChannel channel2 =
1531                 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
1532         mBinderService.createNotificationChannels(mPkg,
1533                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
1534         assertTrue(mBinderService.getNotificationChannel(
1535                 mPkg, mContext.getUserId(), mPkg, "id1") != null);
1536         assertTrue(mBinderService.getNotificationChannel(
1537                 mPkg, mContext.getUserId(), mPkg, "id2") != null);
1538     }
1539 
1540     @Test
testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()1541     public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
1542             throws Exception {
1543         final NotificationChannel channel =
1544                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1545         mBinderService.createNotificationChannels(mPkg,
1546                 new ParceledListSlice(Arrays.asList(channel)));
1547 
1548         // Recreating the channel doesn't throw, but ignores importance.
1549         final NotificationChannel dupeChannel =
1550                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1551         mBinderService.createNotificationChannels(mPkg,
1552                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1553         final NotificationChannel createdChannel =
1554                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1555         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
1556     }
1557 
1558     @Test
testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()1559     public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()
1560             throws Exception {
1561         final NotificationChannel channel =
1562                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1563         mBinderService.createNotificationChannels(mPkg,
1564                 new ParceledListSlice(Arrays.asList(channel)));
1565 
1566         // Recreating with a lower importance is allowed to modify the channel.
1567         final NotificationChannel dupeChannel =
1568                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
1569         mBinderService.createNotificationChannels(mPkg,
1570                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1571         final NotificationChannel createdChannel =
1572                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1573         assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
1574     }
1575 
1576     @Test
testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()1577     public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()
1578             throws Exception {
1579         final NotificationChannel channel =
1580                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1581         mBinderService.createNotificationChannels(mPkg,
1582                 new ParceledListSlice(Arrays.asList(channel)));
1583 
1584         // The user modifies importance directly, can no longer be changed by the app.
1585         final NotificationChannel updatedChannel =
1586                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1587         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, updatedChannel);
1588 
1589         // Recreating with a lower importance leaves channel unchanged.
1590         final NotificationChannel dupeChannel =
1591                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
1592         mBinderService.createNotificationChannels(mPkg,
1593                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1594         final NotificationChannel createdChannel =
1595                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1596         assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
1597     }
1598 
1599     @Test
testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()1600     public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
1601             throws Exception {
1602         final NotificationChannel channel1 =
1603                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1604         final NotificationChannel channel2 =
1605                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1606         mBinderService.createNotificationChannels(mPkg,
1607                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
1608         final NotificationChannel createdChannel =
1609                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1610         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
1611     }
1612 
1613     @Test
testBlockedNotifications_suspended()1614     public void testBlockedNotifications_suspended() throws Exception {
1615         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
1616 
1617         NotificationChannel channel = new NotificationChannel("id", "name",
1618                 IMPORTANCE_HIGH);
1619         NotificationRecord r = generateNotificationRecord(channel);
1620 
1621         // isBlocked is only used for user blocking, not app suspension
1622         assertFalse(mService.isRecordBlockedLocked(r));
1623     }
1624 
1625     @Test
testBlockedNotifications_blockedChannel()1626     public void testBlockedNotifications_blockedChannel() throws Exception {
1627         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1628 
1629         NotificationChannel channel = new NotificationChannel("id", "name",
1630                 NotificationManager.IMPORTANCE_NONE);
1631         NotificationRecord r = generateNotificationRecord(channel);
1632         assertTrue(mService.isRecordBlockedLocked(r));
1633 
1634         mBinderService.createNotificationChannels(
1635                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1636         final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1637         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1638                 "testBlockedNotifications_blockedChannel",
1639                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1640         waitForIdle();
1641         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1642     }
1643 
1644     @Test
testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()1645     public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()
1646             throws Exception {
1647         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1648         when(mAmi.applyForegroundServiceNotification(
1649                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1650 
1651         NotificationChannel channel = new NotificationChannel("blocked", "name",
1652                 NotificationManager.IMPORTANCE_NONE);
1653         mBinderService.createNotificationChannels(
1654                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1655 
1656         final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1657         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1658         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1659                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1660         waitForIdle();
1661         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1662         assertEquals(IMPORTANCE_LOW,
1663                 mService.getNotificationRecord(sbn.getKey()).getImportance());
1664         assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
1665                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1666     }
1667 
1668     @Test
testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()1669     public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()
1670             throws Exception {
1671         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1672         when(mAmi.applyForegroundServiceNotification(
1673                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1674 
1675         NotificationChannel channel =
1676                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH);
1677         mBinderService.createNotificationChannels(
1678                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1679 
1680         NotificationChannel update =
1681                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
1682         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update);
1683         waitForIdle();
1684         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1685                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1686 
1687         StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1688         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1689         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1690                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1691         waitForIdle();
1692         // The first time a foreground service notification is shown, we allow the channel
1693         // to be updated to allow it to be seen.
1694         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1695         assertEquals(IMPORTANCE_LOW,
1696                 mService.getNotificationRecord(sbn.getKey()).getImportance());
1697         assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
1698                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1699         mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId());
1700         waitForIdle();
1701 
1702         update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
1703         update.setUserVisibleTaskShown(true);
1704         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update);
1705         waitForIdle();
1706         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1707                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1708 
1709         sbn = generateNotificationRecord(channel).getSbn();
1710         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1711         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1712                 "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService",
1713                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1714         waitForIdle();
1715         // The second time it is shown, we keep the user's preference.
1716         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1717         assertNull(mService.getNotificationRecord(sbn.getKey()));
1718         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1719                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1720     }
1721 
1722     @Test
testBlockedNotifications_blockedChannelGroup()1723     public void testBlockedNotifications_blockedChannelGroup() throws Exception {
1724         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1725         mService.setPreferencesHelper(mPreferencesHelper);
1726         when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())).
1727                 thenReturn(true);
1728 
1729         NotificationChannel channel = new NotificationChannel("id", "name",
1730                 NotificationManager.IMPORTANCE_HIGH);
1731         channel.setGroup("something");
1732         NotificationRecord r = generateNotificationRecord(channel);
1733         assertTrue(mService.isRecordBlockedLocked(r));
1734     }
1735 
1736     @Test
testEnqueuedBlockedNotifications_blockedApp()1737     public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
1738         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1739         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1740 
1741         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1742         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1743                 "testEnqueuedBlockedNotifications_blockedApp",
1744                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1745         waitForIdle();
1746         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1747     }
1748 
1749     @Test
testEnqueuedBlockedNotifications_blockedAppForegroundService()1750     public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
1751         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1752         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1753         when(mAmi.applyForegroundServiceNotification(
1754                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1755 
1756         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1757         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1758         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1759                 "testEnqueuedBlockedNotifications_blockedAppForegroundService",
1760                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1761         waitForIdle();
1762         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1763         assertNull(mService.getNotificationRecord(sbn.getKey()));
1764     }
1765 
1766     /**
1767      * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive
1768      * devices can use car categories.
1769      */
1770     @Test
testEnqueuedRestrictedNotifications_hasPermission()1771     public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception {
1772         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1773                 .thenReturn(true);
1774         // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot
1775         // obtain. Mocking out enforce permission call to ensure notifications can be created when
1776         // permitted.
1777         doNothing().when(mContext).enforceCallingPermission(
1778                 eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString());
1779         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1780                 Notification.CATEGORY_CAR_WARNING,
1781                 Notification.CATEGORY_CAR_INFORMATION);
1782         int id = 0;
1783         for (String category: categories) {
1784             final StatusBarNotification sbn =
1785                     generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn();
1786             sbn.getNotification().category = category;
1787             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1788                     "testEnqueuedRestrictedNotifications_asSystem",
1789                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
1790         }
1791         waitForIdle();
1792         assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length);
1793     }
1794 
1795 
1796     /**
1797      * Confirm restricted notification categories only apply to automotive.
1798      */
1799     @Test
testEnqueuedRestrictedNotifications_notAutomotive()1800     public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception {
1801         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1802                 .thenReturn(false);
1803         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1804                 Notification.CATEGORY_CAR_WARNING,
1805                 Notification.CATEGORY_CAR_INFORMATION);
1806         int id = 0;
1807         for (String category: categories) {
1808             final StatusBarNotification sbn =
1809                     generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn();
1810             sbn.getNotification().category = category;
1811             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1812                     "testEnqueuedRestrictedNotifications_notAutomotive",
1813                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
1814         }
1815         waitForIdle();
1816         assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length);
1817     }
1818 
1819     /**
1820      * Confirm if an application tries to use the car categories on a automotive device without the
1821      * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown.
1822      */
1823     @Test
testEnqueuedRestrictedNotifications_noPermission()1824     public void testEnqueuedRestrictedNotifications_noPermission() throws Exception {
1825         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1826                 .thenReturn(true);
1827         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1828                 Notification.CATEGORY_CAR_WARNING,
1829                 Notification.CATEGORY_CAR_INFORMATION);
1830         for (String category: categories) {
1831             final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1832             sbn.getNotification().category = category;
1833             try {
1834                 mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1835                         "testEnqueuedRestrictedNotifications_badUser",
1836                         sbn.getId(), sbn.getNotification(), sbn.getUserId());
1837                 fail("Calls from non system apps should not allow use of restricted categories");
1838             } catch (SecurityException e) {
1839                 // pass
1840             }
1841         }
1842         waitForIdle();
1843         assertEquals(0, mBinderService.getActiveNotifications(mPkg).length);
1844     }
1845 
1846     @Test
testSetNotificationsEnabledForPackage_noChange()1847     public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
1848         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1849         mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
1850 
1851         verify(mPermissionHelper, never()).setNotificationPermission(
1852                 anyString(), anyInt(), anyBoolean(), anyBoolean());
1853     }
1854 
1855     @Test
testSetNotificationsEnabledForPackage()1856     public void testSetNotificationsEnabledForPackage() throws Exception {
1857         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1858         mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
1859 
1860         verify(mPermissionHelper).setNotificationPermission(
1861                 mContext.getPackageName(), mUserId, false, true);
1862 
1863         verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
1864         List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls();
1865         Assert.assertEquals(
1866                 NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
1867                 calls.get(calls.size() -1).event);
1868     }
1869 
1870     @Test
testBlockedNotifications_blockedByAssistant()1871     public void testBlockedNotifications_blockedByAssistant() throws Exception {
1872         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1873         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
1874 
1875         NotificationChannel channel = new NotificationChannel("id", "name",
1876                 NotificationManager.IMPORTANCE_HIGH);
1877         NotificationRecord r = generateNotificationRecord(channel);
1878         mService.addEnqueuedNotification(r);
1879 
1880         Bundle bundle = new Bundle();
1881         bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE);
1882         Adjustment adjustment = new Adjustment(
1883                 r.getSbn().getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier());
1884         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
1885 
1886         NotificationManagerService.PostNotificationRunnable runnable =
1887                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1888                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
1889         runnable.run();
1890         waitForIdle();
1891 
1892         verify(mUsageStats, never()).registerPostedByApp(any());
1893     }
1894 
1895     @Test
testBlockedNotifications_blockedByUser()1896     public void testBlockedNotifications_blockedByUser() throws Exception {
1897         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1898         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
1899 
1900         NotificationChannel channel = new NotificationChannel("id", "name",
1901                 NotificationManager.IMPORTANCE_HIGH);
1902         NotificationRecord r = generateNotificationRecord(channel);
1903         mService.addEnqueuedNotification(r);
1904 
1905         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
1906 
1907         NotificationManagerService.PostNotificationRunnable runnable =
1908                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1909                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
1910         runnable.run();
1911         waitForIdle();
1912 
1913         verify(mUsageStats).registerBlocked(any());
1914         verify(mUsageStats, never()).registerPostedByApp(any());
1915     }
1916 
1917     @Test
testEnqueueNotificationInternal_noChannel()1918     public void testEnqueueNotificationInternal_noChannel() throws Exception {
1919         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1920         NotificationRecord nr = generateNotificationRecord(
1921                 new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
1922 
1923         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
1924                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1925         waitForIdle();
1926 
1927         verify(mPermissionHelper).hasPermission(mUid);
1928         verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
1929 
1930         reset(mPermissionHelper);
1931         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1932 
1933         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
1934                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1935         waitForIdle();
1936 
1937         verify(mPermissionHelper).hasPermission(mUid);
1938         assertThat(mService.mChannelToastsSent).contains(mUid);
1939     }
1940 
1941     @Test
testEnqueueNotification_appBlocked()1942     public void testEnqueueNotification_appBlocked() throws Exception {
1943         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1944 
1945         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1946                 "testEnqueueNotification_appBlocked", 0,
1947                 generateNotificationRecord(null).getNotification(), mUserId);
1948         waitForIdle();
1949         verify(mWorkerHandler, never()).post(
1950                 any(NotificationManagerService.EnqueueNotificationRunnable.class));
1951     }
1952 
1953     @Test
testEnqueueNotificationWithTag_PopulatesGetActiveNotifications()1954     public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
1955         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1956                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
1957                 generateNotificationRecord(null).getNotification(), mUserId);
1958         waitForIdle();
1959         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
1960         assertEquals(1, notifs.length);
1961         assertEquals(1, mService.getNotificationRecordCount());
1962     }
1963 
1964     @Test
testEnqueueNotificationWithTag_WritesExpectedLogs()1965     public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception {
1966         final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog";
1967         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
1968                 generateNotificationRecord(null).getNotification(), mUserId);
1969         waitForIdle();
1970         assertEquals(1, mNotificationRecordLogger.numCalls());
1971 
1972         NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0);
1973         assertTrue(call.wasLogged);
1974         assertEquals(NOTIFICATION_POSTED, call.event);
1975         assertNotNull(call.r);
1976         assertNull(call.old);
1977         assertEquals(0, call.position);
1978         assertEquals(0, call.buzzBeepBlink);
1979         assertEquals(mPkg, call.r.getSbn().getPackageName());
1980         assertEquals(0, call.r.getSbn().getId());
1981         assertEquals(tag, call.r.getSbn().getTag());
1982         assertEquals(1, call.getInstanceId());  // Fake instance IDs are assigned in order
1983         assertThat(call.postDurationMillisLogged).isGreaterThan(0);
1984     }
1985 
1986     @Test
testEnqueueNotificationWithTag_LogsOnMajorUpdates()1987     public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception {
1988         final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates";
1989         Notification original = new Notification.Builder(mContext,
1990                 mTestNotificationChannel.getId())
1991                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
1992         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, original, mUserId);
1993         Notification update = new Notification.Builder(mContext,
1994                 mTestNotificationChannel.getId())
1995                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1996                 .setCategory(Notification.CATEGORY_ALARM).build();
1997         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, update, mUserId);
1998         waitForIdle();
1999         assertEquals(2, mNotificationRecordLogger.numCalls());
2000 
2001         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2002         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2003         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
2004         assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0);
2005 
2006         assertTrue(mNotificationRecordLogger.get(1).wasLogged);
2007         assertEquals(NOTIFICATION_UPDATED, mNotificationRecordLogger.event(1));
2008         // Instance ID doesn't change on update of an active notification
2009         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
2010         assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isGreaterThan(0);
2011     }
2012 
2013     @Test
testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate()2014     public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception {
2015         final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate";
2016         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2017                 generateNotificationRecord(null).getNotification(), mUserId);
2018         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2019                 generateNotificationRecord(null).getNotification(), mUserId);
2020         waitForIdle();
2021         assertEquals(2, mNotificationRecordLogger.numCalls());
2022         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2023         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2024         assertFalse(mNotificationRecordLogger.get(1).wasLogged);
2025         assertNull(mNotificationRecordLogger.event(1));
2026     }
2027 
2028     @Test
testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate()2029     public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception {
2030         final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate";
2031         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2032                 generateNotificationRecord(null).getNotification(),
2033                 mUserId);
2034         final Notification notif = generateNotificationRecord(null).getNotification();
2035         notif.extras.putString(Notification.EXTRA_TITLE, "Changed title");
2036         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notif, mUserId);
2037         waitForIdle();
2038         assertEquals(2, mNotificationRecordLogger.numCalls());
2039         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2040         assertNull(mNotificationRecordLogger.event(1));
2041     }
2042 
2043     @Test
testEnqueueNotificationWithTag_LogsAgainAfterCancel()2044     public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception {
2045         final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel";
2046         Notification notification = new Notification.Builder(mContext,
2047                 mTestNotificationChannel.getId())
2048                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
2049         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId);
2050         waitForIdle();
2051         mBinderService.cancelNotificationWithTag(mPkg, mPkg, tag, 0, mUserId);
2052         waitForIdle();
2053         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId);
2054         waitForIdle();
2055         assertEquals(3, mNotificationRecordLogger.numCalls());
2056 
2057         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2058         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2059         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
2060         assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0);
2061 
2062         assertEquals(
2063                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
2064                 mNotificationRecordLogger.event(1));
2065         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
2066         // Cancel is not post, so no logged post_duration_millis.
2067         assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isNull();
2068 
2069         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(2));
2070         assertTrue(mNotificationRecordLogger.get(2).wasLogged);
2071         // New instance ID because notification was canceled before re-post
2072         assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId());
2073         assertThat(mNotificationRecordLogger.get(2).postDurationMillisLogged).isGreaterThan(0);
2074     }
2075 
2076     @Test
testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed()2077     public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception {
2078         when(mAmi.applyForegroundServiceNotification(
2079                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
2080         mContext.getTestablePermissions().setPermission(
2081                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
2082 
2083         final String tag = "testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed";
2084 
2085         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2086                 .setContentTitle("foo")
2087                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2088                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
2089                 .build();
2090         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, tag, mUid, 0,
2091                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
2092         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag,
2093                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2094         waitForIdle();
2095 
2096         StatusBarNotification[] notifs =
2097                 mBinderService.getActiveNotifications(mPkg);
2098         assertThat(notifs[0].getNotification().flags).isEqualTo(
2099                 FLAG_FOREGROUND_SERVICE | FLAG_CAN_COLORIZE | FLAG_NO_CLEAR);
2100     }
2101 
2102     @Test
testEnqueueNotificationWithTag_nullAction_fixed()2103     public void testEnqueueNotificationWithTag_nullAction_fixed() throws Exception {
2104         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2105                 .setContentTitle("foo")
2106                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2107                 .addAction(new Notification.Action.Builder(null, "one", null).build())
2108                 .addAction(new Notification.Action.Builder(null, "two", null).build())
2109                 .addAction(new Notification.Action.Builder(null, "three", null).build())
2110                 .build();
2111         n.actions[1] = null;
2112 
2113         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
2114         waitForIdle();
2115 
2116         StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg);
2117         assertThat(posted).hasLength(1);
2118         assertThat(posted[0].getNotification().actions).hasLength(2);
2119         assertThat(posted[0].getNotification().actions[0].title.toString()).isEqualTo("one");
2120         assertThat(posted[0].getNotification().actions[1].title.toString()).isEqualTo("three");
2121     }
2122 
2123     @Test
testEnqueueNotificationWithTag_allNullActions_fixed()2124     public void testEnqueueNotificationWithTag_allNullActions_fixed() throws Exception {
2125         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2126                 .setContentTitle("foo")
2127                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2128                 .addAction(new Notification.Action.Builder(null, "one", null).build())
2129                 .addAction(new Notification.Action.Builder(null, "two", null).build())
2130                 .build();
2131         n.actions[0] = null;
2132         n.actions[1] = null;
2133 
2134         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
2135         waitForIdle();
2136 
2137         StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg);
2138         assertThat(posted).hasLength(1);
2139         assertThat(posted[0].getNotification().actions).isNull();
2140     }
2141 
2142     @Test
enqueueNotificationWithTag_usesAndFinishesTracker()2143     public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception {
2144         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2145                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2146                 generateNotificationRecord(null).getNotification(), mUserId);
2147 
2148         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2149         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue();
2150 
2151         waitForIdle();
2152 
2153         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(1);
2154         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2155         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2156     }
2157 
2158     @Test
enqueueNotificationWithTag_throws_usesAndCancelsTracker()2159     public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception {
2160         // Simulate not enqueued due to rejected inputs.
2161         assertThrows(Exception.class,
2162                 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2163                         "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2164                         /* notification= */ null, mUserId));
2165 
2166         waitForIdle();
2167 
2168         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2169         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2170         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2171     }
2172 
2173     @Test
enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker()2174     public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception {
2175         // Simulate not enqueued due to snoozing inputs.
2176         when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
2177                 .thenReturn("zzzzzzz");
2178 
2179         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2180                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2181                 generateNotificationRecord(null).getNotification(), mUserId);
2182         waitForIdle();
2183 
2184         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2185         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2186         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2187     }
2188 
2189     @Test
enqueueNotificationWithTag_notPosted_usesAndCancelsTracker()2190     public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception {
2191         // Simulate not posted due to blocked app.
2192         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
2193 
2194         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2195                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2196                 generateNotificationRecord(null).getNotification(), mUserId);
2197         waitForIdle();
2198 
2199         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2200         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2201         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2202     }
2203 
2204     @Test
enqueueNotification_acquiresAndReleasesWakeLock()2205     public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception {
2206         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2207                 "enqueueNotification_acquiresAndReleasesWakeLock", 0,
2208                 generateNotificationRecord(null).getNotification(), mUserId);
2209 
2210         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2211         assertThat(mAcquiredWakeLocks).hasSize(1);
2212         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2213 
2214         waitForIdle();
2215 
2216         assertThat(mAcquiredWakeLocks).hasSize(1);
2217         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2218     }
2219 
2220     @Test
enqueueNotification_throws_acquiresAndReleasesWakeLock()2221     public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception {
2222         // Simulate not enqueued due to rejected inputs.
2223         assertThrows(Exception.class,
2224                 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2225                         "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0,
2226                         /* notification= */ null, mUserId));
2227 
2228         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2229         assertThat(mAcquiredWakeLocks).hasSize(1);
2230         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2231     }
2232 
2233     @Test
enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock()2234     public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception {
2235         // Simulate not enqueued due to snoozing inputs.
2236         when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
2237                 .thenReturn("zzzzzzz");
2238 
2239         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2240                 "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0,
2241                 generateNotificationRecord(null).getNotification(), mUserId);
2242 
2243         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2244         assertThat(mAcquiredWakeLocks).hasSize(1);
2245         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2246 
2247         waitForIdle();
2248 
2249         assertThat(mAcquiredWakeLocks).hasSize(1);
2250         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2251     }
2252 
2253     @Test
enqueueNotification_notPosted_acquiresAndReleasesWakeLock()2254     public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception {
2255         // Simulate enqueued but not posted due to missing small icon.
2256         Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2257                 .setContentTitle("foo")
2258                 .build();
2259 
2260         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2261                 "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0,
2262                 notif, mUserId);
2263 
2264         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2265         assertThat(mAcquiredWakeLocks).hasSize(1);
2266         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2267 
2268         waitForIdle();
2269 
2270         // NLSes were not called.
2271         verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean());
2272 
2273         assertThat(mAcquiredWakeLocks).hasSize(1);
2274         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2275     }
2276 
2277     @Test
enqueueNotification_setsWakeLockWorkSource()2278     public void enqueueNotification_setsWakeLockWorkSource() throws Exception {
2279         // Use a "full" mock for the PowerManager (instead of the one that delegates to the real
2280         // service) so we can return a mocked WakeLock that we can verify() on.
2281         reset(mPowerManager);
2282         WakeLock wakeLock = mock(WakeLock.class);
2283         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock);
2284 
2285         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2286                 "enqueueNotification_setsWakeLockWorkSource", 0,
2287                 generateNotificationRecord(null).getNotification(), mUserId);
2288         waitForIdle();
2289 
2290         InOrder inOrder = inOrder(mPowerManager, wakeLock);
2291         inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2292         inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, mPkg)));
2293         inOrder.verify(wakeLock).acquire(anyLong());
2294         inOrder.verify(wakeLock).release();
2295         inOrder.verifyNoMoreInteractions();
2296     }
2297 
2298     @Test
testCancelNonexistentNotification()2299     public void testCancelNonexistentNotification() throws Exception {
2300         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2301                 "testCancelNonexistentNotification", 0, mUserId);
2302         waitForIdle();
2303         // The notification record logger doesn't even get called when a nonexistent notification
2304         // is cancelled, because that happens very frequently and is not interesting.
2305         assertEquals(0, mNotificationRecordLogger.numCalls());
2306     }
2307 
2308     @Test
testCancelNotificationImmediatelyAfterEnqueue()2309     public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
2310         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2311                 "testCancelNotificationImmediatelyAfterEnqueue", 0,
2312                 generateNotificationRecord(null).getNotification(), mUserId);
2313         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2314                 "testCancelNotificationImmediatelyAfterEnqueue", 0, mUserId);
2315         waitForIdle();
2316         StatusBarNotification[] notifs =
2317                 mBinderService.getActiveNotifications(mPkg);
2318         assertEquals(0, notifs.length);
2319         assertEquals(0, mService.getNotificationRecordCount());
2320     }
2321 
2322     @Test
testPostCancelPostNotifiesListeners()2323     public void testPostCancelPostNotifiesListeners() throws Exception {
2324         // WHEN a notification is posted
2325         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2326         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(),
2327                 sbn.getNotification(), sbn.getUserId());
2328         mTestableLooper.moveTimeForward(1);
2329         // THEN it is canceled
2330         mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId());
2331         mTestableLooper.moveTimeForward(1);
2332         // THEN it is posted again (before the cancel has a chance to finish)
2333         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(),
2334                 sbn.getNotification(), sbn.getUserId());
2335         // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected
2336         waitForIdle();
2337 
2338         // The final enqueue made it to the listener instead of being canceled
2339         StatusBarNotification[] notifs =
2340                 mBinderService.getActiveNotifications(mPkg);
2341         assertEquals(1, notifs.length);
2342         assertEquals(1, mService.getNotificationRecordCount());
2343     }
2344 
2345     @Test
testCancelNotificationWhilePostedAndEnqueued()2346     public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
2347         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2348                 "testCancelNotificationWhilePostedAndEnqueued", 0,
2349                 generateNotificationRecord(null).getNotification(), mUserId);
2350         waitForIdle();
2351         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2352                 "testCancelNotificationWhilePostedAndEnqueued", 0,
2353                 generateNotificationRecord(null).getNotification(), mUserId);
2354         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2355                 "testCancelNotificationWhilePostedAndEnqueued", 0, mUserId);
2356         waitForIdle();
2357         StatusBarNotification[] notifs =
2358                 mBinderService.getActiveNotifications(mPkg);
2359         assertEquals(0, notifs.length);
2360         assertEquals(0, mService.getNotificationRecordCount());
2361         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
2362         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
2363         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
2364     }
2365 
2366     @Test
testCancelNotificationsFromListenerImmediatelyAfterEnqueue()2367     public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
2368         NotificationRecord r = generateNotificationRecord(null);
2369         final StatusBarNotification sbn = r.getSbn();
2370         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2371                 "testCancelNotificationsFromListenerImmediatelyAfterEnqueue",
2372                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2373         mBinderService.cancelNotificationsFromListener(null, null);
2374         waitForIdle();
2375         StatusBarNotification[] notifs =
2376                 mBinderService.getActiveNotifications(sbn.getPackageName());
2377         assertEquals(0, notifs.length);
2378         assertEquals(0, mService.getNotificationRecordCount());
2379     }
2380 
2381     @Test
testCancelAllNotificationsImmediatelyAfterEnqueue()2382     public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
2383         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2384         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2385                 "testCancelAllNotificationsImmediatelyAfterEnqueue",
2386                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2387         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2388         waitForIdle();
2389         StatusBarNotification[] notifs =
2390                 mBinderService.getActiveNotifications(sbn.getPackageName());
2391         assertEquals(0, notifs.length);
2392         assertEquals(0, mService.getNotificationRecordCount());
2393     }
2394 
2395     @Test
testUserInitiatedClearAll_noLeak()2396     public void testUserInitiatedClearAll_noLeak() throws Exception {
2397         final NotificationRecord n = generateNotificationRecord(
2398                 mTestNotificationChannel, 1, "group", true);
2399 
2400         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2401                 "testUserInitiatedClearAll_noLeak",
2402                 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId());
2403         waitForIdle();
2404 
2405         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
2406                 n.getUserId());
2407         waitForIdle();
2408         StatusBarNotification[] notifs =
2409                 mBinderService.getActiveNotifications(n.getSbn().getPackageName());
2410         assertEquals(0, notifs.length);
2411         assertEquals(0, mService.getNotificationRecordCount());
2412         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
2413         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
2414         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
2415     }
2416 
2417     @Test
testCancelAllNotificationsCancelsChildren()2418     public void testCancelAllNotificationsCancelsChildren() throws Exception {
2419         final NotificationRecord parent = generateNotificationRecord(
2420                 mTestNotificationChannel, 1, "group1", true);
2421         final NotificationRecord child = generateNotificationRecord(
2422                 mTestNotificationChannel, 2, "group1", false);
2423 
2424         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2425                 "testCancelAllNotificationsCancelsChildren",
2426                 parent.getSbn().getId(), parent.getSbn().getNotification(),
2427                 parent.getSbn().getUserId());
2428         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2429                 "testCancelAllNotificationsCancelsChildren",
2430                 child.getSbn().getId(), child.getSbn().getNotification(),
2431                 child.getSbn().getUserId());
2432         waitForIdle();
2433 
2434         mBinderService.cancelAllNotifications(mPkg, parent.getSbn().getUserId());
2435         waitForIdle();
2436         assertEquals(0, mService.getNotificationRecordCount());
2437     }
2438 
2439     @Test
testCancelAllNotificationsMultipleEnqueuedDoesNotCrash()2440     public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
2441         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2442         for (int i = 0; i < 10; i++) {
2443             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2444                     "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash",
2445                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
2446         }
2447         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2448         waitForIdle();
2449 
2450         assertEquals(0, mService.getNotificationRecordCount());
2451     }
2452 
2453     @Test
testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash()2454     public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception {
2455         final NotificationRecord parent = generateNotificationRecord(
2456                 mTestNotificationChannel, 1, "group1", true);
2457         final NotificationRecord parentAsChild = generateNotificationRecord(
2458                 mTestNotificationChannel, 1, "group1", false);
2459         final NotificationRecord child = generateNotificationRecord(
2460                 mTestNotificationChannel, 2, "group1", false);
2461 
2462         // fully post parent notification
2463         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2464                 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2465                 parent.getSbn().getId(), parent.getSbn().getNotification(),
2466                 parent.getSbn().getUserId());
2467         waitForIdle();
2468 
2469         // enqueue the child several times
2470         for (int i = 0; i < 10; i++) {
2471             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2472                     "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2473                     child.getSbn().getId(), child.getSbn().getNotification(),
2474                     child.getSbn().getUserId());
2475         }
2476         // make the parent a child, which will cancel the child notification
2477         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2478                 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2479                 parentAsChild.getSbn().getId(), parentAsChild.getSbn().getNotification(),
2480                 parentAsChild.getSbn().getUserId());
2481         waitForIdle();
2482 
2483         assertEquals(0, mService.getNotificationRecordCount());
2484     }
2485 
2486     @Test
testAutobundledSummary_notificationAdded()2487     public void testAutobundledSummary_notificationAdded() {
2488         NotificationRecord summary =
2489                 generateNotificationRecord(mTestNotificationChannel, 0, "pkg", true);
2490         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2491         mService.addNotification(summary);
2492         mService.mSummaryByGroupKey.put("pkg", summary);
2493         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2494         mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
2495 
2496         mService.updateAutobundledSummaryLocked(0, "pkg",
2497                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2498                     mock(Icon.class), 0, VISIBILITY_PRIVATE), false);
2499         waitForIdle();
2500 
2501         assertTrue(summary.getSbn().isOngoing());
2502     }
2503 
2504     @Test
testAutobundledSummary_notificationRemoved()2505     public void testAutobundledSummary_notificationRemoved() {
2506         NotificationRecord summary =
2507                 generateNotificationRecord(mTestNotificationChannel, 0, "pkg", true);
2508         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2509         summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
2510         mService.addNotification(summary);
2511         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2512         mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
2513         mService.mSummaryByGroupKey.put("pkg", summary);
2514 
2515         mService.updateAutobundledSummaryLocked(0, "pkg",
2516                 new NotificationAttributes(GroupHelper.BASE_FLAGS,
2517                     mock(Icon.class), 0, VISIBILITY_PRIVATE), false);
2518         waitForIdle();
2519 
2520         assertFalse(summary.getSbn().isOngoing());
2521     }
2522 
2523     @Test
testCancelAllNotifications_IgnoreForegroundService()2524     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
2525         when(mAmi.applyForegroundServiceNotification(
2526                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
2527         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2528         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2529         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2530                 "testCancelAllNotifications_IgnoreForegroundService",
2531                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2532         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2533         waitForIdle();
2534         StatusBarNotification[] notifs =
2535                 mBinderService.getActiveNotifications(sbn.getPackageName());
2536         assertEquals(1, notifs.length);
2537         assertEquals(1, mService.getNotificationRecordCount());
2538     }
2539 
2540     @Test
testCancelAllNotifications_FgsFlag_NoFgs_Allowed()2541     public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception {
2542         when(mAmi.applyForegroundServiceNotification(
2543                 any(), anyString(), anyInt(), anyString(), anyInt()))
2544                 .thenReturn(NOT_FOREGROUND_SERVICE);
2545         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2546         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2547         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2548                 "testCancelAllNotifications_IgnoreForegroundService",
2549                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2550         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2551         waitForIdle();
2552         StatusBarNotification[] notifs =
2553                 mBinderService.getActiveNotifications(sbn.getPackageName());
2554         assertEquals(0, notifs.length);
2555     }
2556 
2557     @Test
testCancelAllNotifications_IgnoreOtherPackages()2558     public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
2559         when(mAmi.applyForegroundServiceNotification(
2560                 any(), anyString(), anyInt(), anyString(), anyInt()))
2561                 .thenReturn(SHOW_IMMEDIATELY);
2562         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2563         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2564         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2565                 "testCancelAllNotifications_IgnoreOtherPackages",
2566                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2567         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
2568         waitForIdle();
2569         StatusBarNotification[] notifs =
2570                 mBinderService.getActiveNotifications(sbn.getPackageName());
2571         assertEquals(1, notifs.length);
2572         assertEquals(1, mService.getNotificationRecordCount());
2573     }
2574 
2575     @Test
testCancelAllNotifications_NullPkgRemovesAll()2576     public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
2577         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2578         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2579                 "testCancelAllNotifications_NullPkgRemovesAll",
2580                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2581         mBinderService.cancelAllNotifications(null, sbn.getUserId());
2582         waitForIdle();
2583         StatusBarNotification[] notifs =
2584                 mBinderService.getActiveNotifications(sbn.getPackageName());
2585         assertEquals(0, notifs.length);
2586         assertEquals(0, mService.getNotificationRecordCount());
2587     }
2588 
2589     @Test
testCancelAllNotifications_NullPkgIgnoresUserAllNotifications()2590     public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
2591         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2592         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2593                 "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications",
2594                 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
2595         // Null pkg is how we signal a user switch.
2596         mBinderService.cancelAllNotifications(null, sbn.getUserId());
2597         waitForIdle();
2598         StatusBarNotification[] notifs =
2599                 mBinderService.getActiveNotifications(sbn.getPackageName());
2600         assertEquals(1, notifs.length);
2601         assertEquals(1, mService.getNotificationRecordCount());
2602     }
2603 
2604     @Test
testAppInitiatedCancelAllNotifications_CancelsNoClearFlag()2605     public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception {
2606         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2607         sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR;
2608         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2609                 "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag",
2610                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2611         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2612         waitForIdle();
2613         StatusBarNotification[] notifs =
2614                 mBinderService.getActiveNotifications(sbn.getPackageName());
2615         assertEquals(0, notifs.length);
2616     }
2617 
2618     @Test
testCancelAllNotifications_CancelsNoClearFlag()2619     public void testCancelAllNotifications_CancelsNoClearFlag() throws Exception {
2620         final NotificationRecord notif = generateNotificationRecord(
2621                 mTestNotificationChannel, 1, "group", true);
2622         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
2623         mService.addNotification(notif);
2624         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
2625                 notif.getUserId(), REASON_CANCEL);
2626         waitForIdle();
2627         StatusBarNotification[] notifs =
2628                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
2629         assertEquals(0, notifs.length);
2630     }
2631 
2632     @Test
testUserInitiatedCancelAllOnClearAll_NoClearFlag()2633     public void testUserInitiatedCancelAllOnClearAll_NoClearFlag() throws Exception {
2634         final NotificationRecord notif = generateNotificationRecord(
2635                 mTestNotificationChannel, 1, "group", true);
2636         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
2637         mService.addNotification(notif);
2638 
2639         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
2640                 notif.getUserId());
2641         waitForIdle();
2642         StatusBarNotification[] notifs =
2643                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
2644         assertEquals(1, notifs.length);
2645     }
2646 
2647     @Test
testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue()2648     public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
2649         when(mAmi.applyForegroundServiceNotification(
2650                 any(), anyString(), anyInt(), anyString(), anyInt()))
2651                 .thenReturn(SHOW_IMMEDIATELY);
2652         Notification n =
2653                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
2654                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
2655                         .build();
2656         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
2657                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
2658         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2659         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null,
2660                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2661         mInternalService.removeForegroundServiceFlagFromNotification(mPkg, sbn.getId(),
2662                 sbn.getUserId());
2663         waitForIdle();
2664         StatusBarNotification[] notifs =
2665                 mBinderService.getActiveNotifications(sbn.getPackageName());
2666         assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE);
2667     }
2668 
2669     @Test
testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag()2670     public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
2671         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2672         sbn.getNotification().flags =
2673                 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
2674         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
2675                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2676         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
2677         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
2678                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2679         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
2680                 sbn.getUserId());
2681         waitForIdle();
2682         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
2683         assertEquals(0, mService.getNotificationRecordCount());
2684     }
2685 
2686     @Test
2687     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelWithTagDoesNotCancelLifetimeExtended()2688     public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception {
2689         final NotificationRecord notif = generateNotificationRecord(null);
2690         notif.getSbn().getNotification().flags =
2691                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
2692         mService.addNotification(notif);
2693         final StatusBarNotification sbn = notif.getSbn();
2694 
2695         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
2696         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
2697 
2698         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
2699                 sbn.getUserId());
2700         waitForIdle();
2701 
2702         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
2703         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
2704 
2705         // Checks that a post update is sent.
2706         verify(mWorkerHandler, times(1))
2707                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
2708         ArgumentCaptor<NotificationRecord> captor =
2709                 ArgumentCaptor.forClass(NotificationRecord.class);
2710         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
2711                 anyBoolean());
2712         assertThat(captor.getValue().getNotification().flags
2713                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
2714                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
2715     }
2716 
2717     @Test
2718     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelAllClearsLifetimeExtended()2719     public void testCancelAllClearsLifetimeExtended() throws Exception {
2720         final NotificationRecord notif = generateNotificationRecord(
2721                 mTestNotificationChannel, 1, "group", true);
2722         notif.getNotification().flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
2723         mService.addNotification(notif);
2724         StatusBarNotification[] notifs =
2725                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
2726         assertThat(notifs.length).isEqualTo(1);
2727 
2728         // Simulate a "cancel all" received.
2729         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
2730                 notif.getUserId());
2731         waitForIdle();
2732         notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
2733         assertThat(notifs.length).isEqualTo(0);
2734 
2735         // Test that no update post is sent to System UI.
2736         verify(mWorkerHandler, never())
2737                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
2738     }
2739 
2740     @Test
2741     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testAppCancelAllDoesNotCancelLifetimeExtended()2742     public void testAppCancelAllDoesNotCancelLifetimeExtended() throws Exception {
2743         // Adds a lifetime extended notification.
2744         final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1,
2745                 null, false);
2746         notif.getSbn().getNotification().flags =
2747                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
2748         mService.addNotification(notif);
2749         // Adds a second, non-lifetime extended notification.
2750         final NotificationRecord notifCancelable = generateNotificationRecord(
2751                 mTestNotificationChannel, 2, null, false);
2752         mService.addNotification(notifCancelable);
2753         // Verify that both notifications have been posted and are active.
2754         assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(2);
2755 
2756         mBinderService.cancelAllNotifications(mPkg, notif.getSbn().getUserId());
2757         waitForIdle();
2758 
2759         // The non-lifetime extended notification, with id = 2, has been cancelled.
2760         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
2761         assertThat(notifs.length).isEqualTo(1);
2762         assertThat(notifs[0].getId()).isEqualTo(1);
2763 
2764         // Checks that a post update is sent.
2765         verify(mWorkerHandler, times(1))
2766                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
2767         ArgumentCaptor<NotificationRecord> captor =
2768                 ArgumentCaptor.forClass(NotificationRecord.class);
2769         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
2770                 anyBoolean());
2771         assertThat(captor.getValue().getNotification().flags
2772                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
2773                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
2774     }
2775 
2776     @Test
testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()2777     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()
2778             throws Exception {
2779         when(mAmi.applyForegroundServiceNotification(
2780                 any(), anyString(), anyInt(), anyString(), anyInt()))
2781                 .thenReturn(SHOW_IMMEDIATELY);
2782         mService.isSystemUid = false;
2783         mService.isSystemAppId = false;
2784         final NotificationRecord parent = generateNotificationRecord(
2785                 mTestNotificationChannel, 1, "group", true);
2786         final NotificationRecord child = generateNotificationRecord(
2787                 mTestNotificationChannel, 2, "group", false);
2788         final NotificationRecord child2 = generateNotificationRecord(
2789                 mTestNotificationChannel, 3, "group", false);
2790         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2791         mService.addNotification(parent);
2792         mService.addNotification(child);
2793         mService.addNotification(child2);
2794         mService.getBinderService().cancelNotificationWithTag(
2795                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
2796                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
2797         waitForIdle();
2798         StatusBarNotification[] notifs =
2799                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2800         assertEquals(1, notifs.length);
2801     }
2802 
2803     @Test
testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()2804     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()
2805             throws Exception {
2806         when(mAmi.applyForegroundServiceNotification(
2807                 any(), anyString(), anyInt(), anyString(), anyInt()))
2808                 .thenReturn(SHOW_IMMEDIATELY);
2809         mService.isSystemUid = false;
2810         mService.isSystemAppId = false;
2811         final NotificationRecord parent = generateNotificationRecord(
2812                 mTestNotificationChannel, 1, "group", true);
2813         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2814         final NotificationRecord child = generateNotificationRecord(
2815                 mTestNotificationChannel, 2, "group", false);
2816         final NotificationRecord child2 = generateNotificationRecord(
2817                 mTestNotificationChannel, 3, "group", false);
2818         mService.addNotification(parent);
2819         mService.addNotification(child);
2820         mService.addNotification(child2);
2821         mService.getBinderService().cancelNotificationWithTag(
2822                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
2823                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
2824         waitForIdle();
2825         StatusBarNotification[] notifs =
2826                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2827         assertEquals(3, notifs.length);
2828     }
2829 
2830     @Test
testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()2831     public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()
2832             throws Exception {
2833         mService.isSystemUid = false;
2834         mService.isSystemAppId = false;
2835         final NotificationRecord parent = generateNotificationRecord(
2836                 mTestNotificationChannel, 1, "group", true);
2837         final NotificationRecord child = generateNotificationRecord(
2838                 mTestNotificationChannel, 2, "group", false);
2839         final NotificationRecord child2 = generateNotificationRecord(
2840                 mTestNotificationChannel, 3, "group", false);
2841         child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
2842         mService.addNotification(parent);
2843         mService.addNotification(child);
2844         mService.addNotification(child2);
2845         mService.getBinderService().cancelNotificationWithTag(
2846                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
2847                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
2848         waitForIdle();
2849         StatusBarNotification[] notifs =
2850                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2851         assertEquals(0, notifs.length);
2852     }
2853 
2854     @Test
testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()2855     public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()
2856             throws Exception {
2857         mService.isSystemUid = false;
2858         mService.isSystemAppId = false;
2859         final NotificationRecord parent = generateNotificationRecord(
2860                 mTestNotificationChannel, 1, "group", true);
2861         parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
2862         final NotificationRecord child = generateNotificationRecord(
2863                 mTestNotificationChannel, 2, "group", false);
2864         final NotificationRecord child2 = generateNotificationRecord(
2865                 mTestNotificationChannel, 3, "group", false);
2866         mService.addNotification(parent);
2867         mService.addNotification(child);
2868         mService.addNotification(child2);
2869         mService.getBinderService().cancelNotificationWithTag(
2870                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
2871                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
2872         waitForIdle();
2873         StatusBarNotification[] notifs =
2874                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2875         assertEquals(0, notifs.length);
2876     }
2877 
2878     @Test
testCancelAllNotificationsFromApp_cannotCancelFgsChild()2879     public void testCancelAllNotificationsFromApp_cannotCancelFgsChild()
2880             throws Exception {
2881         when(mAmi.applyForegroundServiceNotification(
2882                 any(), anyString(), anyInt(), anyString(), anyInt()))
2883                 .thenReturn(SHOW_IMMEDIATELY);
2884         mService.isSystemUid = false;
2885         mService.isSystemAppId = false;
2886         final NotificationRecord parent = generateNotificationRecord(
2887                 mTestNotificationChannel, 1, "group", true);
2888         final NotificationRecord child = generateNotificationRecord(
2889                 mTestNotificationChannel, 2, "group", false);
2890         final NotificationRecord child2 = generateNotificationRecord(
2891                 mTestNotificationChannel, 3, "group", false);
2892         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2893         final NotificationRecord newGroup = generateNotificationRecord(
2894                 mTestNotificationChannel, 4, "group2", false);
2895         mService.addNotification(parent);
2896         mService.addNotification(child);
2897         mService.addNotification(child2);
2898         mService.addNotification(newGroup);
2899         mService.getBinderService().cancelAllNotifications(
2900                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
2901         waitForIdle();
2902         StatusBarNotification[] notifs =
2903                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2904         assertEquals(1, notifs.length);
2905     }
2906 
2907     @Test
testCancelAllNotifications_fromApp_cannotCancelFgsParent()2908     public void testCancelAllNotifications_fromApp_cannotCancelFgsParent()
2909             throws Exception {
2910         when(mAmi.applyForegroundServiceNotification(
2911                 any(), anyString(), anyInt(), anyString(), anyInt()))
2912                 .thenReturn(SHOW_IMMEDIATELY);
2913         mService.isSystemUid = false;
2914         mService.isSystemAppId = false;
2915         final NotificationRecord parent = generateNotificationRecord(
2916                 mTestNotificationChannel, 1, "group", true);
2917         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
2918         final NotificationRecord child = generateNotificationRecord(
2919                 mTestNotificationChannel, 2, "group", false);
2920         final NotificationRecord child2 = generateNotificationRecord(
2921                 mTestNotificationChannel, 3, "group", false);
2922         final NotificationRecord newGroup = generateNotificationRecord(
2923                 mTestNotificationChannel, 4, "group2", false);
2924         mService.addNotification(parent);
2925         mService.addNotification(child);
2926         mService.addNotification(child2);
2927         mService.addNotification(newGroup);
2928         mService.getBinderService().cancelAllNotifications(
2929                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
2930         waitForIdle();
2931         StatusBarNotification[] notifs =
2932                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2933         assertEquals(1, notifs.length);
2934     }
2935 
2936     @Test
testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()2937     public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()
2938             throws Exception {
2939         mService.isSystemUid = false;
2940         mService.isSystemAppId = false;
2941         final NotificationRecord parent = generateNotificationRecord(
2942                 mTestNotificationChannel, 1, "group", true);
2943         final NotificationRecord child = generateNotificationRecord(
2944                 mTestNotificationChannel, 2, "group", false);
2945         final NotificationRecord child2 = generateNotificationRecord(
2946                 mTestNotificationChannel, 3, "group", false);
2947         child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
2948         final NotificationRecord newGroup = generateNotificationRecord(
2949                 mTestNotificationChannel, 4, "group2", false);
2950         mService.addNotification(parent);
2951         mService.addNotification(child);
2952         mService.addNotification(child2);
2953         mService.addNotification(newGroup);
2954         mService.getBinderService().cancelAllNotifications(
2955                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
2956         waitForIdle();
2957         StatusBarNotification[] notifs =
2958                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2959         assertEquals(0, notifs.length);
2960     }
2961 
2962     @Test
testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()2963     public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()
2964             throws Exception {
2965         mService.isSystemUid = false;
2966         mService.isSystemAppId = false;
2967         final NotificationRecord parent = generateNotificationRecord(
2968                 mTestNotificationChannel, 1, "group", true);
2969         parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
2970         final NotificationRecord child = generateNotificationRecord(
2971                 mTestNotificationChannel, 2, "group", false);
2972         final NotificationRecord child2 = generateNotificationRecord(
2973                 mTestNotificationChannel, 3, "group", false);
2974         final NotificationRecord newGroup = generateNotificationRecord(
2975                 mTestNotificationChannel, 4, "group2", false);
2976         mService.addNotification(parent);
2977         mService.addNotification(child);
2978         mService.addNotification(child2);
2979         mService.addNotification(newGroup);
2980         mService.getBinderService().cancelAllNotifications(
2981                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
2982         waitForIdle();
2983         StatusBarNotification[] notifs =
2984                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
2985         assertEquals(0, notifs.length);
2986     }
2987 
2988     @Test
testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()2989     public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()
2990             throws Exception {
2991         final NotificationRecord parent = generateNotificationRecord(
2992                 mTestNotificationChannel, 1, "group", true);
2993         parent.getNotification().flags |= FLAG_ONGOING_EVENT;
2994         final NotificationRecord child = generateNotificationRecord(
2995                 mTestNotificationChannel, 2, "group", false);
2996         final NotificationRecord child2 = generateNotificationRecord(
2997                 mTestNotificationChannel, 3, "group", false);
2998         final NotificationRecord newGroup = generateNotificationRecord(
2999                 mTestNotificationChannel, 4, "group2", false);
3000         mService.addNotification(parent);
3001         mService.addNotification(child);
3002         mService.addNotification(child2);
3003         mService.addNotification(newGroup);
3004         mService.getBinderService().cancelNotificationsFromListener(null, null);
3005         waitForIdle();
3006         StatusBarNotification[] notifs =
3007                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3008         assertEquals(1, notifs.length);
3009     }
3010 
3011     @Test
testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()3012     public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()
3013             throws Exception {
3014         final NotificationRecord parent = generateNotificationRecord(
3015                 mTestNotificationChannel, 1, "group", true);
3016         final NotificationRecord child = generateNotificationRecord(
3017                 mTestNotificationChannel, 2, "group", false);
3018         final NotificationRecord child2 = generateNotificationRecord(
3019                 mTestNotificationChannel, 3, "group", false);
3020         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3021         final NotificationRecord newGroup = generateNotificationRecord(
3022                 mTestNotificationChannel, 4, "group2", false);
3023         mService.addNotification(parent);
3024         mService.addNotification(child);
3025         mService.addNotification(child2);
3026         mService.addNotification(newGroup);
3027         mService.getBinderService().cancelNotificationsFromListener(null, null);
3028         waitForIdle();
3029         StatusBarNotification[] notifs =
3030                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3031         assertEquals(1, notifs.length);
3032     }
3033 
3034     @Test
testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()3035     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()
3036             throws Exception {
3037         when(mAmi.applyForegroundServiceNotification(
3038                 any(), anyString(), anyInt(), anyString(), anyInt()))
3039                 .thenReturn(SHOW_IMMEDIATELY);
3040         final NotificationRecord parent = generateNotificationRecord(
3041                 mTestNotificationChannel, 1, "group", true);
3042         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3043         final NotificationRecord child = generateNotificationRecord(
3044                 mTestNotificationChannel, 2, "group", false);
3045         final NotificationRecord child2 = generateNotificationRecord(
3046                 mTestNotificationChannel, 3, "group", false);
3047         final NotificationRecord newGroup = generateNotificationRecord(
3048                 mTestNotificationChannel, 4, "group2", false);
3049         mService.addNotification(parent);
3050         mService.addNotification(child);
3051         mService.addNotification(child2);
3052         mService.addNotification(newGroup);
3053         mService.getBinderService().cancelNotificationsFromListener(null, null);
3054         waitForIdle();
3055         StatusBarNotification[] notifs =
3056                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3057         assertEquals(0, notifs.length);
3058     }
3059 
3060     @Test
testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()3061     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()
3062             throws Exception {
3063         when(mAmi.applyForegroundServiceNotification(
3064                 any(), anyString(), anyInt(), anyString(), anyInt()))
3065                 .thenReturn(SHOW_IMMEDIATELY);
3066         final NotificationRecord parent = generateNotificationRecord(
3067                 mTestNotificationChannel, 1, "group", true);
3068         final NotificationRecord child = generateNotificationRecord(
3069                 mTestNotificationChannel, 2, "group", false);
3070         final NotificationRecord child2 = generateNotificationRecord(
3071                 mTestNotificationChannel, 3, "group", false);
3072         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3073         final NotificationRecord newGroup = generateNotificationRecord(
3074                 mTestNotificationChannel, 4, "group2", false);
3075         mService.addNotification(parent);
3076         mService.addNotification(child);
3077         mService.addNotification(child2);
3078         mService.addNotification(newGroup);
3079         mService.getBinderService().cancelNotificationsFromListener(null, null);
3080         waitForIdle();
3081         StatusBarNotification[] notifs =
3082                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3083         assertEquals(0, notifs.length);
3084     }
3085 
3086     @Test
testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()3087     public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()
3088             throws Exception {
3089         final NotificationRecord parent = generateNotificationRecord(
3090                 mTestNotificationChannel, 1, "group", true);
3091         parent.getNotification().flags |= FLAG_NO_CLEAR;
3092         final NotificationRecord child = generateNotificationRecord(
3093                 mTestNotificationChannel, 2, "group", false);
3094         final NotificationRecord child2 = generateNotificationRecord(
3095                 mTestNotificationChannel, 3, "group", false);
3096         final NotificationRecord newGroup = generateNotificationRecord(
3097                 mTestNotificationChannel, 4, "group2", false);
3098         mService.addNotification(parent);
3099         mService.addNotification(child);
3100         mService.addNotification(child2);
3101         mService.addNotification(newGroup);
3102         mService.getBinderService().cancelNotificationsFromListener(null, null);
3103         waitForIdle();
3104         StatusBarNotification[] notifs =
3105                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3106         assertEquals(1, notifs.length);
3107     }
3108 
3109     @Test
testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()3110     public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()
3111             throws Exception {
3112         final NotificationRecord parent = generateNotificationRecord(
3113                 mTestNotificationChannel, 1, "group", true);
3114         final NotificationRecord child = generateNotificationRecord(
3115                 mTestNotificationChannel, 2, "group", false);
3116         final NotificationRecord child2 = generateNotificationRecord(
3117                 mTestNotificationChannel, 3, "group", false);
3118         child2.getNotification().flags |= FLAG_NO_CLEAR;
3119         final NotificationRecord newGroup = generateNotificationRecord(
3120                 mTestNotificationChannel, 4, "group2", false);
3121         mService.addNotification(parent);
3122         mService.addNotification(child);
3123         mService.addNotification(child2);
3124         mService.addNotification(newGroup);
3125         mService.getBinderService().cancelNotificationsFromListener(null, null);
3126         waitForIdle();
3127         StatusBarNotification[] notifs =
3128                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3129         assertEquals(1, notifs.length);
3130     }
3131 
3132     @Test
testCancelNotificationsFromListener_clearAll_Ongoing()3133     public void testCancelNotificationsFromListener_clearAll_Ongoing()
3134             throws Exception {
3135         final NotificationRecord child2 = generateNotificationRecord(
3136                 mTestNotificationChannel, 3, null, false);
3137         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3138         mService.addNotification(child2);
3139         String[] keys = {child2.getSbn().getKey()};
3140         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3141         waitForIdle();
3142         StatusBarNotification[] notifs =
3143                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3144         assertEquals(1, notifs.length);
3145     }
3146 
3147     @Test
testCancelNotificationsFromListener_clearAll_NoClear()3148     public void testCancelNotificationsFromListener_clearAll_NoClear()
3149             throws Exception {
3150         final NotificationRecord child2 = generateNotificationRecord(
3151                 mTestNotificationChannel, 3, null, false);
3152         child2.getNotification().flags |= FLAG_NO_CLEAR;
3153         mService.addNotification(child2);
3154         mService.getBinderService().cancelNotificationsFromListener(null, null);
3155         waitForIdle();
3156         StatusBarNotification[] notifs =
3157                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3158         assertEquals(1, notifs.length);
3159     }
3160 
3161     @Test
testCancelNotificationsFromListener_clearAll_Fgs()3162     public void testCancelNotificationsFromListener_clearAll_Fgs()
3163             throws Exception {
3164         when(mAmi.applyForegroundServiceNotification(
3165                 any(), anyString(), anyInt(), anyString(), anyInt()))
3166                 .thenReturn(SHOW_IMMEDIATELY);
3167         final NotificationRecord child2 = generateNotificationRecord(
3168                 mTestNotificationChannel, 3, null, false);
3169         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3170         mService.addNotification(child2);
3171         mService.getBinderService().cancelNotificationsFromListener(null, null);
3172         waitForIdle();
3173         StatusBarNotification[] notifs =
3174                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3175         assertEquals(0, notifs.length);
3176     }
3177 
3178     @Test
3179     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()3180     public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()
3181             throws Exception {
3182         final NotificationRecord notif = generateNotificationRecord(
3183                 mTestNotificationChannel, 1, null, false);
3184         notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3185         mService.addNotification(notif);
3186         verify(mWorkerHandler, times(0))
3187                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3188         mService.getBinderService().cancelNotificationsFromListener(null, null);
3189         waitForIdle();
3190         // Notification not cancelled.
3191         StatusBarNotification[] notifs =
3192                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3193         assertThat(notifs.length).isEqualTo(1);
3194 
3195         // Checks that a post update is sent.
3196         verify(mWorkerHandler, times(1))
3197                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3198         ArgumentCaptor<NotificationRecord> captor =
3199                 ArgumentCaptor.forClass(NotificationRecord.class);
3200         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3201                 anyBoolean());
3202         assertThat(captor.getValue().getNotification().flags
3203                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3204                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3205     }
3206 
3207     @Test
testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()3208     public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()
3209             throws Exception {
3210         final NotificationRecord parent = generateNotificationRecord(
3211                 mTestNotificationChannel, 1, "group", true);
3212         parent.getNotification().flags |= FLAG_ONGOING_EVENT;
3213         final NotificationRecord child = generateNotificationRecord(
3214                 mTestNotificationChannel, 2, "group", false);
3215         final NotificationRecord child2 = generateNotificationRecord(
3216                 mTestNotificationChannel, 3, "group", false);
3217         final NotificationRecord newGroup = generateNotificationRecord(
3218                 mTestNotificationChannel, 4, "group2", false);
3219         mService.addNotification(parent);
3220         mService.addNotification(child);
3221         mService.addNotification(child2);
3222         mService.addNotification(newGroup);
3223         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3224                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3225         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3226         waitForIdle();
3227         StatusBarNotification[] notifs =
3228                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3229         assertEquals(1, notifs.length);
3230     }
3231 
3232     @Test
testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()3233     public void testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()
3234             throws Exception {
3235         final NotificationRecord parent = generateNotificationRecord(
3236                 mTestNotificationChannel, 1, "group", true);
3237         final NotificationRecord child = generateNotificationRecord(
3238                 mTestNotificationChannel, 2, "group", false);
3239         final NotificationRecord child2 = generateNotificationRecord(
3240                 mTestNotificationChannel, 3, "group", false);
3241         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3242         final NotificationRecord newGroup = generateNotificationRecord(
3243                 mTestNotificationChannel, 4, "group2", false);
3244         mService.addNotification(parent);
3245         mService.addNotification(child);
3246         mService.addNotification(child2);
3247         mService.addNotification(newGroup);
3248         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3249                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3250         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3251         waitForIdle();
3252         StatusBarNotification[] notifs =
3253                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3254         assertEquals(1, notifs.length);
3255     }
3256 
3257     @Test
testCancelNotificationsFromListener_byKey_GroupWithFgsParent()3258     public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent()
3259             throws Exception {
3260         when(mAmi.applyForegroundServiceNotification(
3261                 any(), anyString(), anyInt(), anyString(), anyInt()))
3262                 .thenReturn(SHOW_IMMEDIATELY);
3263         final NotificationRecord parent = generateNotificationRecord(
3264                 mTestNotificationChannel, 1, "group", true);
3265         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3266         final NotificationRecord child = generateNotificationRecord(
3267                 mTestNotificationChannel, 2, "group", false);
3268         final NotificationRecord child2 = generateNotificationRecord(
3269                 mTestNotificationChannel, 3, "group", false);
3270         final NotificationRecord newGroup = generateNotificationRecord(
3271                 mTestNotificationChannel, 4, "group2", false);
3272         mService.addNotification(parent);
3273         mService.addNotification(child);
3274         mService.addNotification(child2);
3275         mService.addNotification(newGroup);
3276         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3277                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3278         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3279         waitForIdle();
3280         StatusBarNotification[] notifs =
3281                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3282         assertEquals(0, notifs.length);
3283     }
3284 
3285     @Test
testCancelNotificationsFromListener_byKey_GroupWithFgsChild()3286     public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild()
3287             throws Exception {
3288         when(mAmi.applyForegroundServiceNotification(
3289                 any(), anyString(), anyInt(), anyString(), anyInt()))
3290                 .thenReturn(SHOW_IMMEDIATELY);
3291         final NotificationRecord parent = generateNotificationRecord(
3292                 mTestNotificationChannel, 1, "group", true);
3293         final NotificationRecord child = generateNotificationRecord(
3294                 mTestNotificationChannel, 2, "group", false);
3295         final NotificationRecord child2 = generateNotificationRecord(
3296                 mTestNotificationChannel, 3, "group", false);
3297         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3298         final NotificationRecord newGroup = generateNotificationRecord(
3299                 mTestNotificationChannel, 4, "group2", false);
3300         mService.addNotification(parent);
3301         mService.addNotification(child);
3302         mService.addNotification(child2);
3303         mService.addNotification(newGroup);
3304         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3305                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3306         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3307         waitForIdle();
3308         StatusBarNotification[] notifs =
3309                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3310         assertEquals(0, notifs.length);
3311     }
3312 
3313     @Test
testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()3314     public void testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()
3315             throws Exception {
3316         final NotificationRecord parent = generateNotificationRecord(
3317                 mTestNotificationChannel, 1, "group", true);
3318         parent.getNotification().flags |= FLAG_NO_CLEAR;
3319         final NotificationRecord child = generateNotificationRecord(
3320                 mTestNotificationChannel, 2, "group", false);
3321         final NotificationRecord child2 = generateNotificationRecord(
3322                 mTestNotificationChannel, 3, "group", false);
3323         final NotificationRecord newGroup = generateNotificationRecord(
3324                 mTestNotificationChannel, 4, "group2", false);
3325         mService.addNotification(parent);
3326         mService.addNotification(child);
3327         mService.addNotification(child2);
3328         mService.addNotification(newGroup);
3329         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3330                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3331         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3332         waitForIdle();
3333         StatusBarNotification[] notifs =
3334                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3335         assertEquals(0, notifs.length);
3336     }
3337 
3338     @Test
testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()3339     public void testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()
3340             throws Exception {
3341         final NotificationRecord parent = generateNotificationRecord(
3342                 mTestNotificationChannel, 1, "group", true);
3343         final NotificationRecord child = generateNotificationRecord(
3344                 mTestNotificationChannel, 2, "group", false);
3345         final NotificationRecord child2 = generateNotificationRecord(
3346                 mTestNotificationChannel, 3, "group", false);
3347         child2.getNotification().flags |= FLAG_NO_CLEAR;
3348         final NotificationRecord newGroup = generateNotificationRecord(
3349                 mTestNotificationChannel, 4, "group2", false);
3350         mService.addNotification(parent);
3351         mService.addNotification(child);
3352         mService.addNotification(child2);
3353         mService.addNotification(newGroup);
3354         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3355                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3356         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3357         waitForIdle();
3358         StatusBarNotification[] notifs =
3359                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3360         assertEquals(0, notifs.length);
3361     }
3362 
3363     @Test
testCancelNotificationsFromListener_byKey_Ongoing()3364     public void testCancelNotificationsFromListener_byKey_Ongoing()
3365             throws Exception {
3366         final NotificationRecord child2 = generateNotificationRecord(
3367                 mTestNotificationChannel, 3, null, false);
3368         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3369         mService.addNotification(child2);
3370         String[] keys = {child2.getSbn().getKey()};
3371         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3372         waitForIdle();
3373         StatusBarNotification[] notifs =
3374                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3375         assertEquals(1, notifs.length);
3376     }
3377 
3378     @Test
testCancelNotificationsFromListener_byKey_NoClear()3379     public void testCancelNotificationsFromListener_byKey_NoClear()
3380             throws Exception {
3381         final NotificationRecord child2 = generateNotificationRecord(
3382                 mTestNotificationChannel, 3, null, false);
3383         child2.getNotification().flags |= FLAG_NO_CLEAR;
3384         mService.addNotification(child2);
3385         String[] keys = {child2.getSbn().getKey()};
3386         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3387         waitForIdle();
3388         StatusBarNotification[] notifs =
3389                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3390         assertEquals(0, notifs.length);
3391     }
3392 
3393     @Test
testCancelNotificationsFromListener_byKey_Fgs()3394     public void testCancelNotificationsFromListener_byKey_Fgs()
3395             throws Exception {
3396         when(mAmi.applyForegroundServiceNotification(
3397                 any(), anyString(), anyInt(), anyString(), anyInt()))
3398                 .thenReturn(SHOW_IMMEDIATELY);
3399         final NotificationRecord child2 = generateNotificationRecord(
3400                 mTestNotificationChannel, 3, null, false);
3401         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3402         mService.addNotification(child2);
3403         String[] keys = {child2.getSbn().getKey()};
3404         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3405         waitForIdle();
3406         StatusBarNotification[] notifs =
3407                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3408         assertEquals(0, notifs.length);
3409     }
3410 
3411     @Test
3412     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()3413     public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()
3414             throws Exception {
3415         final NotificationRecord notif = generateNotificationRecord(
3416                 mTestNotificationChannel, 3, null, false);
3417         notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3418         mService.addNotification(notif);
3419         String[] keys = {notif.getSbn().getKey()};
3420         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3421         waitForIdle();
3422         StatusBarNotification[] notifs =
3423                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3424         assertEquals(1, notifs.length);
3425 
3426         // Checks that a post update is sent.
3427         verify(mWorkerHandler, times(1))
3428                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3429         ArgumentCaptor<NotificationRecord> captor =
3430                 ArgumentCaptor.forClass(NotificationRecord.class);
3431         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3432                 anyBoolean());
3433         assertThat(captor.getValue().getNotification().flags
3434                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3435                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3436     }
3437 
3438     @Test
testGroupInstanceIds()3439     public void testGroupInstanceIds() throws Exception {
3440         final NotificationRecord group1 = generateNotificationRecord(
3441                 mTestNotificationChannel, 1, "group1", true);
3442         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds",
3443                 group1.getSbn().getId(), group1.getSbn().getNotification(),
3444                 group1.getSbn().getUserId());
3445         waitForIdle();
3446 
3447         // same group, child, should be returned
3448         final NotificationRecord group1Child = generateNotificationRecord(
3449                 mTestNotificationChannel, 2, "group1", false);
3450         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds",
3451                 group1Child.getSbn().getId(),
3452                 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
3453         waitForIdle();
3454 
3455         assertEquals(2, mNotificationRecordLogger.numCalls());
3456         assertEquals(mNotificationRecordLogger.get(0).getInstanceId(),
3457                 mNotificationRecordLogger.get(1).groupInstanceId.getId());
3458     }
3459 
3460     @Test
testFindGroupNotificationsLocked()3461     public void testFindGroupNotificationsLocked() throws Exception {
3462         // make sure the same notification can be found in both lists and returned
3463         final NotificationRecord group1 = generateNotificationRecord(
3464                 mTestNotificationChannel, 1, "group1", true);
3465         mService.addEnqueuedNotification(group1);
3466         mService.addNotification(group1);
3467 
3468         // should not be returned
3469         final NotificationRecord group2 = generateNotificationRecord(
3470                 mTestNotificationChannel, 2, "group2", true);
3471         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
3472                 group2.getSbn().getId(), group2.getSbn().getNotification(),
3473                 group2.getSbn().getUserId());
3474         waitForIdle();
3475 
3476         // should not be returned
3477         final NotificationRecord nonGroup = generateNotificationRecord(
3478                 mTestNotificationChannel, 3, null, false);
3479         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
3480                 nonGroup.getSbn().getId(), nonGroup.getSbn().getNotification(),
3481                 nonGroup.getSbn().getUserId());
3482         waitForIdle();
3483 
3484         // same group, child, should be returned
3485         final NotificationRecord group1Child = generateNotificationRecord(
3486                 mTestNotificationChannel, 4, "group1", false);
3487         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
3488                 group1Child.getSbn().getId(),
3489                 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
3490         waitForIdle();
3491 
3492         List<NotificationRecord> inGroup1 =
3493                 mService.findGroupNotificationsLocked(mPkg, group1.getGroupKey(),
3494                         group1.getSbn().getUserId());
3495         assertEquals(3, inGroup1.size());
3496         for (NotificationRecord record : inGroup1) {
3497             assertTrue(record.getGroupKey().equals(group1.getGroupKey()));
3498             assertTrue(record.getSbn().getId() == 1 || record.getSbn().getId() == 4);
3499         }
3500     }
3501 
3502     @Test
testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing()3503     public void testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing() throws Exception {
3504         final NotificationRecord notif = generateNotificationRecord(
3505                 mTestNotificationChannel, 1, "group", true);
3506         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3507         mService.addNotification(notif);
3508         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0,
3509                 Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL);
3510         waitForIdle();
3511         StatusBarNotification[] notifs =
3512                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3513         assertEquals(0, notifs.length);
3514     }
3515 
3516     @Test
testAppInitiatedCancelAllNotifications_CancelsOngoingFlag()3517     public void testAppInitiatedCancelAllNotifications_CancelsOngoingFlag() throws Exception {
3518         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3519         sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
3520         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3521                 "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag",
3522                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3523         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3524         waitForIdle();
3525         StatusBarNotification[] notifs =
3526                 mBinderService.getActiveNotifications(sbn.getPackageName());
3527         assertEquals(0, notifs.length);
3528     }
3529 
3530     @Test
testCancelAllNotificationsInt_CancelsOngoingFlag()3531     public void testCancelAllNotificationsInt_CancelsOngoingFlag() throws Exception {
3532         final NotificationRecord notif = generateNotificationRecord(
3533                 mTestNotificationChannel, 1, "group", true);
3534         notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
3535         mService.addNotification(notif);
3536         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
3537                 notif.getUserId(), REASON_CANCEL);
3538         waitForIdle();
3539         StatusBarNotification[] notifs =
3540                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3541         assertEquals(0, notifs.length);
3542     }
3543 
3544     @Test
testUserInitiatedCancelAllWithGroup_OngoingFlag()3545     public void testUserInitiatedCancelAllWithGroup_OngoingFlag() throws Exception {
3546         final NotificationRecord parent = generateNotificationRecord(
3547                 mTestNotificationChannel, 1, "group", true);
3548         final NotificationRecord child = generateNotificationRecord(
3549                 mTestNotificationChannel, 2, "group", false);
3550         final NotificationRecord child2 = generateNotificationRecord(
3551                 mTestNotificationChannel, 3, "group", false);
3552         child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
3553         final NotificationRecord newGroup = generateNotificationRecord(
3554                 mTestNotificationChannel, 4, "group2", false);
3555         mService.addNotification(parent);
3556         mService.addNotification(child);
3557         mService.addNotification(child2);
3558         mService.addNotification(newGroup);
3559         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3560                 parent.getUserId());
3561         waitForIdle();
3562         StatusBarNotification[] notifs =
3563                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3564         assertEquals(1, notifs.length);
3565     }
3566 
3567     @Test
testUserInitiatedCancelAllWithGroup_NoClearFlag()3568     public void testUserInitiatedCancelAllWithGroup_NoClearFlag() throws Exception {
3569         final NotificationRecord parent = generateNotificationRecord(
3570                 mTestNotificationChannel, 1, "group", true);
3571         final NotificationRecord child = generateNotificationRecord(
3572                 mTestNotificationChannel, 2, "group", false);
3573         final NotificationRecord child2 = generateNotificationRecord(
3574                 mTestNotificationChannel, 3, "group", false);
3575         child2.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3576         final NotificationRecord newGroup = generateNotificationRecord(
3577                 mTestNotificationChannel, 4, "group2", false);
3578         mService.addNotification(parent);
3579         mService.addNotification(child);
3580         mService.addNotification(child2);
3581         mService.addNotification(newGroup);
3582         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3583                 parent.getUserId());
3584         waitForIdle();
3585         StatusBarNotification[] notifs =
3586                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3587         assertEquals(1, notifs.length);
3588     }
3589 
3590     @Test
testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag()3591     public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception {
3592         when(mAmi.applyForegroundServiceNotification(
3593                 any(), anyString(), anyInt(), anyString(), anyInt()))
3594                 .thenReturn(SHOW_IMMEDIATELY);
3595         final NotificationRecord parent = generateNotificationRecord(
3596                 mTestNotificationChannel, 1, "group", true);
3597         final NotificationRecord child = generateNotificationRecord(
3598                 mTestNotificationChannel, 2, "group", false);
3599         final NotificationRecord child2 = generateNotificationRecord(
3600                 mTestNotificationChannel, 3, "group", false);
3601         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3602         final NotificationRecord newGroup = generateNotificationRecord(
3603                 mTestNotificationChannel, 4, "group2", false);
3604         mService.addNotification(parent);
3605         mService.addNotification(child);
3606         mService.addNotification(child2);
3607         mService.addNotification(newGroup);
3608         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3609                 parent.getUserId());
3610         waitForIdle();
3611         StatusBarNotification[] notifs =
3612                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3613         assertEquals(0, notifs.length);
3614     }
3615 
3616     @Test
testDefaultChannelUpdatesApp_postMigrationToPermissions()3617     public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception {
3618         final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
3619                 PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
3620                 NotificationChannel.DEFAULT_CHANNEL_ID);
3621         defaultChannel.setImportance(IMPORTANCE_NONE);
3622 
3623         mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
3624 
3625         verify(mPermissionHelper).setNotificationPermission(
3626                 PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
3627     }
3628 
3629     @Test
testPostNotification_appPermissionFixed()3630     public void testPostNotification_appPermissionFixed() throws Exception {
3631         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
3632         when(mPermissionHelper.isPermissionFixed(mPkg, mUserId)).thenReturn(true);
3633 
3634         NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
3635         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3636                 "testPostNotification_appPermissionFixed", 0,
3637                 temp.getNotification(), mUserId);
3638         waitForIdle();
3639         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3640         StatusBarNotification[] notifs =
3641                 mBinderService.getActiveNotifications(mPkg);
3642         assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
3643     }
3644 
3645     @Test
testSummaryNotification_appPermissionFixed()3646     public void testSummaryNotification_appPermissionFixed() {
3647         NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
3648         mService.addNotification(temp);
3649 
3650         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
3651         when(mPermissionHelper.isPermissionFixed(mPkg, temp.getUserId())).thenReturn(true);
3652 
3653         NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(),
3654                 temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0,
3655                 VISIBILITY_PRIVATE);
3656 
3657         assertThat(r.isImportanceFixed()).isTrue();
3658     }
3659 
3660     @Test
testTvExtenderChannelOverride_onTv()3661     public void testTvExtenderChannelOverride_onTv() throws Exception {
3662         mService.setIsTelevision(true);
3663         mService.setPreferencesHelper(mPreferencesHelper);
3664         when(mPreferencesHelper.getNotificationChannel(
3665                 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
3666                     new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
3667 
3668         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
3669         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_onTv", 0,
3670                 generateNotificationRecord(null, tv).getNotification(), mUserId);
3671         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
3672                 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean());
3673     }
3674 
3675     @Test
testTvExtenderChannelOverride_notOnTv()3676     public void testTvExtenderChannelOverride_notOnTv() throws Exception {
3677         mService.setIsTelevision(false);
3678         mService.setPreferencesHelper(mPreferencesHelper);
3679         when(mPreferencesHelper.getNotificationChannel(
3680                 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
3681                 mTestNotificationChannel);
3682 
3683         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
3684         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_notOnTv",
3685                 0, generateNotificationRecord(null, tv).getNotification(), mUserId);
3686         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
3687                 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null),
3688                 anyBoolean(), anyBoolean());
3689     }
3690 
3691     @Test
onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()3692     public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()
3693             throws RemoteException {
3694         // Have preexisting posted notifications from revoked package and other packages.
3695         mService.addNotification(new NotificationRecord(mContext,
3696                 generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel));
3697         mService.addNotification(new NotificationRecord(mContext,
3698                 generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
3699         // Have preexisting enqueued notifications from revoked package and other packages.
3700         mService.addEnqueuedNotification(new NotificationRecord(mContext,
3701                 generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel));
3702         mService.addEnqueuedNotification(new NotificationRecord(mContext,
3703                 generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
3704         assertThat(mService.mNotificationList).hasSize(2);
3705         assertThat(mService.mEnqueuedNotifications).hasSize(2);
3706 
3707         when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001);
3708         when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
3709 
3710         mOnPermissionChangeListener.onOpChanged(
3711                 AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0);
3712         waitForIdle();
3713 
3714         assertThat(mService.mNotificationList).hasSize(1);
3715         assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other");
3716         assertThat(mService.mEnqueuedNotifications).hasSize(1);
3717         assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo(
3718                 "other");
3719     }
3720 
3721     @Test
onOpChanged_permissionStillGranted_notificationsAreNotAffected()3722     public void onOpChanged_permissionStillGranted_notificationsAreNotAffected()
3723             throws RemoteException {
3724         // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission
3725         // being now granted, AND having previously posted notifications from said package) should
3726         // never happen (if we trust the broadcasts are correct). So this test is for a what-if
3727         // scenario, to verify we still handle it reasonably.
3728 
3729         // Have preexisting posted notifications from specific package and other packages.
3730         mService.addNotification(new NotificationRecord(mContext,
3731                 generateSbn("granted", 1001, 1, 0), mTestNotificationChannel));
3732         mService.addNotification(new NotificationRecord(mContext,
3733                 generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
3734         // Have preexisting enqueued notifications from specific package and other packages.
3735         mService.addEnqueuedNotification(new NotificationRecord(mContext,
3736                 generateSbn("granted", 1001, 3, 0), mTestNotificationChannel));
3737         mService.addEnqueuedNotification(new NotificationRecord(mContext,
3738                 generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
3739         assertThat(mService.mNotificationList).hasSize(2);
3740         assertThat(mService.mEnqueuedNotifications).hasSize(2);
3741 
3742         when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001);
3743         when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
3744 
3745         mOnPermissionChangeListener.onOpChanged(
3746                 AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0);
3747         waitForIdle();
3748 
3749         assertThat(mService.mNotificationList).hasSize(2);
3750         assertThat(mService.mEnqueuedNotifications).hasSize(2);
3751     }
3752 
3753     @Test
onOpChanged_notInitializedUser_ignored()3754     public void onOpChanged_notInitializedUser_ignored() throws RemoteException {
3755         when(mUmInternal.isUserInitialized(eq(0))).thenReturn(false);
3756 
3757         mOnPermissionChangeListener.onOpChanged(
3758                 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
3759         waitForIdle();
3760 
3761         // We early-exited and didn't even query PM for package details.
3762         verify(mPackageManagerInternal, never()).getPackageUid(any(), anyLong(), anyInt());
3763     }
3764 
3765     @Test
setNotificationsEnabledForPackage_disabling_clearsNotifications()3766     public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception {
3767         mService.addNotification(new NotificationRecord(mContext,
3768                 generateSbn("package", 1001, 1, 0), mTestNotificationChannel));
3769         assertThat(mService.mNotificationList).hasSize(1);
3770         when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001);
3771         when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn(
3772                 true);
3773 
3774         // Start with granted permission and simulate effect of revoking it.
3775         when(mPermissionHelper.hasPermission(1001)).thenReturn(true);
3776         doAnswer(invocation -> {
3777             when(mPermissionHelper.hasPermission(1001)).thenReturn(false);
3778             mOnPermissionChangeListener.onOpChanged(
3779                     AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
3780             return null;
3781         }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true);
3782 
3783         mBinderService.setNotificationsEnabledForPackage("package", 1001, false);
3784         waitForIdle();
3785 
3786         assertThat(mService.mNotificationList).hasSize(0);
3787 
3788         mTestableLooper.moveTimeForward(500);
3789         waitForIdle();
3790         verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null));
3791     }
3792 
3793     @Test
testUpdateAppNotifyCreatorBlock()3794     public void testUpdateAppNotifyCreatorBlock() throws Exception {
3795         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
3796 
3797         mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, false);
3798         Thread.sleep(500);
3799         waitForIdle();
3800 
3801         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
3802         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
3803 
3804         assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
3805                 captor.getValue().getAction());
3806         assertEquals(mPkg, captor.getValue().getPackage());
3807         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
3808     }
3809 
3810     @Test
testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting()3811     public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
3812         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
3813 
3814         mBinderService.setNotificationsEnabledForPackage(mPkg, 0, false);
3815         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
3816     }
3817 
3818     @Test
testUpdateAppNotifyCreatorUnblock()3819     public void testUpdateAppNotifyCreatorUnblock() throws Exception {
3820         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
3821 
3822         mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, true);
3823         Thread.sleep(500);
3824         waitForIdle();
3825 
3826         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
3827         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
3828 
3829         assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
3830                 captor.getValue().getAction());
3831         assertEquals(mPkg, captor.getValue().getPackage());
3832         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
3833     }
3834 
3835     @Test
testUpdateChannelNotifyCreatorBlock()3836     public void testUpdateChannelNotifyCreatorBlock() throws Exception {
3837         mService.setPreferencesHelper(mPreferencesHelper);
3838         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
3839                 eq(mTestNotificationChannel.getId()), anyBoolean()))
3840                 .thenReturn(mTestNotificationChannel);
3841 
3842         NotificationChannel updatedChannel =
3843                 new NotificationChannel(mTestNotificationChannel.getId(),
3844                         mTestNotificationChannel.getName(), IMPORTANCE_NONE);
3845 
3846         mBinderService.updateNotificationChannelForPackage(mPkg, 0, updatedChannel);
3847         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
3848         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
3849 
3850         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
3851                 captor.getValue().getAction());
3852         assertEquals(mPkg, captor.getValue().getPackage());
3853         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
3854                         NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
3855         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
3856     }
3857 
3858     @Test
testUpdateChannelNotifyCreatorUnblock()3859     public void testUpdateChannelNotifyCreatorUnblock() throws Exception {
3860         NotificationChannel existingChannel =
3861                 new NotificationChannel(mTestNotificationChannel.getId(),
3862                         mTestNotificationChannel.getName(), IMPORTANCE_NONE);
3863         mService.setPreferencesHelper(mPreferencesHelper);
3864         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
3865                 eq(mTestNotificationChannel.getId()), anyBoolean()))
3866                 .thenReturn(existingChannel);
3867 
3868         mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel);
3869         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
3870         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
3871 
3872         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
3873                 captor.getValue().getAction());
3874         assertEquals(mPkg, captor.getValue().getPackage());
3875         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
3876                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
3877         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
3878     }
3879 
3880     @Test
testUpdateChannelNoNotifyCreatorOtherChanges()3881     public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception {
3882         NotificationChannel existingChannel =
3883                 new NotificationChannel(mTestNotificationChannel.getId(),
3884                         mTestNotificationChannel.getName(), IMPORTANCE_MAX);
3885         mService.setPreferencesHelper(mPreferencesHelper);
3886         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
3887                 eq(mTestNotificationChannel.getId()), anyBoolean()))
3888                 .thenReturn(existingChannel);
3889 
3890         mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel);
3891         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
3892     }
3893 
3894     @Test
testUpdateGroupNotifyCreatorBlock()3895     public void testUpdateGroupNotifyCreatorBlock() throws Exception {
3896         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
3897         mService.setPreferencesHelper(mPreferencesHelper);
3898         when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()),
3899                 eq(mPkg), anyInt()))
3900                 .thenReturn(existing);
3901 
3902         NotificationChannelGroup updated = new NotificationChannelGroup("id", "name");
3903         updated.setBlocked(true);
3904 
3905         mBinderService.updateNotificationChannelGroupForPackage(mPkg, 0, updated);
3906         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
3907         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
3908 
3909         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
3910                 captor.getValue().getAction());
3911         assertEquals(mPkg, captor.getValue().getPackage());
3912         assertEquals(existing.getId(), captor.getValue().getStringExtra(
3913                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
3914         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
3915     }
3916 
3917     @Test
testUpdateGroupNotifyCreatorUnblock()3918     public void testUpdateGroupNotifyCreatorUnblock() throws Exception {
3919         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
3920         existing.setBlocked(true);
3921         mService.setPreferencesHelper(mPreferencesHelper);
3922         when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()),
3923                 eq(mPkg), anyInt()))
3924                 .thenReturn(existing);
3925 
3926         mBinderService.updateNotificationChannelGroupForPackage(
3927                 mPkg, 0, new NotificationChannelGroup("id", "name"));
3928         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
3929         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
3930 
3931         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
3932                 captor.getValue().getAction());
3933         assertEquals(mPkg, captor.getValue().getPackage());
3934         assertEquals(existing.getId(), captor.getValue().getStringExtra(
3935                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
3936         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
3937     }
3938 
3939     @Test
testUpdateGroupNoNotifyCreatorOtherChanges()3940     public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception {
3941         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
3942         mService.setPreferencesHelper(mPreferencesHelper);
3943         when(mPreferencesHelper.getNotificationChannelGroup(
3944                 eq(existing.getId()), eq(mPkg), anyInt()))
3945                 .thenReturn(existing);
3946 
3947         mBinderService.updateNotificationChannelGroupForPackage(
3948                 mPkg, 0, new NotificationChannelGroup("id", "new name"));
3949         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
3950     }
3951 
3952     @Test
testCreateChannelNotifyListener()3953     public void testCreateChannelNotifyListener() throws Exception {
3954         when(mCompanionMgr.getAssociations(mPkg, mUserId))
3955                 .thenReturn(singletonList(mock(AssociationInfo.class)));
3956         mService.setPreferencesHelper(mPreferencesHelper);
3957         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
3958                 eq(mTestNotificationChannel.getId()), anyBoolean()))
3959                 .thenReturn(mTestNotificationChannel);
3960         NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW);
3961         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
3962                 eq(channel2.getId()), anyBoolean()))
3963                 .thenReturn(channel2);
3964         when(mPreferencesHelper.createNotificationChannel(eq(mPkg), anyInt(),
3965                 eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()))
3966                 .thenReturn(true);
3967 
3968         reset(mListeners);
3969         mBinderService.createNotificationChannels(mPkg,
3970                 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2)));
3971         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
3972                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
3973                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
3974         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
3975                 eq(Process.myUserHandle()), eq(channel2),
3976                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
3977     }
3978 
3979     @Test
testCreateChannelGroupNotifyListener()3980     public void testCreateChannelGroupNotifyListener() throws Exception {
3981         when(mCompanionMgr.getAssociations(mPkg, mUserId))
3982                 .thenReturn(singletonList(mock(AssociationInfo.class)));
3983         mService.setPreferencesHelper(mPreferencesHelper);
3984         NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
3985         NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
3986 
3987         reset(mListeners);
3988         mBinderService.createNotificationChannelGroups(mPkg,
3989                 new ParceledListSlice(Arrays.asList(group1, group2)));
3990         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
3991                 eq(Process.myUserHandle()), eq(group1),
3992                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
3993         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
3994                 eq(Process.myUserHandle()), eq(group2),
3995                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
3996     }
3997 
3998     @Test
testUpdateChannelNotifyListener()3999     public void testUpdateChannelNotifyListener() throws Exception {
4000         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4001                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4002         mService.setPreferencesHelper(mPreferencesHelper);
4003         mTestNotificationChannel.setLightColor(Color.CYAN);
4004         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4005                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4006                 .thenReturn(mTestNotificationChannel);
4007 
4008         reset(mListeners);
4009         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel);
4010         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4011                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4012                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4013     }
4014 
4015     @Test
testDeleteChannelNotifyListener()4016     public void testDeleteChannelNotifyListener() throws Exception {
4017         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4018                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4019         mService.setPreferencesHelper(mPreferencesHelper);
4020         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4021                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4022                 .thenReturn(mTestNotificationChannel);
4023         when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
4024                 eq(mTestNotificationChannel.getId()),  anyInt(), anyBoolean())).thenReturn(true);
4025         reset(mListeners);
4026         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
4027         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4028                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4029                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4030     }
4031 
4032     @Test
testDeleteChannelOnlyDoExtraWorkIfExisted()4033     public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
4034         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4035                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4036         mService.setPreferencesHelper(mPreferencesHelper);
4037         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4038                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4039                 .thenReturn(null);
4040         reset(mListeners);
4041         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
4042         verifyNoMoreInteractions(mListeners);
4043         verifyNoMoreInteractions(mHistoryManager);
4044     }
4045 
4046     @Test
testDeleteChannelGroupNotifyListener()4047     public void testDeleteChannelGroupNotifyListener() throws Exception {
4048         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4049                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4050         NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
4051         mService.setPreferencesHelper(mPreferencesHelper);
4052         when(mPreferencesHelper.getNotificationChannelGroupWithChannels(
4053                 eq(mPkg), anyInt(), eq(ncg.getId()), anyBoolean()))
4054                 .thenReturn(ncg);
4055         reset(mListeners);
4056         mBinderService.deleteNotificationChannelGroup(mPkg, ncg.getId());
4057         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4058                 eq(Process.myUserHandle()), eq(ncg),
4059                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4060     }
4061 
4062     @Test
testDeleteChannelGroupChecksForFgses()4063     public void testDeleteChannelGroupChecksForFgses() throws Exception {
4064         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4065                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4066         CountDownLatch latch = new CountDownLatch(2);
4067         mService.createNotificationChannelGroup(
4068                 mPkg, mUid, new NotificationChannelGroup("group", "group"), true, false);
4069         new Thread(() -> {
4070             NotificationChannel notificationChannel = new NotificationChannel("id", "id",
4071                     NotificationManager.IMPORTANCE_HIGH);
4072             notificationChannel.setGroup("group");
4073             ParceledListSlice<NotificationChannel> pls =
4074                     new ParceledListSlice(ImmutableList.of(notificationChannel));
4075             try {
4076                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
4077             } catch (RemoteException e) {
4078                 throw new RuntimeException(e);
4079             }
4080             latch.countDown();
4081         }).start();
4082         new Thread(() -> {
4083             try {
4084                 synchronized (this) {
4085                     wait(5000);
4086                 }
4087                 mService.createNotificationChannelGroup(mPkg, mUid,
4088                         new NotificationChannelGroup("new", "new group"), true, false);
4089                 NotificationChannel notificationChannel =
4090                         new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
4091                 notificationChannel.setGroup("new");
4092                 ParceledListSlice<NotificationChannel> pls =
4093                         new ParceledListSlice(ImmutableList.of(notificationChannel));
4094                 try {
4095                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
4096                 mBinderService.deleteNotificationChannelGroup(mPkg, "group");
4097                 } catch (RemoteException e) {
4098                     throw new RuntimeException(e);
4099                 }
4100             } catch (Exception e) {
4101                 e.printStackTrace();
4102             }
4103             latch.countDown();
4104         }).start();
4105 
4106         latch.await();
4107         verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString());
4108     }
4109 
4110     @Test
testUpdateNotificationChannelFromPrivilegedListener_success()4111     public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception {
4112         mService.setPreferencesHelper(mPreferencesHelper);
4113         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4114                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4115         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4116                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4117                 .thenReturn(mTestNotificationChannel);
4118 
4119         mBinderService.updateNotificationChannelFromPrivilegedListener(
4120                 null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
4121 
4122         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
4123                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
4124 
4125         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4126                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4127                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4128     }
4129 
4130     @Test
testUpdateNotificationChannelFromPrivilegedListener_noAccess()4131     public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
4132         mService.setPreferencesHelper(mPreferencesHelper);
4133         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4134                 .thenReturn(emptyList());
4135 
4136         try {
4137             mBinderService.updateNotificationChannelFromPrivilegedListener(
4138                     null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
4139             fail("listeners that don't have a companion device shouldn't be able to call this");
4140         } catch (SecurityException e) {
4141             // pass
4142         }
4143 
4144         verify(mPreferencesHelper, never()).updateNotificationChannel(
4145                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
4146 
4147         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4148                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4149                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4150     }
4151 
4152     @Test
testUpdateNotificationChannelFromPrivilegedListener_badUser()4153     public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception {
4154         mService.setPreferencesHelper(mPreferencesHelper);
4155         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4156                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4157         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4158         mListener.component = new ComponentName(mPkg, mPkg);
4159         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
4160         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4161 
4162         try {
4163             mBinderService.updateNotificationChannelFromPrivilegedListener(
4164                     null, mPkg, UserHandle.ALL, mTestNotificationChannel);
4165             fail("incorrectly allowed a change to a user listener cannot see");
4166         } catch (SecurityException e) {
4167             // pass
4168         }
4169 
4170         verify(mPreferencesHelper, never()).updateNotificationChannel(
4171                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
4172 
4173         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4174                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4175                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4176     }
4177 
4178     @Test
testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()4179     public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
4180             throws Exception {
4181         mService.setPreferencesHelper(mPreferencesHelper);
4182         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4183                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4184         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4185                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4186                 .thenReturn(mTestNotificationChannel);
4187 
4188         final Uri soundUri = Uri.parse("content://media/test/sound/uri");
4189         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
4190                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
4191         updatedNotificationChannel.setSound(soundUri,
4192                 updatedNotificationChannel.getAudioAttributes());
4193 
4194         doThrow(new SecurityException("no access")).when(mUgmInternal)
4195                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
4196                 anyInt(), eq(Process.myUserHandle().getIdentifier()));
4197 
4198         assertThrows(SecurityException.class,
4199                 () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, mPkg,
4200                 Process.myUserHandle(), updatedNotificationChannel));
4201 
4202         verify(mPreferencesHelper, never()).updateNotificationChannel(
4203                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
4204 
4205         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4206                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4207                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4208     }
4209 
4210     @Test
testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()4211     public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
4212             throws Exception {
4213         mService.setPreferencesHelper(mPreferencesHelper);
4214         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4215                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4216         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4217                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4218                 .thenReturn(mTestNotificationChannel);
4219 
4220         final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
4221         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
4222                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
4223         updatedNotificationChannel.setSound(soundUri,
4224                 updatedNotificationChannel.getAudioAttributes());
4225 
4226         doThrow(new SecurityException("no access")).when(mUgmInternal)
4227                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
4228                     anyInt(), eq(Process.myUserHandle().getIdentifier()));
4229 
4230         mBinderService.updateNotificationChannelFromPrivilegedListener(
4231                 null, mPkg, Process.myUserHandle(), updatedNotificationChannel);
4232 
4233         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
4234                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
4235 
4236         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4237                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4238                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4239     }
4240 
4241     @Test
testGetNotificationChannelFromPrivilegedListener_cdm_success()4242     public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
4243         mService.setPreferencesHelper(mPreferencesHelper);
4244         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4245                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4246 
4247         mBinderService.getNotificationChannelsFromPrivilegedListener(
4248                 null, mPkg, Process.myUserHandle());
4249 
4250         verify(mPreferencesHelper, times(1)).getNotificationChannels(
4251                 anyString(), anyInt(), anyBoolean());
4252     }
4253 
4254     @Test
testGetNotificationChannelFromPrivilegedListener_cdm_noAccess()4255     public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
4256         mService.setPreferencesHelper(mPreferencesHelper);
4257         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4258                 .thenReturn(emptyList());
4259 
4260         try {
4261             mBinderService.getNotificationChannelsFromPrivilegedListener(
4262                     null, mPkg, Process.myUserHandle());
4263             fail("listeners that don't have a companion device shouldn't be able to call this");
4264         } catch (SecurityException e) {
4265             // pass
4266         }
4267 
4268         verify(mPreferencesHelper, never()).getNotificationChannels(
4269                 anyString(), anyInt(), anyBoolean());
4270     }
4271 
4272     @Test
testGetNotificationChannelFromPrivilegedListener_assistant_success()4273     public void testGetNotificationChannelFromPrivilegedListener_assistant_success()
4274             throws Exception {
4275         mService.setPreferencesHelper(mPreferencesHelper);
4276         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4277                 .thenReturn(emptyList());
4278         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
4279 
4280         mBinderService.getNotificationChannelsFromPrivilegedListener(
4281                 null, mPkg, Process.myUserHandle());
4282 
4283         verify(mPreferencesHelper, times(1)).getNotificationChannels(
4284                 anyString(), anyInt(), anyBoolean());
4285     }
4286 
4287     @Test
testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()4288     public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()
4289             throws Exception {
4290         mService.setPreferencesHelper(mPreferencesHelper);
4291         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4292                 .thenReturn(emptyList());
4293         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
4294 
4295         try {
4296             mBinderService.getNotificationChannelsFromPrivilegedListener(
4297                     null, mPkg, Process.myUserHandle());
4298             fail("listeners that don't have a companion device shouldn't be able to call this");
4299         } catch (SecurityException e) {
4300             // pass
4301         }
4302 
4303         verify(mPreferencesHelper, never()).getNotificationChannels(
4304                 anyString(), anyInt(), anyBoolean());
4305     }
4306 
4307     @Test
testGetNotificationChannelFromPrivilegedListener_badUser()4308     public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception {
4309         mService.setPreferencesHelper(mPreferencesHelper);
4310         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4311                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4312         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4313         mListener.component = new ComponentName(mPkg, mPkg);
4314         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
4315         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4316 
4317         try {
4318             mBinderService.getNotificationChannelsFromPrivilegedListener(
4319                     null, mPkg, Process.myUserHandle());
4320             fail("listener getting channels from a user they cannot see");
4321         } catch (SecurityException e) {
4322             // pass
4323         }
4324 
4325         verify(mPreferencesHelper, never()).getNotificationChannels(
4326                 anyString(), anyInt(), anyBoolean());
4327     }
4328 
4329     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_success()4330     public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
4331         mService.setPreferencesHelper(mPreferencesHelper);
4332         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4333                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4334 
4335         mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
4336                 null, mPkg, Process.myUserHandle());
4337 
4338         verify(mPreferencesHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt());
4339     }
4340 
4341     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_noAccess()4342     public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
4343         mService.setPreferencesHelper(mPreferencesHelper);
4344         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4345                 .thenReturn(emptyList());
4346 
4347         try {
4348             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
4349                     null, mPkg, Process.myUserHandle());
4350             fail("listeners that don't have a companion device shouldn't be able to call this");
4351         } catch (SecurityException e) {
4352             // pass
4353         }
4354 
4355         verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
4356     }
4357 
4358     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_badUser()4359     public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
4360         mService.setPreferencesHelper(mPreferencesHelper);
4361         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4362                 .thenReturn(emptyList());
4363         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4364         mListener.component = new ComponentName(mPkg, mPkg);
4365         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
4366         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4367         try {
4368             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
4369                     null, mPkg, Process.myUserHandle());
4370             fail("listeners that don't have a companion device shouldn't be able to call this");
4371         } catch (SecurityException e) {
4372             // pass
4373         }
4374 
4375         verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
4376     }
4377 
4378     @Test
testHasCompanionDevice_failure()4379     public void testHasCompanionDevice_failure() throws Exception {
4380         when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
4381                 new IllegalArgumentException());
4382         mService.hasCompanionDevice(mListener);
4383     }
4384 
4385     @Test
testHasCompanionDevice_noService()4386     public void testHasCompanionDevice_noService() {
4387         NotificationManagerService noManService =
4388                 new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
4389                 mNotificationInstanceIdSequence);
4390 
4391         assertFalse(noManService.hasCompanionDevice(mListener));
4392     }
4393 
4394     @Test
testCrossUserSnooze()4395     public void testCrossUserSnooze() {
4396         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
4397         mService.addNotification(r);
4398         NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
4399         mService.addNotification(r2);
4400 
4401         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4402         mListener.component = new ComponentName(mPkg, mPkg);
4403         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
4404         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4405 
4406         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
4407                 r.getKey(), 1000, null);
4408 
4409         verify(mWorkerHandler, never()).post(
4410                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
4411     }
4412 
4413     @Test
testSameUserSnooze()4414     public void testSameUserSnooze() {
4415         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
4416         mService.addNotification(r);
4417         NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
4418         mService.addNotification(r2);
4419 
4420         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4421         mListener.component = new ComponentName(mPkg, mPkg);
4422         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
4423         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4424 
4425         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
4426                 r2.getKey(), 1000, null);
4427 
4428         verify(mWorkerHandler).post(
4429                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
4430     }
4431 
4432     @Test
snoozeNotificationInt_rapidSnooze_new()4433     public void snoozeNotificationInt_rapidSnooze_new() {
4434         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
4435                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
4436 
4437         // Create recent notification.
4438         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
4439                 System.currentTimeMillis());
4440         mService.addNotification(nr1);
4441 
4442         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4443         mListener.component = new ComponentName(mPkg, mPkg);
4444         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
4445         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4446 
4447         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
4448                 nr1.getKey(), 1000, null);
4449 
4450         verify(mWorkerHandler).post(
4451                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
4452         // Ensure cancel event is logged.
4453         verify(mAppOpsManager).noteOpNoThrow(
4454                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null,
4455                 null);
4456     }
4457 
4458     @Test
snoozeNotificationInt_rapidSnooze_old()4459     public void snoozeNotificationInt_rapidSnooze_old() {
4460         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
4461                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
4462 
4463         // Create old notification.
4464         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
4465                 System.currentTimeMillis() - 60000);
4466         mService.addNotification(nr1);
4467 
4468         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4469         mListener.component = new ComponentName(mPkg, mPkg);
4470         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
4471         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4472 
4473         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
4474                 nr1.getKey(), 1000, null);
4475 
4476         verify(mWorkerHandler).post(
4477                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
4478         // Ensure cancel event is not logged.
4479         verify(mAppOpsManager, never()).noteOpNoThrow(
4480                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
4481                 any(), any());
4482     }
4483 
4484     @Test
snoozeNotificationInt_rapidSnooze_new_flagDisabled()4485     public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() {
4486         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
4487                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
4488 
4489         // Create recent notification.
4490         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
4491                 System.currentTimeMillis());
4492         mService.addNotification(nr1);
4493 
4494         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4495         mListener.component = new ComponentName(mPkg, mPkg);
4496         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
4497         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4498 
4499         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
4500                 nr1.getKey(), 1000, null);
4501 
4502         verify(mWorkerHandler).post(
4503                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
4504         // Ensure cancel event is not logged.
4505         verify(mAppOpsManager, never()).noteOpNoThrow(
4506                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
4507                 any(), any());
4508     }
4509 
4510     @Test
snoozeNotificationInt_rapidSnooze_old_flagDisabled()4511     public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() {
4512         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
4513                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
4514 
4515         // Create old notification.
4516         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
4517                 System.currentTimeMillis() - 60000);
4518         mService.addNotification(nr1);
4519 
4520         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4521         mListener.component = new ComponentName(mPkg, mPkg);
4522         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
4523         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4524 
4525         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
4526                 nr1.getKey(), 1000, null);
4527 
4528         verify(mWorkerHandler).post(
4529                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
4530         // Ensure cancel event is not logged.
4531         verify(mAppOpsManager, never()).noteOpNoThrow(
4532                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
4533                 any(), any());
4534     }
4535 
4536     @Test
testSnoozeRunnable_tooManySnoozed_singleNotification()4537     public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
4538         final NotificationRecord notification = generateNotificationRecord(
4539                 mTestNotificationChannel, 1, null, true);
4540         mService.addNotification(notification);
4541 
4542         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4543         when(mSnoozeHelper.canSnooze(1)).thenReturn(false);
4544 
4545         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4546                 mService.new SnoozeNotificationRunnable(
4547                         notification.getKey(), 100, null);
4548         snoozeNotificationRunnable.run();
4549 
4550         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
4551         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
4552     }
4553 
4554     @Test
testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification()4555     public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() {
4556         final NotificationRecord notification = generateNotificationRecord(
4557                 mTestNotificationChannel, 1, "group", true);
4558         final NotificationRecord notificationChild = generateNotificationRecord(
4559                 mTestNotificationChannel, 1, "group", false);
4560         mService.addNotification(notification);
4561         mService.addNotification(notificationChild);
4562 
4563         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4564         when(mSnoozeHelper.canSnooze(2)).thenReturn(false);
4565 
4566         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4567                 mService.new SnoozeNotificationRunnable(
4568                         notificationChild.getKey(), 100, null);
4569         snoozeNotificationRunnable.run();
4570 
4571         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
4572         assertThat(mService.getNotificationRecordCount()).isEqualTo(2);
4573     }
4574 
4575     @Test
testSnoozeRunnable_tooManySnoozed_summaryNotification()4576     public void testSnoozeRunnable_tooManySnoozed_summaryNotification() {
4577         final NotificationRecord notification = generateNotificationRecord(
4578                 mTestNotificationChannel, 1, "group", true);
4579         final NotificationRecord notificationChild = generateNotificationRecord(
4580                 mTestNotificationChannel, 12, "group", false);
4581         final NotificationRecord notificationChild2 = generateNotificationRecord(
4582                 mTestNotificationChannel, 13, "group", false);
4583         mService.addNotification(notification);
4584         mService.addNotification(notificationChild);
4585         mService.addNotification(notificationChild2);
4586 
4587         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4588         when(mSnoozeHelper.canSnooze(3)).thenReturn(false);
4589 
4590         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4591                 mService.new SnoozeNotificationRunnable(
4592                         notification.getKey(), 100, null);
4593         snoozeNotificationRunnable.run();
4594 
4595         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
4596         assertThat(mService.getNotificationRecordCount()).isEqualTo(3);
4597     }
4598 
4599     @Test
testSnoozeRunnable_reSnoozeASingleSnoozedNotification()4600     public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() {
4601         final NotificationRecord notification = generateNotificationRecord(
4602                 mTestNotificationChannel, 1, null, true);
4603         mService.addNotification(notification);
4604         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
4605         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4606 
4607         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4608                 mService.new SnoozeNotificationRunnable(
4609                 notification.getKey(), 100, null);
4610         snoozeNotificationRunnable.run();
4611         snoozeNotificationRunnable.run();
4612 
4613         // snooze twice
4614         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
4615     }
4616 
4617     @Test
testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey()4618     public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() {
4619         final NotificationRecord notification = generateNotificationRecord(
4620                 mTestNotificationChannel, 1, "group", true);
4621         mService.addNotification(notification);
4622         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
4623         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4624 
4625         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4626                 mService.new SnoozeNotificationRunnable(
4627                 notification.getKey(), 100, null);
4628         snoozeNotificationRunnable.run();
4629         snoozeNotificationRunnable.run();
4630 
4631         // snooze twice
4632         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
4633     }
4634 
4635     @Test
testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey()4636     public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception {
4637         final NotificationRecord notification = generateNotificationRecord(
4638                 mTestNotificationChannel, 1, "group", true);
4639         final NotificationRecord notification2 = generateNotificationRecord(
4640                 mTestNotificationChannel, 2, "group", true);
4641         mService.addNotification(notification);
4642         mService.addNotification(notification2);
4643         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
4644         when(mSnoozeHelper.getNotifications(
4645                 anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
4646         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4647 
4648         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4649                 mService.new SnoozeNotificationRunnable(
4650                         notification.getKey(), 100, null);
4651         snoozeNotificationRunnable.run();
4652         when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt()))
4653                 .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
4654         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
4655                 mService.new SnoozeNotificationRunnable(
4656                         notification2.getKey(), 100, null);
4657         snoozeNotificationRunnable2.run();
4658 
4659         // snooze twice
4660         verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
4661     }
4662 
4663     @Test
testSnoozeRunnable_snoozeNonGrouped()4664     public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
4665         final NotificationRecord nonGrouped = generateNotificationRecord(
4666                 mTestNotificationChannel, 1, null, false);
4667         final NotificationRecord grouped = generateNotificationRecord(
4668                 mTestNotificationChannel, 2, "group", false);
4669         mService.addNotification(grouped);
4670         mService.addNotification(nonGrouped);
4671         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4672 
4673         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4674                 mService.new SnoozeNotificationRunnable(
4675                         nonGrouped.getKey(), 100, null);
4676         snoozeNotificationRunnable.run();
4677 
4678         // only snooze the one notification
4679         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
4680         assertTrue(nonGrouped.getStats().hasSnoozed());
4681 
4682         assertEquals(2, mNotificationRecordLogger.numCalls());
4683         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
4684                 mNotificationRecordLogger.event(0));
4685         assertEquals(
4686                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
4687                 mNotificationRecordLogger.event(1));
4688     }
4689 
4690     @Test
testSnoozeRunnable_snoozeSummary_withChildren()4691     public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception {
4692         final NotificationRecord parent = generateNotificationRecord(
4693                 mTestNotificationChannel, 1, "group", true);
4694         final NotificationRecord child = generateNotificationRecord(
4695                 mTestNotificationChannel, 2, "group", false);
4696         final NotificationRecord child2 = generateNotificationRecord(
4697                 mTestNotificationChannel, 3, "group", false);
4698         mService.addNotification(parent);
4699         mService.addNotification(child);
4700         mService.addNotification(child2);
4701         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4702 
4703         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4704                 mService.new SnoozeNotificationRunnable(
4705                         parent.getKey(), 100, null);
4706         snoozeNotificationRunnable.run();
4707 
4708         // snooze parent and children
4709         verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong());
4710     }
4711 
4712     @Test
testSnoozeRunnable_snoozeGroupChild_fellowChildren()4713     public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception {
4714         final NotificationRecord parent = generateNotificationRecord(
4715                 mTestNotificationChannel, 1, "group", true);
4716         final NotificationRecord child = generateNotificationRecord(
4717                 mTestNotificationChannel, 2, "group", false);
4718         final NotificationRecord child2 = generateNotificationRecord(
4719                 mTestNotificationChannel, 3, "group", false);
4720         mService.addNotification(parent);
4721         mService.addNotification(child);
4722         mService.addNotification(child2);
4723         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4724 
4725         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4726                 mService.new SnoozeNotificationRunnable(
4727                         child2.getKey(), 100, null);
4728         snoozeNotificationRunnable.run();
4729 
4730         // only snooze the one child
4731         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
4732 
4733         assertEquals(2, mNotificationRecordLogger.numCalls());
4734         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
4735                 mNotificationRecordLogger.event(0));
4736         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
4737                         .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1));
4738     }
4739 
4740     @Test
testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary()4741     public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception {
4742         final NotificationRecord parent = generateNotificationRecord(
4743                 mTestNotificationChannel, 1, "group", true);
4744         assertTrue(parent.getSbn().getNotification().isGroupSummary());
4745         final NotificationRecord child = generateNotificationRecord(
4746                 mTestNotificationChannel, 2, "group", false);
4747         mService.addNotification(parent);
4748         mService.addNotification(child);
4749         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4750 
4751         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4752                 mService.new SnoozeNotificationRunnable(
4753                         child.getKey(), 100, null);
4754         snoozeNotificationRunnable.run();
4755 
4756         // snooze child and summary
4757         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
4758 
4759         assertEquals(4, mNotificationRecordLogger.numCalls());
4760         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
4761                 mNotificationRecordLogger.event(0));
4762         assertEquals(
4763                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
4764                 mNotificationRecordLogger.event(1));
4765         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
4766                 mNotificationRecordLogger.event(2));
4767         assertEquals(
4768                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
4769                 mNotificationRecordLogger.event(3));
4770     }
4771 
4772     @Test
testSnoozeRunnable_snoozeGroupChild_noOthersInGroup()4773     public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception {
4774         final NotificationRecord child = generateNotificationRecord(
4775                 mTestNotificationChannel, 2, "group", false);
4776         mService.addNotification(child);
4777         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4778 
4779         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4780                 mService.new SnoozeNotificationRunnable(
4781                         child.getKey(), 100, null);
4782         snoozeNotificationRunnable.run();
4783 
4784         // snooze child only
4785         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
4786 
4787         assertEquals(2, mNotificationRecordLogger.numCalls());
4788         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
4789                 mNotificationRecordLogger.event(0));
4790         assertEquals(
4791                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
4792                 mNotificationRecordLogger.event(1));
4793     }
4794 
4795     @Test
testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed()4796     public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception {
4797         final NotificationRecord parent = generateNotificationRecord(
4798                 mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true);
4799         final NotificationRecord child = generateNotificationRecord(
4800                 mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false);
4801         mService.addNotification(parent);
4802         mService.addNotification(child);
4803         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
4804 
4805         // snooze child only
4806         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4807                 mService.new SnoozeNotificationRunnable(
4808                         child.getKey(), 100, null);
4809         snoozeNotificationRunnable.run();
4810 
4811         // only child should be snoozed
4812         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
4813 
4814         // both group summary and child should be cancelled
4815         assertNull(mService.getNotificationRecord(parent.getKey()));
4816         assertNull(mService.getNotificationRecord(child.getKey()));
4817 
4818         assertEquals(4, mNotificationRecordLogger.numCalls());
4819         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
4820                 mNotificationRecordLogger.event(0));
4821         assertEquals(
4822                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
4823                 mNotificationRecordLogger.event(1));
4824     }
4825 
4826     @Test
testPostGroupChild_unsnoozeParent()4827     public void testPostGroupChild_unsnoozeParent() throws Exception {
4828         final NotificationRecord child = generateNotificationRecord(
4829                 mTestNotificationChannel, 2, "group", false);
4830 
4831         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing",
4832                 child.getSbn().getId(), child.getSbn().getNotification(),
4833                 child.getSbn().getUserId());
4834         waitForIdle();
4835 
4836         verify(mSnoozeHelper, times(1)).repostGroupSummary(
4837                 anyString(), anyInt(), eq(child.getGroupKey()));
4838     }
4839 
4840     @Test
testPostNonGroup_noUnsnoozing()4841     public void testPostNonGroup_noUnsnoozing() throws Exception {
4842         final NotificationRecord record = generateNotificationRecord(
4843                 mTestNotificationChannel, 2, null, false);
4844 
4845         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing",
4846                 record.getSbn().getId(), record.getSbn().getNotification(),
4847                 record.getSbn().getUserId());
4848         waitForIdle();
4849 
4850         verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
4851     }
4852 
4853     @Test
testPostGroupSummary_noUnsnoozing()4854     public void testPostGroupSummary_noUnsnoozing() throws Exception {
4855         final NotificationRecord parent = generateNotificationRecord(
4856                 mTestNotificationChannel, 2, "group", true);
4857 
4858         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostGroupSummary_noUnsnoozing",
4859                 parent.getSbn().getId(), parent.getSbn().getNotification(),
4860                 parent.getSbn().getUserId());
4861         waitForIdle();
4862 
4863         verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
4864     }
4865 
4866     @Test
testSystemNotificationListenerCanUnsnooze()4867     public void testSystemNotificationListenerCanUnsnooze() throws Exception {
4868         final NotificationRecord nr = generateNotificationRecord(
4869                 mTestNotificationChannel, 2, "group", false);
4870 
4871         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
4872                 "testSystemNotificationListenerCanUnsnooze",
4873                 nr.getSbn().getId(), nr.getSbn().getNotification(),
4874                 nr.getSbn().getUserId());
4875         waitForIdle();
4876         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
4877                 mService.new SnoozeNotificationRunnable(
4878                         nr.getKey(), 100, null);
4879         snoozeNotificationRunnable.run();
4880 
4881         ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo(
4882                 null, new ComponentName(mPkg, "test_class"), mUid, true, null, 0, 234);
4883         listener.isSystem = true;
4884         when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener);
4885 
4886         mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey());
4887         waitForIdle();
4888         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
4889         assertEquals(1, notifs.length);
4890         assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey()));
4891     }
4892 
4893     @Test
testSetListenerAccessForUser()4894     public void testSetListenerAccessForUser() throws Exception {
4895         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
4896         ComponentName c = ComponentName.unflattenFromString("package/Component");
4897         mBinderService.setNotificationListenerAccessGrantedForUser(
4898                 c, user.getIdentifier(), true, true);
4899 
4900 
4901         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
4902         verify(mListeners, times(1)).setPackageOrComponentEnabled(
4903                 c.flattenToString(), user.getIdentifier(), true, true, true);
4904         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
4905                 c.flattenToString(), user.getIdentifier(), false, true, true);
4906         verify(mAssistants, never()).setPackageOrComponentEnabled(
4907                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
4908     }
4909 
4910     @Test
testSetListenerAccessForUser_grantWithNameTooLong_throws()4911     public void testSetListenerAccessForUser_grantWithNameTooLong_throws() {
4912         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
4913         ComponentName c = new ComponentName("com.example.package",
4914                 com.google.common.base.Strings.repeat("Blah", 150));
4915 
4916         assertThrows(IllegalArgumentException.class,
4917                 () -> mBinderService.setNotificationListenerAccessGrantedForUser(
4918                         c, user.getIdentifier(), /* enabled= */ true, true));
4919     }
4920 
4921     @Test
testSetListenerAccessForUser_revokeWithNameTooLong_okay()4922     public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception {
4923         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
4924         ComponentName c = new ComponentName("com.example.package",
4925                 com.google.common.base.Strings.repeat("Blah", 150));
4926 
4927         mBinderService.setNotificationListenerAccessGrantedForUser(
4928                 c, user.getIdentifier(), /* enabled= */ false, true);
4929 
4930         verify(mListeners).setPackageOrComponentEnabled(
4931                 c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
4932     }
4933 
4934     @Test
testSetAssistantAccessForUser()4935     public void testSetAssistantAccessForUser() throws Exception {
4936         UserInfo ui = new UserInfo();
4937         ui.id = mContext.getUserId() + 10;
4938         UserHandle user = UserHandle.of(ui.id);
4939         List<UserInfo> uis = new ArrayList<>();
4940         uis.add(ui);
4941         ComponentName c = ComponentName.unflattenFromString("package/Component");
4942         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
4943 
4944         mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true);
4945 
4946         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
4947         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
4948                 c.flattenToString(), user.getIdentifier(), true, true, true);
4949         verify(mAssistants).setUserSet(ui.id, true);
4950         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
4951                 c.flattenToString(), user.getIdentifier(), false, true);
4952         verify(mListeners, never()).setPackageOrComponentEnabled(
4953                 any(), anyInt(), anyBoolean(), anyBoolean());
4954     }
4955 
4956     @Test
testGetAssistantAllowedForUser()4957     public void testGetAssistantAllowedForUser() throws Exception {
4958         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
4959         try {
4960             mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier());
4961         } catch (IllegalStateException e) {
4962             if (!e.getMessage().contains("At most one NotificationAssistant")) {
4963                 throw e;
4964             }
4965         }
4966         verify(mAssistants, times(1)).getAllowedComponents(user.getIdentifier());
4967     }
4968 
4969     @Test
testGetAssistantAllowed()4970     public void testGetAssistantAllowed() throws Exception {
4971         try {
4972             mBinderService.getAllowedNotificationAssistant();
4973         } catch (IllegalStateException e) {
4974             if (!e.getMessage().contains("At most one NotificationAssistant")) {
4975                 throw e;
4976             }
4977         }
4978         verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId());
4979     }
4980 
4981     @Test
testSetNASMigrationDoneAndResetDefault_enableNAS()4982     public void testSetNASMigrationDoneAndResetDefault_enableNAS() throws Exception {
4983         int userId = 10;
4984         setNASMigrationDone(false, userId);
4985         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
4986 
4987         mBinderService.setNASMigrationDoneAndResetDefault(userId, true);
4988 
4989         assertTrue(mService.isNASMigrationDone(userId));
4990         verify(mAssistants, times(1)).resetDefaultFromConfig();
4991     }
4992 
4993     @Test
testSetNASMigrationDoneAndResetDefault_disableNAS()4994     public void testSetNASMigrationDoneAndResetDefault_disableNAS() throws Exception {
4995         int userId = 10;
4996         setNASMigrationDone(false, userId);
4997         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
4998 
4999         mBinderService.setNASMigrationDoneAndResetDefault(userId, false);
5000 
5001         assertTrue(mService.isNASMigrationDone(userId));
5002         verify(mAssistants, times(1)).clearDefaults();
5003     }
5004 
5005     @Test
testSetNASMigrationDoneAndResetDefault_multiProfile()5006     public void testSetNASMigrationDoneAndResetDefault_multiProfile() throws Exception {
5007         int userId1 = 11;
5008         int userId2 = 12; //work profile
5009         setNASMigrationDone(false, userId1);
5010         setNASMigrationDone(false, userId2);
5011         setUsers(new int[]{userId1, userId2});
5012         when(mUm.isManagedProfile(userId2)).thenReturn(true);
5013         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2});
5014 
5015         mBinderService.setNASMigrationDoneAndResetDefault(userId1, true);
5016         assertTrue(mService.isNASMigrationDone(userId1));
5017         assertTrue(mService.isNASMigrationDone(userId2));
5018     }
5019 
5020     @Test
testSetNASMigrationDoneAndResetDefault_multiUser()5021     public void testSetNASMigrationDoneAndResetDefault_multiUser() throws Exception {
5022         int userId1 = 11;
5023         int userId2 = 12;
5024         setNASMigrationDone(false, userId1);
5025         setNASMigrationDone(false, userId2);
5026         setUsers(new int[]{userId1, userId2});
5027         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1});
5028         when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2});
5029 
5030         mBinderService.setNASMigrationDoneAndResetDefault(userId1, true);
5031         assertTrue(mService.isNASMigrationDone(userId1));
5032         assertFalse(mService.isNASMigrationDone(userId2));
5033     }
5034 
5035     @Test
testSetDndAccessForUser()5036     public void testSetDndAccessForUser() throws Exception {
5037         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5038         ComponentName c = ComponentName.unflattenFromString("package/Component");
5039         mBinderService.setNotificationPolicyAccessGrantedForUser(
5040                 c.getPackageName(), user.getIdentifier(), true);
5041 
5042         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
5043         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5044                 c.getPackageName(), user.getIdentifier(), true, true);
5045         verify(mAssistants, never()).setPackageOrComponentEnabled(
5046                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5047         verify(mListeners, never()).setPackageOrComponentEnabled(
5048                 any(), anyInt(), anyBoolean(), anyBoolean());
5049     }
5050 
5051     @Test
testSetListenerAccess()5052     public void testSetListenerAccess() throws Exception {
5053         ComponentName c = ComponentName.unflattenFromString("package/Component");
5054         mBinderService.setNotificationListenerAccessGranted(c, true, true);
5055 
5056         verify(mListeners, times(1)).setPackageOrComponentEnabled(
5057                 c.flattenToString(), mContext.getUserId(), true, true, true);
5058         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5059                 c.flattenToString(), mContext.getUserId(), false, true, true);
5060         verify(mAssistants, never()).setPackageOrComponentEnabled(
5061                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5062     }
5063 
5064     @Test
testSetAssistantAccess()5065     public void testSetAssistantAccess() throws Exception {
5066         List<UserInfo> uis = new ArrayList<>();
5067         UserInfo ui = new UserInfo();
5068         ui.id = mContext.getUserId();
5069         uis.add(ui);
5070         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5071         ComponentName c = ComponentName.unflattenFromString("package/Component");
5072 
5073         mBinderService.setNotificationAssistantAccessGranted(c, true);
5074 
5075         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5076                 c.flattenToString(), ui.id, true, true, true);
5077         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5078                 c.flattenToString(), ui.id, false, true);
5079         verify(mListeners, never()).setPackageOrComponentEnabled(
5080                 any(), anyInt(), anyBoolean(), anyBoolean());
5081     }
5082 
5083     @Test
testSetAssistantAccess_multiProfile()5084     public void testSetAssistantAccess_multiProfile() throws Exception {
5085         List<UserInfo> uis = new ArrayList<>();
5086         UserInfo ui = new UserInfo();
5087         ui.id = mContext.getUserId();
5088         uis.add(ui);
5089         UserInfo ui10 = new UserInfo();
5090         ui10.id = mContext.getUserId() + 10;
5091         uis.add(ui10);
5092         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5093         ComponentName c = ComponentName.unflattenFromString("package/Component");
5094 
5095         mBinderService.setNotificationAssistantAccessGranted(c, true);
5096 
5097         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5098                 c.flattenToString(), ui.id, true, true, true);
5099         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5100                 c.flattenToString(), ui10.id, true, true, true);
5101 
5102         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5103                 c.flattenToString(), ui.id, false, true);
5104         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5105                 c.flattenToString(), ui10.id, false, true);
5106         verify(mListeners, never()).setPackageOrComponentEnabled(
5107                 any(), anyInt(), anyBoolean(), anyBoolean());
5108     }
5109 
5110     @Test
testSetAssistantAccess_nullWithAllowedAssistant()5111     public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception {
5112         ArrayList<ComponentName> componentList = new ArrayList<>();
5113         ComponentName c = ComponentName.unflattenFromString("package/Component");
5114         componentList.add(c);
5115         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
5116         List<UserInfo> uis = new ArrayList<>();
5117         UserInfo ui = new UserInfo();
5118         ui.id = mContext.getUserId();
5119         uis.add(ui);
5120         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5121 
5122         mBinderService.setNotificationAssistantAccessGranted(null, true);
5123 
5124         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5125                 c.flattenToString(), ui.id, true, false, true);
5126         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5127                 c.flattenToString(), ui.id, false,  false);
5128         verify(mListeners, never()).setPackageOrComponentEnabled(
5129                 any(), anyInt(), anyBoolean(), anyBoolean());
5130     }
5131 
5132     @Test
testSetAssistantAccessForUser_nullWithAllowedAssistant()5133     public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception {
5134         List<UserInfo> uis = new ArrayList<>();
5135         UserInfo ui = new UserInfo();
5136         ui.id = mContext.getUserId() + 10;
5137         uis.add(ui);
5138         UserHandle user = ui.getUserHandle();
5139         ArrayList<ComponentName> componentList = new ArrayList<>();
5140         ComponentName c = ComponentName.unflattenFromString("package/Component");
5141         componentList.add(c);
5142         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
5143         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5144 
5145         mBinderService.setNotificationAssistantAccessGrantedForUser(
5146                 null, user.getIdentifier(), true);
5147 
5148         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5149                 c.flattenToString(), user.getIdentifier(), true, false, true);
5150         verify(mAssistants).setUserSet(ui.id, true);
5151         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5152                 c.flattenToString(), user.getIdentifier(), false,  false);
5153         verify(mListeners, never()).setPackageOrComponentEnabled(
5154                 any(), anyInt(), anyBoolean(), anyBoolean());
5155     }
5156 
5157     @Test
testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()5158     public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()
5159             throws Exception {
5160         List<UserInfo> uis = new ArrayList<>();
5161         UserInfo ui = new UserInfo();
5162         ui.id = mContext.getUserId();
5163         uis.add(ui);
5164         UserInfo ui10 = new UserInfo();
5165         ui10.id = mContext.getUserId() + 10;
5166         uis.add(ui10);
5167         UserHandle user = ui.getUserHandle();
5168         ArrayList<ComponentName> componentList = new ArrayList<>();
5169         ComponentName c = ComponentName.unflattenFromString("package/Component");
5170         componentList.add(c);
5171         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
5172         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5173 
5174         mBinderService.setNotificationAssistantAccessGrantedForUser(
5175                     null, user.getIdentifier(), true);
5176 
5177         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5178                 c.flattenToString(), user.getIdentifier(), true, false, true);
5179         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5180                 c.flattenToString(), ui10.id, true, false, true);
5181         verify(mAssistants).setUserSet(ui.id, true);
5182         verify(mAssistants).setUserSet(ui10.id, true);
5183         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5184                 c.flattenToString(), user.getIdentifier(), false,  false);
5185         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5186                 c.flattenToString(), ui10.id, false,  false);
5187         verify(mListeners, never()).setPackageOrComponentEnabled(
5188                 any(), anyInt(), anyBoolean(), anyBoolean());
5189     }
5190 
5191     @Test
testSetDndAccess()5192     public void testSetDndAccess() throws Exception {
5193         ComponentName c = ComponentName.unflattenFromString("package/Component");
5194 
5195         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
5196 
5197         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5198                 c.getPackageName(), mContext.getUserId(), true, true);
5199         verify(mAssistants, never()).setPackageOrComponentEnabled(
5200                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5201         verify(mListeners, never()).setPackageOrComponentEnabled(
5202                 any(), anyInt(), anyBoolean(), anyBoolean());
5203     }
5204 
5205     @Test
testSetListenerAccess_onLowRam()5206     public void testSetListenerAccess_onLowRam() throws Exception {
5207         when(mActivityManager.isLowRamDevice()).thenReturn(true);
5208         ComponentName c = ComponentName.unflattenFromString("package/Component");
5209         mBinderService.setNotificationListenerAccessGranted(c, true, true);
5210 
5211         verify(mListeners).setPackageOrComponentEnabled(
5212                 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5213         verify(mConditionProviders).setPackageOrComponentEnabled(
5214                 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5215         verify(mAssistants).migrateToXml();
5216         verify(mAssistants).resetDefaultAssistantsIfNecessary();
5217     }
5218 
5219     @Test
testSetAssistantAccess_onLowRam()5220     public void testSetAssistantAccess_onLowRam() throws Exception {
5221         when(mActivityManager.isLowRamDevice()).thenReturn(true);
5222         ComponentName c = ComponentName.unflattenFromString("package/Component");
5223         List<UserInfo> uis = new ArrayList<>();
5224         UserInfo ui = new UserInfo();
5225         ui.id = mContext.getUserId();
5226         uis.add(ui);
5227         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5228 
5229         mBinderService.setNotificationAssistantAccessGranted(c, true);
5230 
5231         verify(mListeners).migrateToXml();
5232         verify(mConditionProviders).setPackageOrComponentEnabled(
5233                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5234         verify(mAssistants).migrateToXml();
5235         verify(mAssistants).resetDefaultAssistantsIfNecessary();
5236     }
5237 
5238     @Test
testSetDndAccess_onLowRam()5239     public void testSetDndAccess_onLowRam() throws Exception {
5240         when(mActivityManager.isLowRamDevice()).thenReturn(true);
5241         ComponentName c = ComponentName.unflattenFromString("package/Component");
5242         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
5243 
5244         verify(mListeners).migrateToXml();
5245         verify(mConditionProviders).setPackageOrComponentEnabled(
5246                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5247         verify(mAssistants).migrateToXml();
5248         verify(mAssistants).resetDefaultAssistantsIfNecessary();
5249     }
5250 
5251     @Test
testSetListenerAccess_doesNothingOnLowRam_exceptWatch()5252     public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
5253         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
5254         when(mActivityManager.isLowRamDevice()).thenReturn(true);
5255         ComponentName c = ComponentName.unflattenFromString("package/Component");
5256 
5257         mBinderService.setNotificationListenerAccessGranted(c, true, true);
5258 
5259         verify(mListeners, times(1)).setPackageOrComponentEnabled(
5260                 c.flattenToString(), mContext.getUserId(), true, true, true);
5261         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5262                 c.flattenToString(), mContext.getUserId(), false, true, true);
5263         verify(mAssistants, never()).setPackageOrComponentEnabled(
5264                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5265     }
5266 
5267     @Test
testSetAssistantAccess_doesNothingOnLowRam_exceptWatch()5268     public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
5269         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
5270         when(mActivityManager.isLowRamDevice()).thenReturn(true);
5271         ComponentName c = ComponentName.unflattenFromString("package/Component");
5272         List<UserInfo> uis = new ArrayList<>();
5273         UserInfo ui = new UserInfo();
5274         ui.id = mContext.getUserId();
5275         uis.add(ui);
5276         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5277 
5278         mBinderService.setNotificationAssistantAccessGranted(c, true);
5279 
5280         verify(mListeners, never()).setPackageOrComponentEnabled(
5281                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5282         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5283                 c.flattenToString(), ui.id, false, true);
5284         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5285                 c.flattenToString(), ui.id, true, true, true);
5286     }
5287 
5288     @Test
testSetDndAccess_doesNothingOnLowRam_exceptWatch()5289     public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
5290         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
5291         when(mActivityManager.isLowRamDevice()).thenReturn(true);
5292         ComponentName c = ComponentName.unflattenFromString("package/Component");
5293 
5294         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
5295 
5296         verify(mListeners, never()).setPackageOrComponentEnabled(
5297                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5298         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5299                 c.getPackageName(), mContext.getUserId(), true, true);
5300         verify(mAssistants, never()).setPackageOrComponentEnabled(
5301                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5302     }
5303 
5304     @Test
testOnlyAutogroupIfNeeded_newNotification_ghUpdate()5305     public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() {
5306         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
5307         mService.addEnqueuedNotification(r);
5308         NotificationManagerService.PostNotificationRunnable runnable =
5309                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
5310                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
5311         runnable.run();
5312         waitForIdle();
5313 
5314         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
5315     }
5316 
5317     @Test
testOnlyAutogroupIfNeeded_groupChanged_ghUpdate()5318     public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() {
5319         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
5320                 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false);
5321         mService.addNotification(r);
5322 
5323         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
5324                 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false);
5325         mService.addEnqueuedNotification(update);
5326         NotificationManagerService.PostNotificationRunnable runnable =
5327                 mService.new PostNotificationRunnable(update.getKey(),
5328                         update.getSbn().getPackageName(), update.getUid(),
5329                         mPostNotificationTrackerFactory.newTracker(null));
5330         runnable.run();
5331         waitForIdle();
5332 
5333         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
5334     }
5335 
5336     @Test
testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate()5337     public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() {
5338         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
5339                 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false);
5340         mService.addNotification(r);
5341 
5342         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
5343                 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false);
5344         update.getNotification().flags = FLAG_AUTO_CANCEL;
5345         mService.addEnqueuedNotification(update);
5346         NotificationManagerService.PostNotificationRunnable runnable =
5347                 mService.new PostNotificationRunnable(update.getKey(),
5348                         update.getSbn().getPackageName(), update.getUid(),
5349                         mPostNotificationTrackerFactory.newTracker(null));
5350         runnable.run();
5351         waitForIdle();
5352 
5353         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
5354     }
5355 
5356     @Test
testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate()5357     public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() {
5358         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
5359                 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);
5360         mService.addNotification(r);
5361         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
5362                 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);
5363         update.getNotification().color = Color.BLACK;
5364         mService.addEnqueuedNotification(update);
5365 
5366         NotificationManagerService.PostNotificationRunnable runnable =
5367                 mService.new PostNotificationRunnable(update.getKey(),
5368                         update.getSbn().getPackageName(),
5369                         update.getUid(), mPostNotificationTrackerFactory.newTracker(null));
5370         runnable.run();
5371         waitForIdle();
5372 
5373         verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
5374     }
5375 
5376     @Test
testDontAutogroupIfCritical()5377     public void testDontAutogroupIfCritical() throws Exception {
5378         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
5379         r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW);
5380         mService.addEnqueuedNotification(r);
5381         NotificationManagerService.PostNotificationRunnable runnable =
5382                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
5383                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
5384         runnable.run();
5385 
5386         r = generateNotificationRecord(mTestNotificationChannel, 1, null, false);
5387         r.setCriticality(CriticalNotificationExtractor.CRITICAL);
5388         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
5389                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
5390         mService.addEnqueuedNotification(r);
5391 
5392         runnable.run();
5393         waitForIdle();
5394 
5395         verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
5396     }
5397 
5398     @Test
testNoNotificationDuringSetupPermission()5399     public void testNoNotificationDuringSetupPermission() throws Exception {
5400         mContext.getTestablePermissions().setPermission(
5401                 android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED);
5402         Bundle extras = new Bundle();
5403         extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true);
5404         Notification.Builder nb = new Notification.Builder(mContext,
5405                 mTestNotificationChannel.getId())
5406                 .setContentTitle("foo")
5407                 .addExtras(extras)
5408                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
5409         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
5410                 "testNoNotificationDuringSetupPermission", mUid, 0,
5411                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
5412         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
5413 
5414         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
5415                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
5416         waitForIdle();
5417 
5418         NotificationRecord posted = mService.findNotificationLocked(
5419                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
5420 
5421         assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP));
5422     }
5423 
5424     @Test
testNoFakeColorizedPermission()5425     public void testNoFakeColorizedPermission() throws Exception {
5426         mContext.getTestablePermissions().setPermission(
5427                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED);
5428         Notification.Builder nb = new Notification.Builder(mContext,
5429                 mTestNotificationChannel.getId())
5430                 .setContentTitle("foo")
5431                 .setColorized(true).setColor(Color.WHITE)
5432                 .setFlag(FLAG_CAN_COLORIZE, true)
5433                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
5434         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
5435                 "testNoFakeColorizedPermission", mUid, 0,
5436                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
5437         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
5438 
5439         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
5440                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
5441         waitForIdle();
5442 
5443         NotificationRecord posted = mService.findNotificationLocked(
5444                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
5445 
5446         assertFalse(posted.getNotification().isColorized());
5447     }
5448 
5449     @Test
5450     @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
testMediaStyle_enforceNoClearFlagEnabled()5451     public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
5452         Notification.MediaStyle style = new Notification.MediaStyle();
5453         Notification.Builder nb = new Notification.Builder(mContext,
5454                 mTestNotificationChannel.getId())
5455                 .setStyle(style);
5456 
5457         NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
5458 
5459         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
5460     }
5461 
5462     @Test
5463     @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
testCustomMediaStyle_enforceNoClearFlagEnabled()5464     public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
5465         Notification.DecoratedMediaCustomViewStyle style =
5466                 new Notification.DecoratedMediaCustomViewStyle();
5467         Notification.Builder nb = new Notification.Builder(mContext,
5468                 mTestNotificationChannel.getId())
5469                 .setStyle(style);
5470 
5471         NotificationRecord posted = createAndPostNotification(nb,
5472                 "testCustomMediaStyleSetNoClearFlag");
5473 
5474         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
5475     }
5476 
5477     @Test
5478     @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
testMediaStyle_enforceNoClearFlagDisabled()5479     public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
5480         Notification.MediaStyle style = new Notification.MediaStyle();
5481         Notification.Builder nb = new Notification.Builder(mContext,
5482                 mTestNotificationChannel.getId())
5483                 .setStyle(style);
5484 
5485         NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
5486 
5487         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
5488     }
5489 
5490     @Test
5491     @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
testCustomMediaStyle_enforceNoClearFlagDisabled()5492     public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
5493         Notification.DecoratedMediaCustomViewStyle style =
5494                 new Notification.DecoratedMediaCustomViewStyle();
5495         Notification.Builder nb = new Notification.Builder(mContext,
5496                 mTestNotificationChannel.getId())
5497                 .setStyle(style);
5498 
5499         NotificationRecord posted = createAndPostNotification(nb,
5500                 "testCustomMediaStyleSetNoClearFlag");
5501 
5502         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
5503     }
5504 
5505     @Test
testMediaStyleRemote_hasPermission()5506     public void testMediaStyleRemote_hasPermission() throws RemoteException {
5507         String deviceName = "device";
5508         mContext.getTestablePermissions().setPermission(
5509                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED);
5510         Notification.MediaStyle style = new Notification.MediaStyle();
5511         style.setRemotePlaybackInfo(deviceName, 0, null);
5512         Notification.Builder nb = new Notification.Builder(mContext,
5513                 mTestNotificationChannel.getId())
5514                 .setStyle(style);
5515 
5516         NotificationRecord posted = createAndPostNotification(nb,
5517                 "testMediaStyleRemoteHasPermission");
5518         Bundle extras = posted.getNotification().extras;
5519 
5520         assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
5521         assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
5522     }
5523 
5524     @Test
testMediaStyleRemote_noPermission()5525     public void testMediaStyleRemote_noPermission() throws RemoteException {
5526         String deviceName = "device";
5527         mContext.getTestablePermissions().setPermission(
5528                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED);
5529         Notification.MediaStyle style = new Notification.MediaStyle();
5530         style.setRemotePlaybackInfo(deviceName, 0, null);
5531         Notification.Builder nb = new Notification.Builder(mContext,
5532                 mTestNotificationChannel.getId())
5533                 .setStyle(style);
5534 
5535         NotificationRecord posted = createAndPostNotification(nb,
5536                 "testMediaStyleRemoteNoPermission");
5537 
5538         assertFalse(posted.getNotification().extras
5539                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
5540         assertFalse(posted.getNotification().extras
5541                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
5542         assertFalse(posted.getNotification().extras
5543                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
5544     }
5545 
5546     @Test
testCustomMediaStyleRemote_noPermission()5547     public void testCustomMediaStyleRemote_noPermission() throws RemoteException {
5548         String deviceName = "device";
5549         when(mPackageManager.checkPermission(
5550                 eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
5551                 .thenReturn(PERMISSION_DENIED);
5552         Notification.DecoratedMediaCustomViewStyle style =
5553                 new Notification.DecoratedMediaCustomViewStyle();
5554         style.setRemotePlaybackInfo(deviceName, 0, null);
5555         Notification.Builder nb = new Notification.Builder(mContext,
5556                 mTestNotificationChannel.getId())
5557                 .setStyle(style);
5558 
5559         NotificationRecord posted = createAndPostNotification(nb,
5560                 "testCustomMediaStyleRemoteNoPermission");
5561 
5562         assertFalse(posted.getNotification().extras
5563                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
5564         assertFalse(posted.getNotification().extras
5565                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
5566         assertFalse(posted.getNotification().extras
5567                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
5568     }
5569 
5570     @Test
testSubstituteAppName_hasPermission()5571     public void testSubstituteAppName_hasPermission() throws RemoteException {
5572         String subName = "Substitute Name";
5573         mContext.getTestablePermissions().setPermission(
5574                 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED);
5575         Bundle extras = new Bundle();
5576         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
5577         Notification.Builder nb = new Notification.Builder(mContext,
5578                 mTestNotificationChannel.getId())
5579                 .addExtras(extras);
5580 
5581         NotificationRecord posted = createAndPostNotification(nb,
5582                 "testSubstituteAppNameHasPermission");
5583 
5584         assertTrue(posted.getNotification().extras
5585                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
5586         assertEquals(posted.getNotification().extras
5587                 .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName);
5588     }
5589 
5590     @Test
testSubstituteAppName_noPermission()5591     public void testSubstituteAppName_noPermission() throws RemoteException {
5592         mContext.getTestablePermissions().setPermission(
5593                 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED);
5594         Bundle extras = new Bundle();
5595         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
5596         Notification.Builder nb = new Notification.Builder(mContext,
5597                 mTestNotificationChannel.getId())
5598                 .addExtras(extras);
5599 
5600         NotificationRecord posted = createAndPostNotification(nb,
5601                 "testSubstituteAppNameNoPermission");
5602 
5603         assertFalse(posted.getNotification().extras
5604                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
5605     }
5606 
5607     @Test
testGetNotificationCountLocked()5608     public void testGetNotificationCountLocked() {
5609         String sampleTagToExclude = null;
5610         int sampleIdToExclude = 0;
5611         for (int i = 0; i < 20; i++) {
5612             NotificationRecord r =
5613                     generateNotificationRecord(mTestNotificationChannel, i, null, false);
5614             mService.addEnqueuedNotification(r);
5615 
5616         }
5617         for (int i = 0; i < 20; i++) {
5618             NotificationRecord r =
5619                     generateNotificationRecord(mTestNotificationChannel, i, null, false);
5620             mService.addNotification(r);
5621             sampleTagToExclude = r.getSbn().getTag();
5622             sampleIdToExclude = i;
5623         }
5624 
5625         // another package
5626         Notification n =
5627                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
5628                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
5629                 .build();
5630 
5631         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0,
5632                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
5633         NotificationRecord otherPackage =
5634                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
5635         mService.addEnqueuedNotification(otherPackage);
5636         mService.addNotification(otherPackage);
5637 
5638         // Same notifications are enqueued as posted, everything counts b/c id and tag don't match
5639         // anything that's currently enqueued or posted
5640         int userId = mUserId;
5641         assertEquals(40,
5642                 mService.getNotificationCount(mPkg, userId, 0, null));
5643         assertEquals(40,
5644                 mService.getNotificationCount(mPkg, userId, 0, "tag2"));
5645 
5646         // return all for package "a" - "banana" tag isn't used
5647         assertEquals(2,
5648                 mService.getNotificationCount("a", userId, 0, "banana"));
5649 
5650         // exclude a known notification - it's excluded from only the posted list, not enqueued
5651         assertEquals(39, mService.getNotificationCount(
5652                 mPkg, userId, sampleIdToExclude, sampleTagToExclude));
5653     }
5654 
5655     @Test
testAddAutogroup_requestsSort()5656     public void testAddAutogroup_requestsSort() throws Exception {
5657         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5658         mService.addNotification(r);
5659         mService.addAutogroupKeyLocked(r.getKey(), true);
5660 
5661         verify(mRankingHandler, times(1)).requestSort();
5662     }
5663 
5664     @Test
testRemoveAutogroup_requestsSort()5665     public void testRemoveAutogroup_requestsSort() throws Exception {
5666         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5667         r.setOverrideGroupKey("TEST");
5668         mService.addNotification(r);
5669         mService.removeAutogroupKeyLocked(r.getKey());
5670 
5671         verify(mRankingHandler, times(1)).requestSort();
5672     }
5673 
5674     @Test
testReaddAutogroup_noSort()5675     public void testReaddAutogroup_noSort() throws Exception {
5676         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5677         r.setOverrideGroupKey("TEST");
5678         mService.addNotification(r);
5679         mService.addAutogroupKeyLocked(r.getKey(), true);
5680 
5681         verify(mRankingHandler, never()).requestSort();
5682     }
5683 
5684     @Test
5685     @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST)
testAutogroupSuppressSort_noSort()5686     public void testAutogroupSuppressSort_noSort() throws Exception {
5687         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5688         mService.addNotification(r);
5689         mService.addAutogroupKeyLocked(r.getKey(), false);
5690 
5691         verify(mRankingHandler, never()).requestSort();
5692     }
5693 
5694     @Test
5695     @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST)
testAutogroupOnPost_skipManualSort()5696     public void testAutogroupOnPost_skipManualSort() throws Exception {
5697         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5698         mService.addNotification(r);
5699         verify(mRankingHandler, never()).requestSort();
5700     }
5701 
5702     @Test
testHandleRankingSort_sendsUpdateOnSignalExtractorChange()5703     public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception {
5704         mService.setPreferencesHelper(mPreferencesHelper);
5705         NotificationManagerService.WorkerHandler handler = mock(
5706                 NotificationManagerService.WorkerHandler.class);
5707         mService.setHandler(handler);
5708 
5709         Map<String, Answer> answers = getSignalExtractorSideEffects();
5710         for (String message : answers.keySet()) {
5711             mService.clearNotifications();
5712             final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5713             mService.addNotification(r);
5714 
5715             doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r);
5716 
5717             mService.handleRankingSort();
5718         }
5719         verify(handler, times(answers.size())).scheduleSendRankingUpdate();
5720     }
5721 
5722     @Test
testHandleRankingSort_noUpdateWhenNoSignalChange()5723     public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception {
5724         mService.setRankingHelper(mRankingHelper);
5725         NotificationManagerService.WorkerHandler handler = mock(
5726                 NotificationManagerService.WorkerHandler.class);
5727         mService.setHandler(handler);
5728 
5729         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
5730         mService.addNotification(r);
5731 
5732         mService.handleRankingSort();
5733         verify(handler, never()).scheduleSendRankingUpdate();
5734     }
5735 
5736     @Test
testReadPolicyXml_readApprovedServicesFromXml()5737     public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception {
5738         final String upgradeXml = "<notification-policy version=\"1\">"
5739                 + "<ranking></ranking>"
5740                 + "<enabled_listeners>"
5741                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
5742                 + "</enabled_listeners>"
5743                 + "<enabled_assistants>"
5744                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
5745                 + "</enabled_assistants>"
5746                 + "<dnd_apps>"
5747                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
5748                 + "</dnd_apps>"
5749                 + "</notification-policy>";
5750         mService.readPolicyXml(
5751                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
5752                 false,
5753                 UserHandle.USER_ALL);
5754         verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
5755         verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
5756         verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
5757 
5758         // numbers are inflated for setup
5759         verify(mListeners, times(1)).migrateToXml();
5760         verify(mConditionProviders, times(1)).migrateToXml();
5761         verify(mAssistants, times(1)).migrateToXml();
5762         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
5763     }
5764 
5765     @Test
testReadPolicyXml_readSnoozedNotificationsFromXml()5766     public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception {
5767         final String upgradeXml = "<notification-policy version=\"1\">"
5768                 + "<snoozed-notifications>></snoozed-notifications>"
5769                 + "</notification-policy>";
5770         mService.readPolicyXml(
5771                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
5772                 false,
5773                 UserHandle.USER_ALL);
5774         verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong());
5775     }
5776 
5777     @Test
testReadPolicyXml_readApprovedServicesFromSettings()5778     public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
5779         final String preupgradeXml = "<notification-policy version=\"1\">"
5780                 + "<ranking></ranking>"
5781                 + "</notification-policy>";
5782         mService.readPolicyXml(
5783                 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
5784                 false,
5785                 UserHandle.USER_ALL);
5786         verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt());
5787         verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt());
5788         verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt());
5789 
5790         // numbers are inflated for setup
5791         verify(mListeners, times(2)).migrateToXml();
5792         verify(mConditionProviders, times(2)).migrateToXml();
5793         verify(mAssistants, times(2)).migrateToXml();
5794         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
5795     }
5796 
5797     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser()5798     public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception {
5799         final String policyXml = "<notification-policy version=\"1\">"
5800                 + "<ranking></ranking>"
5801                 + "<enabled_listeners>"
5802                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5803                 + "</enabled_listeners>"
5804                 + "<enabled_assistants>"
5805                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5806                 + "</enabled_assistants>"
5807                 + "<dnd_apps>"
5808                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5809                 + "</dnd_apps>"
5810                 + "</notification-policy>";
5811         UserInfo ui = new UserInfo(10, "Clone", UserInfo.FLAG_PROFILE);
5812         ui.userType = USER_TYPE_PROFILE_CLONE;
5813         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
5814         mService.readPolicyXml(
5815                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
5816                 true,
5817                 10);
5818         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
5819         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
5820         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
5821     }
5822 
5823     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser()5824     public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception {
5825         final String policyXml = "<notification-policy version=\"1\">"
5826                 + "<ranking></ranking>"
5827                 + "<enabled_listeners>"
5828                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5829                 + "</enabled_listeners>"
5830                 + "<enabled_assistants>"
5831                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5832                 + "</enabled_assistants>"
5833                 + "<dnd_apps>"
5834                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5835                 + "</dnd_apps>"
5836                 + "</notification-policy>";
5837         UserInfo ui = new UserInfo(10, "Work", UserInfo.FLAG_PROFILE);
5838         ui.userType = USER_TYPE_PROFILE_MANAGED;
5839         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
5840         mService.readPolicyXml(
5841                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
5842                 true,
5843                 10);
5844         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
5845         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
5846         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
5847     }
5848 
5849     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser()5850     public void testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser() throws Exception {
5851         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
5852                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
5853         final String policyXml = "<notification-policy version=\"1\">"
5854                 + "<ranking></ranking>"
5855                 + "<enabled_listeners>"
5856                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5857                 + "</enabled_listeners>"
5858                 + "<enabled_assistants>"
5859                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5860                 + "</enabled_assistants>"
5861                 + "<dnd_apps>"
5862                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5863                 + "</dnd_apps>"
5864                 + "</notification-policy>";
5865         UserInfo ui = new UserInfo(10, "Private", UserInfo.FLAG_PROFILE);
5866         ui.userType = USER_TYPE_PROFILE_PRIVATE;
5867         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
5868         mService.readPolicyXml(
5869                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
5870                 true,
5871                 10);
5872         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
5873         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
5874         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
5875     }
5876 
5877     @Test
testReadPolicyXml_restoresManagedServicesForNonManagedUser()5878     public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception {
5879         final String policyXml = "<notification-policy version=\"1\">"
5880                 + "<ranking></ranking>"
5881                 + "<enabled_listeners>"
5882                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5883                 + "</enabled_listeners>"
5884                 + "<enabled_assistants>"
5885                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5886                 + "</enabled_assistants>"
5887                 + "<dnd_apps>"
5888                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
5889                 + "</dnd_apps>"
5890                 + "</notification-policy>";
5891         UserInfo ui = new UserInfo();
5892         ui.id = 10;
5893         ui.userType = USER_TYPE_FULL_SECONDARY;
5894         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
5895         mService.readPolicyXml(
5896                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
5897                 true,
5898                 10);
5899         verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10));
5900         verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10));
5901         verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10));
5902     }
5903 
5904     @Test
testLocaleChangedCallsUpdateDefaultZenModeRules()5905     public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception {
5906         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
5907         mService.mZenModeHelper = mZenModeHelper;
5908         mService.mLocaleChangeReceiver.onReceive(mContext,
5909                 new Intent(Intent.ACTION_LOCALE_CHANGED));
5910 
5911         verify(mZenModeHelper).updateZenRulesOnLocaleChange();
5912     }
5913 
simulateNotificationTimeout(String notificationKey)5914     private void simulateNotificationTimeout(String notificationKey) {
5915         if (Flags.allNotifsNeedTtl()) {
5916             mService.mNotificationManagerPrivate.timeoutNotification(notificationKey);
5917         } else {
5918             final Bundle extras = new Bundle();
5919             extras.putString(EXTRA_KEY, notificationKey);
5920             final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT);
5921             intent.putExtras(extras);
5922             mNotificationTimeoutReceiver.onReceive(getContext(), intent);
5923         }
5924     }
5925 
5926     @Test
testTimeout_CancelsNotification()5927     public void testTimeout_CancelsNotification() throws Exception {
5928         final NotificationRecord notif = generateNotificationRecord(
5929                 mTestNotificationChannel, 1, null, false);
5930         mService.addNotification(notif);
5931 
5932         simulateNotificationTimeout(notif.getKey());
5933         waitForIdle();
5934 
5935         // Check that the notification was cancelled.
5936         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
5937         assertThat(notifsAfter.length).isEqualTo(0);
5938         assertThat(mService.getNotificationRecord(notif.getKey())).isNull();
5939     }
5940 
5941     @Test
testTimeout_NoCancelForegroundServiceNotification()5942     public void testTimeout_NoCancelForegroundServiceNotification() throws Exception {
5943         // Creates a notification with FLAG_FOREGROUND_SERVICE
5944         final NotificationRecord notif = generateNotificationRecord(null);
5945         notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
5946         mService.addNotification(notif);
5947 
5948         simulateNotificationTimeout(notif.getKey());
5949         waitForIdle();
5950 
5951         // Check that the notification was not cancelled.
5952         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
5953         assertThat(notifsAfter.length).isEqualTo(1);
5954         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
5955     }
5956 
5957     @Test
testTimeout_NoCancelUserInitJobNotification()5958     public void testTimeout_NoCancelUserInitJobNotification() throws Exception {
5959         // Create a notification with FLAG_USER_INITIATED_JOB
5960         final NotificationRecord notif = generateNotificationRecord(null);
5961         notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB;
5962         mService.addNotification(notif);
5963 
5964         simulateNotificationTimeout(notif.getKey());
5965         waitForIdle();
5966 
5967         // Check that the notification was not cancelled.
5968         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
5969         assertThat(notifsAfter.length).isEqualTo(1);
5970         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
5971     }
5972 
5973     @Test
5974     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testTimeout_NoCancelLifetimeExtensionNotification()5975     public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception {
5976         // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY
5977         final NotificationRecord notif = generateNotificationRecord(null);
5978         notif.getSbn().getNotification().flags =
5979                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
5980         mService.addNotification(notif);
5981 
5982         simulateNotificationTimeout(notif.getKey());
5983         waitForIdle();
5984 
5985         // Check that the notification was not cancelled.
5986         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
5987         assertThat(notifsAfter.length).isEqualTo(1);
5988         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
5989 
5990         // Checks that a post update is sent.
5991         verify(mWorkerHandler, times(1))
5992                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
5993         ArgumentCaptor<NotificationRecord> captor =
5994                 ArgumentCaptor.forClass(NotificationRecord.class);
5995         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
5996                 anyBoolean());
5997         assertThat(captor.getValue().getNotification().flags
5998                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
5999                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
6000     }
6001 
6002     @Test
testBumpFGImportance_channelChangePreOApp()6003     public void testBumpFGImportance_channelChangePreOApp() throws Exception {
6004         Notification.Builder nb = new Notification.Builder(mContext,
6005                 NotificationChannel.DEFAULT_CHANNEL_ID)
6006                 .setContentTitle("foo")
6007                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6008                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
6009                 .setPriority(Notification.PRIORITY_MIN);
6010 
6011         StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9,
6012                 "testBumpFGImportance_channelChangePreOApp",
6013                 Binder.getCallingUid(), 0, nb.build(),
6014                 UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
6015 
6016         mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
6017                 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
6018         waitForIdle();
6019 
6020         assertEquals(IMPORTANCE_LOW,
6021                 mService.getNotificationRecord(sbn.getKey()).getImportance());
6022         assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance(
6023                 sbn.getPackageName()));
6024 
6025         nb = new Notification.Builder(mContext)
6026                 .setContentTitle("foo")
6027                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6028                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
6029                 .setPriority(Notification.PRIORITY_MIN);
6030 
6031         sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9,
6032                 "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(),
6033                 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
6034 
6035         mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1,
6036                 "testBumpFGImportance_channelChangePreOApp",
6037                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
6038         waitForIdle();
6039         assertEquals(IMPORTANCE_LOW,
6040                 mService.getNotificationRecord(sbn.getKey()).getImportance());
6041 
6042         NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
6043                 PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID);
6044         assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance());
6045     }
6046 
6047     @Test
testStats_updatedOnDirectReply()6048     public void testStats_updatedOnDirectReply() throws Exception {
6049         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6050         mService.addNotification(r);
6051 
6052         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
6053         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied());
6054         verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r));
6055 
6056         assertEquals(1, mNotificationRecordLogger.numCalls());
6057         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
6058                 mNotificationRecordLogger.event(0));
6059     }
6060 
6061     @Test
6062     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate()6063     public void testStats_DirectReplyLifetimeExtendedPostsUpdate() throws Exception {
6064         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6065         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
6066         mService.addNotification(r);
6067 
6068         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
6069         waitForIdle();
6070 
6071         assertThat(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied())
6072                 .isTrue();
6073         // Checks that a post update is sent.
6074         verify(mWorkerHandler, times(1))
6075                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
6076         ArgumentCaptor<NotificationRecord> captor =
6077                 ArgumentCaptor.forClass(NotificationRecord.class);
6078         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
6079                 anyBoolean());
6080         assertThat(captor.getValue().getNotification().flags
6081                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
6082                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
6083         assertThat(captor.getValue().getNotification().flags
6084                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
6085         assertThat(captor.getValue().shouldPostSilently()).isTrue();
6086     }
6087 
6088     @Test
6089     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds()6090     public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception {
6091         // Creates a lifetime extended notification.
6092         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
6093         original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
6094         mService.addNotification(original);
6095 
6096         // Post an update for that notification.
6097         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
6098                 original.getSbn().getTag(), mUid, 0,
6099                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
6100                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
6101                         .setContentTitle("new title").build(),
6102                 UserHandle.getUserHandleForUid(mUid), null, 0);
6103         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6104         mService.addEnqueuedNotification(update);
6105 
6106         NotificationManagerService.PostNotificationRunnable runnable =
6107                 mService.new PostNotificationRunnable(update.getKey(),
6108                         update.getSbn().getPackageName(),
6109                         update.getUid(),
6110                         mPostNotificationTrackerFactory.newTracker(null));
6111         runnable.run();
6112         waitForIdle();
6113 
6114         // Checks the update was sent, and that update contains the new title, and does not contain
6115         // the lifetime extension flag.
6116         ArgumentCaptor<NotificationRecord> captor =
6117                 ArgumentCaptor.forClass(NotificationRecord.class);
6118         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
6119                 anyBoolean());
6120         assertThat(captor.getValue().getNotification().flags
6121                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
6122         assertThat(captor.getValue()
6123                 .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString())
6124                 .isEqualTo("new title");
6125     }
6126 
6127     @Test
testStats_updatedOnUserExpansion()6128     public void testStats_updatedOnUserExpansion() throws Exception {
6129         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6130         mService.addNotification(r);
6131 
6132         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true,
6133                 NOTIFICATION_LOCATION_UNKNOWN);
6134         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
6135                 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true)));
6136         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
6137 
6138         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false,
6139                 NOTIFICATION_LOCATION_UNKNOWN);
6140         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
6141                 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false)));
6142         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
6143 
6144         assertEquals(2, mNotificationRecordLogger.numCalls());
6145         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER,
6146                 mNotificationRecordLogger.event(0));
6147         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER,
6148                 mNotificationRecordLogger.event(1));
6149     }
6150 
6151     @Test
testStats_notUpdatedOnAutoExpansion()6152     public void testStats_notUpdatedOnAutoExpansion() throws Exception {
6153         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6154         mService.addNotification(r);
6155 
6156         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
6157                 NOTIFICATION_LOCATION_UNKNOWN);
6158         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
6159         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
6160                 eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true)));
6161 
6162         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false,
6163                 NOTIFICATION_LOCATION_UNKNOWN);
6164         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
6165         verify(mAssistants).notifyAssistantExpansionChangedLocked(
6166                 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false)));
6167     }
6168 
6169     @Test
testStats_updatedOnViewSettings()6170     public void testStats_updatedOnViewSettings() throws Exception {
6171         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6172         mService.addNotification(r);
6173 
6174         mService.mNotificationDelegate.onNotificationSettingsViewed(r.getKey());
6175         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasViewedSettings());
6176     }
6177 
6178     @Test
testStats_updatedOnVisibilityChanged()6179     public void testStats_updatedOnVisibilityChanged() throws Exception {
6180         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6181         mService.addNotification(r);
6182 
6183         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true);
6184         mService.mNotificationDelegate.onNotificationVisibilityChanged(
6185                 new NotificationVisibility[] {nv}, new NotificationVisibility[]{});
6186         verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true));
6187         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
6188         mService.mNotificationDelegate.onNotificationVisibilityChanged(
6189                 new NotificationVisibility[] {}, new NotificationVisibility[]{nv});
6190         verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false));
6191         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
6192     }
6193 
6194     @Test
testStats_dismissalSurface()6195     public void testStats_dismissalSurface() throws Exception {
6196         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6197         r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6198         mService.addNotification(r);
6199 
6200         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
6201         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(),
6202                 r.getKey(), NotificationStats.DISMISSAL_AOD,
6203                 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv);
6204         waitForIdle();
6205 
6206         assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface());
6207 
6208         // Using mService.addNotification() does not generate a NotificationRecordLogger log,
6209         // so we only get the cancel notification.
6210         assertEquals(1, mNotificationRecordLogger.numCalls());
6211 
6212         assertEquals(
6213                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
6214                 mNotificationRecordLogger.event(0));
6215         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
6216     }
6217 
6218     @Test
testStats_dismissalSentiment()6219     public void testStats_dismissalSentiment() throws Exception {
6220         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6221         mService.addNotification(r);
6222 
6223         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
6224         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(),
6225                 r.getKey(), NotificationStats.DISMISSAL_AOD,
6226                 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv);
6227         waitForIdle();
6228 
6229         assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE,
6230                 r.getStats().getDismissalSentiment());
6231     }
6232 
6233     @Test
testTextChangedSet_forNewNotifs()6234     public void testTextChangedSet_forNewNotifs() throws Exception {
6235         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
6236         mService.addEnqueuedNotification(original);
6237 
6238         NotificationManagerService.PostNotificationRunnable runnable =
6239                 mService.new PostNotificationRunnable(original.getKey(),
6240                         original.getSbn().getPackageName(),
6241                         original.getUid(),
6242                         mPostNotificationTrackerFactory.newTracker(null));
6243         runnable.run();
6244         waitForIdle();
6245 
6246         assertTrue(original.isTextChanged());
6247     }
6248 
6249     @Test
testVisuallyInterruptive_notSeen()6250     public void testVisuallyInterruptive_notSeen() throws Exception {
6251         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
6252         mService.addNotification(original);
6253 
6254         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
6255                 original.getSbn().getTag(), mUid, 0,
6256                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
6257                         .setContentTitle("new title").build(),
6258                 UserHandle.getUserHandleForUid(mUid), null, 0);
6259         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6260         mService.addEnqueuedNotification(update);
6261 
6262         NotificationManagerService.PostNotificationRunnable runnable =
6263                 mService.new PostNotificationRunnable(update.getKey(),
6264                         update.getSbn().getPackageName(),
6265                         update.getUid(),
6266                         mPostNotificationTrackerFactory.newTracker(null));
6267         runnable.run();
6268         waitForIdle();
6269 
6270         assertFalse(update.isInterruptive());
6271     }
6272 
6273     @Test
testApplyAdjustmentMultiUser()6274     public void testApplyAdjustmentMultiUser() throws Exception {
6275         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6276         mService.addNotification(r);
6277         NotificationManagerService.WorkerHandler handler = mock(
6278                 NotificationManagerService.WorkerHandler.class);
6279         mService.setHandler(handler);
6280 
6281         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false);
6282 
6283         Bundle signals = new Bundle();
6284         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
6285                 USER_SENTIMENT_NEGATIVE);
6286         Adjustment adjustment = new Adjustment(
6287                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6288         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
6289 
6290         waitForIdle();
6291 
6292         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
6293     }
6294 
6295     @Test
testAssistantBlockingTriggersCancel()6296     public void testAssistantBlockingTriggersCancel() throws Exception {
6297         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6298         mService.addNotification(r);
6299         NotificationManagerService.WorkerHandler handler = mock(
6300                 NotificationManagerService.WorkerHandler.class);
6301         mService.setHandler(handler);
6302 
6303         Bundle signals = new Bundle();
6304         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE);
6305         Adjustment adjustment = new Adjustment(
6306                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6307         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
6308         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
6309 
6310         waitForIdle();
6311 
6312         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
6313         verify(handler, times(1)).scheduleCancelNotification(any(), eq(0));
6314     }
6315 
6316     @Test
testApplyEnqueuedAdjustmentFromAssistant_singleUser()6317     public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception {
6318         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6319         mService.addEnqueuedNotification(r);
6320         NotificationManagerService.WorkerHandler handler = mock(
6321                 NotificationManagerService.WorkerHandler.class);
6322         mService.setHandler(handler);
6323         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6324 
6325         Bundle signals = new Bundle();
6326         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
6327                 USER_SENTIMENT_NEGATIVE);
6328         Adjustment adjustment = new Adjustment(
6329                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6330         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
6331 
6332         assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
6333     }
6334 
6335     @Test
testApplyEnqueuedAdjustmentFromAssistant_importance()6336     public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception {
6337         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6338         mService.addEnqueuedNotification(r);
6339         NotificationManagerService.WorkerHandler handler = mock(
6340                 NotificationManagerService.WorkerHandler.class);
6341         mService.setHandler(handler);
6342         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6343 
6344         Bundle signals = new Bundle();
6345         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
6346         Adjustment adjustment = new Adjustment(
6347                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6348         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
6349 
6350         assertEquals(IMPORTANCE_LOW, r.getImportance());
6351     }
6352 
6353     @Test
testApplyEnqueuedAdjustmentFromAssistant_crossUser()6354     public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception {
6355         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6356         mService.addEnqueuedNotification(r);
6357         NotificationManagerService.WorkerHandler handler = mock(
6358                 NotificationManagerService.WorkerHandler.class);
6359         mService.setHandler(handler);
6360         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false);
6361 
6362         Bundle signals = new Bundle();
6363         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
6364                 USER_SENTIMENT_NEGATIVE);
6365         Adjustment adjustment = new Adjustment(
6366                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6367         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
6368 
6369         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
6370 
6371         waitForIdle();
6372 
6373         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
6374     }
6375 
6376     @Test
testUserSentimentChangeTriggersUpdate()6377     public void testUserSentimentChangeTriggersUpdate() throws Exception {
6378         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6379         mService.addNotification(r);
6380         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6381 
6382         Bundle signals = new Bundle();
6383         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
6384                 USER_SENTIMENT_NEGATIVE);
6385         Adjustment adjustment = new Adjustment(
6386                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6387         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
6388 
6389         waitForIdle();
6390 
6391         verify(mRankingHandler, timeout(300).times(1)).requestSort();
6392     }
6393 
6394     @Test
testTooLateAdjustmentTriggersUpdate()6395     public void testTooLateAdjustmentTriggersUpdate() throws Exception {
6396         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6397         mService.addNotification(r);
6398         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6399 
6400         Bundle signals = new Bundle();
6401         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
6402                 USER_SENTIMENT_NEGATIVE);
6403         Adjustment adjustment = new Adjustment(
6404                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6405         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
6406 
6407         waitForIdle();
6408 
6409         verify(mRankingHandler, times(1)).requestSort();
6410     }
6411 
6412     @Test
testApplyAdjustmentsLogged()6413     public void testApplyAdjustmentsLogged() throws Exception {
6414         NotificationManagerService.WorkerHandler handler = mock(
6415                 NotificationManagerService.WorkerHandler.class);
6416         mService.setHandler(handler);
6417         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6418 
6419         // Set up notifications that will be adjusted
6420         final NotificationRecord r1 = generateNotificationRecord(
6421                 mTestNotificationChannel, 1, null, true);
6422         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6423         mService.addNotification(r1);
6424         final NotificationRecord r2 = generateNotificationRecord(
6425                 mTestNotificationChannel, 2, null, true);
6426         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6427         mService.addNotification(r2);
6428 
6429         // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously
6430         // logged.
6431         final NotificationRecord r3 = generateNotificationRecord(
6432                 mTestNotificationChannel, 3, null, true);
6433         r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6434         mService.addNotification(r3);
6435 
6436         List<Adjustment> adjustments = new ArrayList<>();
6437 
6438         // Test an adjustment that's associated with a ranking change and one that's not
6439         Bundle signals1 = new Bundle();
6440         signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH);
6441         Adjustment adjustment1 = new Adjustment(
6442                 r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
6443                 r1.getUser().getIdentifier());
6444         adjustments.add(adjustment1);
6445 
6446         // This one wouldn't trigger a ranking change, but should still trigger a log.
6447         Bundle signals2 = new Bundle();
6448         signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f);
6449         Adjustment adjustment2 = new Adjustment(
6450                 r2.getSbn().getPackageName(), r2.getKey(), signals2, "",
6451                 r2.getUser().getIdentifier());
6452         adjustments.add(adjustment2);
6453 
6454         mBinderService.applyAdjustmentsFromAssistant(null, adjustments);
6455         verify(mRankingHandler, times(1)).requestSort();
6456 
6457         // Actually apply the adjustments & recalculate importance when run
6458         doAnswer(invocationOnMock -> {
6459             ((NotificationRecord) invocationOnMock.getArguments()[0])
6460                     .applyAdjustments();
6461             ((NotificationRecord) invocationOnMock.getArguments()[0])
6462                     .calculateImportance();
6463             return null;
6464         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
6465 
6466         // Now make sure that when the sort happens, we actually log the changes.
6467         mService.handleRankingSort();
6468 
6469         // Even though the ranking score change is not meant to trigger a ranking update,
6470         // during this process the package visibility & canShowBadge values are changing
6471         // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead
6472         // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed
6473         // accordingly to confirm the adjustments happened to the 2 relevant notifications.
6474         verify(handler, times(3)).scheduleSendRankingUpdate();
6475         assertEquals(IMPORTANCE_HIGH, r1.getImportance());
6476         assertTrue(r2.rankingScoreMatches(-0.5f));
6477         assertEquals(2, mNotificationRecordLogger.numCalls());
6478         assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(0));
6479         assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(1));
6480         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
6481         assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId());
6482     }
6483 
6484     @Test
testSensitiveAdjustmentsLogged()6485     public void testSensitiveAdjustmentsLogged() throws Exception {
6486         NotificationManagerService.WorkerHandler handler = mock(
6487                 NotificationManagerService.WorkerHandler.class);
6488         mService.setHandler(handler);
6489         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
6490         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
6491 
6492         // Set up notifications that will be adjusted
6493         final NotificationRecord r1 = spy(generateNotificationRecord(
6494                 mTestNotificationChannel, 1, null, true));
6495         when(r1.getLifespanMs(anyLong())).thenReturn(1);
6496 
6497         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6498         mService.addEnqueuedNotification(r1);
6499 
6500         // Test an adjustment for an enqueued notification
6501         Bundle signals = new Bundle();
6502         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true);
6503         Adjustment adjustment1 = new Adjustment(
6504                 r1.getSbn().getPackageName(), r1.getKey(), signals, "",
6505                 r1.getUser().getIdentifier());
6506         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1);
6507         assertTrue(mService.checkLastSensitiveLog(false, true, 1));
6508 
6509         // Set up notifications that will be adjusted
6510         final NotificationRecord r2 = spy(generateNotificationRecord(
6511                 mTestNotificationChannel, 1, null, true));
6512         when(r2.getLifespanMs(anyLong())).thenReturn(2);
6513 
6514         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6515         mService.addNotification(r2);
6516         Adjustment adjustment2 = new Adjustment(
6517                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
6518                 r2.getUser().getIdentifier());
6519         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2);
6520         assertTrue(mService.checkLastSensitiveLog(true, true, 2));
6521 
6522         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, false);
6523         Adjustment adjustment3 = new Adjustment(
6524                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
6525                 r2.getUser().getIdentifier());
6526         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3);
6527         assertTrue(mService.checkLastSensitiveLog(true, false, 2));
6528     }
6529 
6530     @Test
testAdjustmentToImportanceNone_cancelsNotification()6531     public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception {
6532         NotificationManagerService.WorkerHandler handler = mock(
6533                 NotificationManagerService.WorkerHandler.class);
6534         mService.setHandler(handler);
6535         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6536         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
6537 
6538         // Set up notifications: r1 is adjusted, r2 is not
6539         final NotificationRecord r1 = generateNotificationRecord(
6540                 mTestNotificationChannel, 1, null, true);
6541         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6542         mService.addNotification(r1);
6543         final NotificationRecord r2 = generateNotificationRecord(
6544                 mTestNotificationChannel, 2, null, true);
6545         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
6546         mService.addNotification(r2);
6547 
6548         // Test an adjustment that sets importance to none (meaning it's cancelling)
6549         Bundle signals1 = new Bundle();
6550         signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
6551         Adjustment adjustment1 = new Adjustment(
6552                 r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
6553                 r1.getUser().getIdentifier());
6554 
6555         mBinderService.applyAdjustmentFromAssistant(null, adjustment1);
6556 
6557         // Actually apply the adjustments & recalculate importance when run
6558         doAnswer(invocationOnMock -> {
6559             ((NotificationRecord) invocationOnMock.getArguments()[0])
6560                     .applyAdjustments();
6561             ((NotificationRecord) invocationOnMock.getArguments()[0])
6562                     .calculateImportance();
6563             return null;
6564         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
6565 
6566         // run the CancelNotificationRunnable when it happens
6567         ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor =
6568                 ArgumentCaptor.forClass(
6569                         NotificationManagerService.CancelNotificationRunnable.class);
6570 
6571         verify(handler, times(1)).scheduleCancelNotification(
6572                 captor.capture(), eq(0));
6573 
6574         // Run the runnable given to the cancel notification, and see if it logs properly
6575         NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue();
6576         runnable.run();
6577         assertEquals(1, mNotificationRecordLogger.numCalls());
6578         assertEquals(
6579                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT,
6580                 mNotificationRecordLogger.event(0));
6581     }
6582 
6583     @Test
testEnqueuedAdjustmentAppliesAdjustments()6584     public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
6585         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6586         mService.addEnqueuedNotification(r);
6587         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6588 
6589         Bundle signals = new Bundle();
6590         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
6591                 USER_SENTIMENT_NEGATIVE);
6592         Adjustment adjustment = new Adjustment(
6593                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
6594         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
6595 
6596         assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
6597     }
6598 
6599     @Test
testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications()6600     public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception {
6601         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel);
6602         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel);
6603         mService.addEnqueuedNotification(r1);
6604         mService.addEnqueuedNotification(r2);
6605         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
6606 
6607         Bundle signals = new Bundle();
6608         signals.putInt(Adjustment.KEY_IMPORTANCE,
6609                 IMPORTANCE_HIGH);
6610         Adjustment adjustment = new Adjustment(
6611                 r1.getSbn().getPackageName(), r1.getKey(), signals,
6612                 "", r1.getUser().getIdentifier());
6613 
6614         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
6615 
6616         assertEquals(IMPORTANCE_HIGH, r1.getImportance());
6617         assertEquals(IMPORTANCE_HIGH, r2.getImportance());
6618     }
6619 
6620     @Test
testRestore()6621     public void testRestore() throws Exception {
6622         int systemChecks = mService.countSystemChecks;
6623         mBinderService.applyRestore(null, USER_SYSTEM);
6624         assertEquals(1, mService.countSystemChecks - systemChecks);
6625     }
6626 
6627     @Test
testBackupEmptySound()6628     public void testBackupEmptySound() throws Exception {
6629         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
6630         channel.setSound(Uri.EMPTY, null);
6631 
6632         TypedXmlSerializer serializer = Xml.newFastSerializer();
6633         ByteArrayOutputStream baos = new ByteArrayOutputStream();
6634         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
6635         channel.writeXmlForBackup(serializer, getContext());
6636 
6637         TypedXmlPullParser parser = Xml.newFastPullParser();
6638         parser.setInput(new BufferedInputStream(
6639                 new ByteArrayInputStream(baos.toByteArray())), null);
6640         NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
6641         restored.populateFromXmlForRestore(parser, true, getContext());
6642 
6643         assertNull(restored.getSound());
6644     }
6645 
6646     @Test
testBackup()6647     public void testBackup() throws Exception {
6648         mService.setPreferencesHelper(mPreferencesHelper);
6649         int systemChecks = mService.countSystemChecks;
6650         when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
6651                 .thenReturn(new ArraySet<>());
6652         mBinderService.getBackupPayload(1);
6653         assertEquals(1, mService.countSystemChecks - systemChecks);
6654     }
6655 
6656     @Test
testEmptyVibration_noException()6657     public void testEmptyVibration_noException() throws Exception {
6658         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
6659         channel.setVibrationPattern(new long[0]);
6660 
6661         TypedXmlSerializer serializer = Xml.newFastSerializer();
6662         ByteArrayOutputStream baos = new ByteArrayOutputStream();
6663         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
6664         channel.writeXml(serializer);
6665     }
6666 
6667     @Test
updateUriPermissions_update()6668     public void updateUriPermissions_update() throws Exception {
6669         NotificationChannel c = new NotificationChannel(
6670                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
6671         c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
6672         Message message1 = new Message("", 0, "");
6673         message1.setData("",
6674                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1));
6675         Message message2 = new Message("", 1, "");
6676         message2.setData("",
6677                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2));
6678 
6679         Notification.Builder nbA = new Notification.Builder(mContext, c.getId())
6680                 .setContentTitle("foo")
6681                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6682                 .setStyle(new Notification.MessagingStyle("")
6683                         .addMessage(message1)
6684                         .addMessage(message2));
6685         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
6686                 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
6687                 null, 0), c);
6688 
6689         // First post means we grant access to both
6690         reset(mUgm);
6691         reset(mUgmInternal);
6692         when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
6693         mService.updateUriPermissions(recordA, null, mContext.getPackageName(),
6694                 USER_SYSTEM);
6695         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
6696                 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
6697         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
6698                 eq(message2.getDataUri()), anyInt(), anyInt(), anyInt());
6699 
6700         Notification.Builder nbB = new Notification.Builder(mContext, c.getId())
6701                 .setContentTitle("foo")
6702                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6703                 .setStyle(new Notification.MessagingStyle("").addMessage(message2));
6704         NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(mPkg,
6705                 mPkg, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0),
6706                 c);
6707 
6708         // Update means we drop access to first
6709         reset(mUgmInternal);
6710         mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(),
6711                 USER_SYSTEM);
6712         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(),
6713                 eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1));
6714 
6715         // Update back means we grant access to first again
6716         reset(mUgm);
6717         mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(),
6718                 USER_SYSTEM);
6719         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
6720                 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
6721 
6722         // And update to empty means we drop everything
6723         reset(mUgmInternal);
6724         mService.updateUriPermissions(null, recordB, mContext.getPackageName(),
6725                 USER_SYSTEM);
6726         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null),
6727                 anyInt(), anyInt());
6728     }
6729 
6730     @Test
updateUriPermissions_posterDoesNotOwnUri()6731     public void updateUriPermissions_posterDoesNotOwnUri() throws Exception {
6732         NotificationChannel c = new NotificationChannel(
6733                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
6734         c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
6735         Message message1 = new Message("", 0, "");
6736         message1.setData("",
6737                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1));
6738 
6739         Notification.Builder nbA = new Notification.Builder(mContext, c.getId())
6740                 .setContentTitle("foo")
6741                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6742                 .setStyle(new Notification.MessagingStyle("")
6743                         .addMessage(message1));
6744         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
6745                 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
6746                 null, 0), c);
6747 
6748         doThrow(new SecurityException("no access")).when(mUgm)
6749                 .grantUriPermissionFromOwner(
6750                         any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt());
6751 
6752         when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
6753         mService.updateUriPermissions(recordA, null, mContext.getPackageName(),  USER_SYSTEM);
6754 
6755         // yay, no crash
6756     }
6757 
6758     @Test
testVisitUris()6759     public void testVisitUris() throws Exception {
6760         final Uri audioContents = Uri.parse("content://com.example/audio");
6761         final Uri backgroundImage = Uri.parse("content://com.example/background");
6762         final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon");
6763         final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon");
6764         final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
6765         final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
6766         final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
6767         final Person person1 = new Person.Builder()
6768                 .setName("Messaging Person")
6769                 .setIcon(personIcon1)
6770                 .build();
6771         final Person person2 = new Person.Builder()
6772                 .setName("People List Person 1")
6773                 .setIcon(personIcon2)
6774                 .build();
6775         final Person person3 = new Person.Builder()
6776                 .setName("People List Person 2")
6777                 .setIcon(personIcon3)
6778                 .build();
6779         final Uri historyUri1 = Uri.parse("content://com.example/history1");
6780         final Uri historyUri2 = Uri.parse("content://com.example/history2");
6781         final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1,
6782                 "a");
6783         final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2,
6784                 "b");
6785 
6786         Bundle extras = new Bundle();
6787         extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents);
6788         extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString());
6789         extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1);
6790         extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST,
6791                 new ArrayList<>(Arrays.asList(person2, person3)));
6792         extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
6793                 new RemoteInputHistoryItem[]{historyItem1, historyItem2});
6794 
6795         Notification n = new Notification.Builder(mContext, "a")
6796                 .setContentTitle("notification with uris")
6797                 .setSmallIcon(smallIcon)
6798                 .setLargeIcon(largeIcon)
6799                 .addExtras(extras)
6800                 .build();
6801 
6802         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6803         n.visitUris(visitor);
6804         verify(visitor, times(1)).accept(eq(audioContents));
6805         verify(visitor, times(1)).accept(eq(backgroundImage));
6806         verify(visitor, times(1)).accept(eq(smallIcon.getUri()));
6807         verify(visitor, times(1)).accept(eq(largeIcon.getUri()));
6808         verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
6809         verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
6810         verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
6811         verify(visitor, times(1)).accept(eq(historyUri1));
6812         verify(visitor, times(1)).accept(eq(historyUri2));
6813     }
6814 
6815     @Test
testVisitUris_publicVersion()6816     public void testVisitUris_publicVersion() throws Exception {
6817         final Icon smallIconPublic = Icon.createWithContentUri("content://media/small/icon");
6818         final Icon largeIconPrivate = Icon.createWithContentUri("content://media/large/icon");
6819 
6820         Notification publicVersion = new Notification.Builder(mContext, "a")
6821                 .setContentTitle("notification with uris")
6822                 .setSmallIcon(smallIconPublic)
6823                 .build();
6824         Notification n = new Notification.Builder(mContext, "a")
6825                 .setLargeIcon(largeIconPrivate)
6826                 .setPublicVersion(publicVersion)
6827                 .build();
6828 
6829         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6830         n.visitUris(visitor);
6831         verify(visitor, times(1)).accept(eq(smallIconPublic.getUri()));
6832         verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri()));
6833     }
6834 
6835     @Test
testVisitUris_audioContentsString()6836     public void testVisitUris_audioContentsString() throws Exception {
6837         final Uri audioContents = Uri.parse("content://com.example/audio");
6838 
6839         Bundle extras = new Bundle();
6840         extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString());
6841 
6842         Notification n = new Notification.Builder(mContext, "a")
6843                 .setContentTitle("notification with uris")
6844                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6845                 .addExtras(extras)
6846                 .build();
6847 
6848         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6849         n.visitUris(visitor);
6850         verify(visitor, times(1)).accept(eq(audioContents));
6851     }
6852 
6853     @Test
testVisitUris_messagingStyle()6854     public void testVisitUris_messagingStyle() {
6855         final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
6856         final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
6857         final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
6858         final Person person1 = new Person.Builder()
6859                 .setName("Messaging Person 1")
6860                 .setIcon(personIcon1)
6861                 .build();
6862         final Person person2 = new Person.Builder()
6863                 .setName("Messaging Person 2")
6864                 .setIcon(personIcon2)
6865                 .build();
6866         final Person person3 = new Person.Builder()
6867                 .setName("Messaging Person 3")
6868                 .setIcon(personIcon3)
6869                 .build();
6870         Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut");
6871 
6872         Notification.Builder builder = new Notification.Builder(mContext, "a")
6873                 .setCategory(Notification.CATEGORY_MESSAGE)
6874                 .setContentTitle("new message!")
6875                 .setContentText("Conversation Notification")
6876                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
6877         Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message(
6878                 "Marco?", System.currentTimeMillis(), person2);
6879         Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message(
6880                 "Polo!", System.currentTimeMillis(), person3);
6881         Notification.MessagingStyle style = new Notification.MessagingStyle(person1)
6882                 .addMessage(message1)
6883                 .addMessage(message2)
6884                 .setShortcutIcon(shortcutIcon);
6885         builder.setStyle(style);
6886         Notification n = builder.build();
6887 
6888         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6889         n.visitUris(visitor);
6890 
6891         verify(visitor, times(1)).accept(eq(shortcutIcon.getUri()));
6892         verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
6893         verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
6894         verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
6895     }
6896 
6897     @Test
testVisitUris_callStyle()6898     public void testVisitUris_callStyle() {
6899         Icon personIcon = Icon.createWithContentUri("content://media/person");
6900         Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
6901         Person callingPerson = new Person.Builder().setName("Someone")
6902                 .setIcon(personIcon)
6903                 .build();
6904         PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
6905                 PendingIntent.FLAG_IMMUTABLE);
6906         Notification n = new Notification.Builder(mContext, "a")
6907                 .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
6908                         .setVerificationIcon(verificationIcon))
6909                 .setContentTitle("Calling...")
6910                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6911                 .build();
6912 
6913         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6914         n.visitUris(visitor);
6915 
6916         verify(visitor, times(1)).accept(eq(personIcon.getUri()));
6917         verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
6918         hangUpIntent.cancel();
6919     }
6920 
6921     @Test
testVisitUris_styleExtrasWithoutStyle()6922     public void testVisitUris_styleExtrasWithoutStyle() {
6923         Notification.Builder notification = new Notification.Builder(mContext, "a")
6924                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
6925 
6926         Bundle messagingExtras = new Bundle();
6927         messagingExtras.putParcelable(Notification.EXTRA_MESSAGING_PERSON,
6928                 personWithIcon("content://user"));
6929         messagingExtras.putParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES,
6930                 new Bundle[] { new Notification.MessagingStyle.Message("Heyhey!",
6931                         System.currentTimeMillis() - 100,
6932                         personWithIcon("content://historicalMessenger")).toBundle()});
6933         messagingExtras.putParcelableArray(Notification.EXTRA_MESSAGES,
6934                 new Bundle[] { new Notification.MessagingStyle.Message("Are you there?",
6935                         System.currentTimeMillis(),
6936                         personWithIcon("content://messenger")).toBundle()});
6937         messagingExtras.putParcelable(Notification.EXTRA_CONVERSATION_ICON,
6938                 Icon.createWithContentUri("content://conversationShortcut"));
6939         notification.addExtras(messagingExtras);
6940 
6941         Bundle callExtras = new Bundle();
6942         callExtras.putParcelable(Notification.EXTRA_CALL_PERSON,
6943                 personWithIcon("content://caller"));
6944         callExtras.putParcelable(Notification.EXTRA_VERIFICATION_ICON,
6945                 Icon.createWithContentUri("content://callVerification"));
6946         notification.addExtras(callExtras);
6947 
6948         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6949         notification.build().visitUris(visitor);
6950 
6951         verify(visitor).accept(eq(Uri.parse("content://user")));
6952         verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
6953         verify(visitor).accept(eq(Uri.parse("content://messenger")));
6954         verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
6955         verify(visitor).accept(eq(Uri.parse("content://caller")));
6956         verify(visitor).accept(eq(Uri.parse("content://callVerification")));
6957     }
6958 
personWithIcon(String iconUri)6959     private static Person personWithIcon(String iconUri) {
6960         return new Person.Builder()
6961                 .setName("Mr " + iconUri)
6962                 .setIcon(Icon.createWithContentUri(iconUri))
6963                 .build();
6964     }
6965 
6966     @Test
testVisitUris_wearableExtender()6967     public void testVisitUris_wearableExtender() {
6968         Icon actionIcon = Icon.createWithContentUri("content://media/action");
6969         Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
6970         PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
6971                 PendingIntent.FLAG_IMMUTABLE);
6972         Notification n = new Notification.Builder(mContext, "a")
6973                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6974                 .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
6975                 .extend(new Notification.WearableExtender().addAction(
6976                         new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
6977                 .build();
6978 
6979         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
6980         n.visitUris(visitor);
6981 
6982         verify(visitor).accept(eq(actionIcon.getUri()));
6983         verify(visitor).accept(eq(wearActionIcon.getUri()));
6984     }
6985 
6986     @Test
testSetNotificationPolicy_preP_setOldFields()6987     public void testSetNotificationPolicy_preP_setOldFields() {
6988         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
6989         mService.mZenModeHelper = mZenModeHelper;
6990         NotificationManager.Policy userPolicy =
6991                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
6992         when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
6993 
6994         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
6995                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
6996 
6997         int expected = SUPPRESSED_EFFECT_BADGE
6998                 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
6999                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS
7000                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
7001         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
7002 
7003         assertEquals(expected, actual);
7004     }
7005 
7006     @Test
testSetNotificationPolicy_preP_setNewFields()7007     public void testSetNotificationPolicy_preP_setNewFields() {
7008         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
7009         mService.mZenModeHelper = mZenModeHelper;
7010         NotificationManager.Policy userPolicy =
7011                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
7012         when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
7013 
7014         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
7015                 SUPPRESSED_EFFECT_NOTIFICATION_LIST);
7016 
7017         int expected = SUPPRESSED_EFFECT_BADGE;
7018         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
7019 
7020         assertEquals(expected, actual);
7021     }
7022 
7023     @Test
testSetNotificationPolicy_preP_setOldNewFields()7024     public void testSetNotificationPolicy_preP_setOldNewFields() {
7025         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
7026         mService.mZenModeHelper = mZenModeHelper;
7027         NotificationManager.Policy userPolicy =
7028                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
7029         when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
7030 
7031         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
7032                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
7033 
7034         int expected =
7035                 SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
7036         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
7037 
7038         assertEquals(expected, actual);
7039     }
7040 
7041     @Test
testSetNotificationPolicy_P_setOldFields()7042     public void testSetNotificationPolicy_P_setOldFields() {
7043         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
7044         mService.mZenModeHelper = mZenModeHelper;
7045         NotificationManager.Policy userPolicy =
7046                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
7047         when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
7048 
7049         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
7050                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
7051 
7052         int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
7053                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
7054                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
7055         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
7056 
7057         assertEquals(expected, actual);
7058     }
7059 
7060     @Test
testSetNotificationPolicy_P_setNewFields()7061     public void testSetNotificationPolicy_P_setNewFields() {
7062         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
7063         mService.mZenModeHelper = mZenModeHelper;
7064         NotificationManager.Policy userPolicy =
7065                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
7066         when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
7067 
7068         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
7069                 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
7070                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
7071 
7072         int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
7073                 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
7074                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
7075         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
7076 
7077         assertEquals(expected, actual);
7078     }
7079 
7080     @Test
testSetNotificationPolicy_P_setOldNewFields()7081     public void testSetNotificationPolicy_P_setOldNewFields() {
7082         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
7083         mService.mZenModeHelper = mZenModeHelper;
7084         NotificationManager.Policy userPolicy =
7085                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
7086         when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
7087 
7088         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
7089                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
7090 
7091         int expected =  SUPPRESSED_EFFECT_STATUS_BAR;
7092         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
7093 
7094         assertEquals(expected, actual);
7095 
7096         appPolicy = new NotificationManager.Policy(0, 0, 0,
7097                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
7098                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
7099 
7100         expected =  SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
7101                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
7102         actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
7103 
7104         assertEquals(expected, actual);
7105     }
7106 
7107     @Test
testVisualDifference_foreground()7108     public void testVisualDifference_foreground() {
7109         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7110                 .setContentTitle("foo");
7111         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7112                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7113         NotificationRecord r1 =
7114                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7115 
7116         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7117                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
7118                 .setContentTitle("bar");
7119         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7120                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7121         NotificationRecord r2 =
7122                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7123 
7124         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7125     }
7126 
7127     @Test
testVisualDifference_diffTitle()7128     public void testVisualDifference_diffTitle() {
7129         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7130                 .setContentTitle("foo");
7131         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7132                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7133         NotificationRecord r1 =
7134                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7135 
7136         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7137                 .setContentTitle("bar");
7138         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7139                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7140         NotificationRecord r2 =
7141                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7142 
7143         assertTrue(mService.isVisuallyInterruptive(r1, r2));
7144     }
7145 
7146     @Test
testVisualDifference_inboxStyle()7147     public void testVisualDifference_inboxStyle() {
7148         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7149                 .setStyle(new Notification.InboxStyle()
7150                     .addLine("line1").addLine("line2"));
7151         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7152                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7153         NotificationRecord r1 =
7154                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7155 
7156         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7157                 .setStyle(new Notification.InboxStyle()
7158                         .addLine("line1").addLine("line2_changed"));
7159         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7160                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7161         NotificationRecord r2 =
7162                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7163 
7164         assertTrue(mService.isVisuallyInterruptive(r1, r2)); // line 2 changed unnoticed
7165 
7166         Notification.Builder nb3 = new Notification.Builder(mContext, "")
7167                 .setStyle(new Notification.InboxStyle()
7168                         .addLine("line1"));
7169         StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7170                 nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7171         NotificationRecord r3 =
7172                 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class));
7173 
7174         assertTrue(mService.isVisuallyInterruptive(r1, r3)); // line 2 removed unnoticed
7175 
7176         Notification.Builder nb4 = new Notification.Builder(mContext, "")
7177                 .setStyle(new Notification.InboxStyle()
7178                         .addLine("line1").addLine("line2").addLine("line3"));
7179         StatusBarNotification sbn4 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7180                 nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7181         NotificationRecord r4 =
7182                 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class));
7183 
7184         assertTrue(mService.isVisuallyInterruptive(r1, r4)); // line 3 added unnoticed
7185 
7186         Notification.Builder nb5 = new Notification.Builder(mContext, "")
7187             .setContentText("not an inbox");
7188         StatusBarNotification sbn5 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7189                 nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7190         NotificationRecord r5 =
7191                 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class));
7192 
7193         assertTrue(mService.isVisuallyInterruptive(r1, r5)); // changed Styles, went unnoticed
7194     }
7195 
7196     @Test
testVisualDifference_diffText()7197     public void testVisualDifference_diffText() {
7198         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7199                 .setContentText("foo");
7200         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7201                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7202         NotificationRecord r1 =
7203                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7204 
7205         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7206                 .setContentText("bar");
7207         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7208                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7209         NotificationRecord r2 =
7210                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7211 
7212         assertTrue(mService.isVisuallyInterruptive(r1, r2));
7213     }
7214 
7215     @Test
testVisualDifference_sameText()7216     public void testVisualDifference_sameText() {
7217         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7218                 .setContentText("foo");
7219         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7220                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7221         NotificationRecord r1 =
7222                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7223 
7224         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7225                 .setContentText("foo");
7226         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7227                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7228         NotificationRecord r2 =
7229                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7230 
7231         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7232     }
7233 
7234     @Test
testVisualDifference_sameTextButStyled()7235     public void testVisualDifference_sameTextButStyled() {
7236         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7237                 .setContentText(Html.fromHtml("<b>foo</b>"));
7238         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7239                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7240         NotificationRecord r1 =
7241                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7242 
7243         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7244                 .setContentText(Html.fromHtml("<b>foo</b>"));
7245         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7246                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7247         NotificationRecord r2 =
7248                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7249 
7250         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7251     }
7252 
7253     @Test
testVisualDifference_diffTextButStyled()7254     public void testVisualDifference_diffTextButStyled() {
7255         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7256                 .setContentText(Html.fromHtml("<b>foo</b>"));
7257         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7258                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7259         NotificationRecord r1 =
7260                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7261 
7262         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7263                 .setContentText(Html.fromHtml("<b>bar</b>"));
7264         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7265                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7266         NotificationRecord r2 =
7267                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7268 
7269         assertTrue(mService.isVisuallyInterruptive(r1, r2));
7270     }
7271 
7272     @Test
testVisualDifference_diffProgress()7273     public void testVisualDifference_diffProgress() {
7274         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7275                 .setProgress(100, 90, false);
7276         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7277                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7278         NotificationRecord r1 =
7279                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7280 
7281         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7282                 .setProgress(100, 100, false);
7283         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7284                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7285         NotificationRecord r2 =
7286                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7287 
7288         assertTrue(mService.isVisuallyInterruptive(r1, r2));
7289     }
7290 
7291     @Test
testVisualDifference_diffProgressNotDone()7292     public void testVisualDifference_diffProgressNotDone() {
7293         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7294                 .setProgress(100, 90, false);
7295         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7296                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7297         NotificationRecord r1 =
7298                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7299 
7300         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7301                 .setProgress(100, 91, false);
7302         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7303                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7304         NotificationRecord r2 =
7305                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7306 
7307         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7308     }
7309 
7310     @Test
testVisualDifference_sameProgressStillDone()7311     public void testVisualDifference_sameProgressStillDone() {
7312         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7313                 .setProgress(100, 100, false);
7314         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7315                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7316         NotificationRecord r1 =
7317                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7318 
7319         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7320                 .setProgress(100, 100, false);
7321         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7322                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7323         NotificationRecord r2 =
7324                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7325 
7326         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7327     }
7328 
7329     @Test
testVisualDifference_summary()7330     public void testVisualDifference_summary() {
7331         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7332                 .setGroup("bananas")
7333                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
7334                 .setContentText("foo");
7335         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7336                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7337         NotificationRecord r1 =
7338                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7339 
7340         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7341                 .setGroup("bananas")
7342                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
7343                 .setContentText("bar");
7344         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7345                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7346         NotificationRecord r2 =
7347                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7348 
7349         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7350     }
7351 
7352     @Test
testVisualDifference_summaryNewNotification()7353     public void testVisualDifference_summaryNewNotification() {
7354         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7355                 .setGroup("bananas")
7356                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
7357                 .setContentText("bar");
7358         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7359                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7360         NotificationRecord r2 =
7361                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7362 
7363         assertFalse(mService.isVisuallyInterruptive(null, r2));
7364     }
7365 
7366     @Test
testVisualDifference_sameImages()7367     public void testVisualDifference_sameImages() {
7368         Icon large = Icon.createWithResource(mContext, 1);
7369         Notification n1 = new Notification.Builder(mContext, "channel")
7370                 .setSmallIcon(1).setLargeIcon(large).build();
7371         Notification n2 = new Notification.Builder(mContext, "channel")
7372                 .setSmallIcon(1).setLargeIcon(large).build();
7373 
7374         NotificationRecord r1 = notificationToRecord(n1);
7375         NotificationRecord r2 = notificationToRecord(n2);
7376 
7377         assertThat(mService.isVisuallyInterruptive(r1, r2)).isFalse();
7378     }
7379 
7380     @Test
testVisualDifference_differentSmallImage()7381     public void testVisualDifference_differentSmallImage() {
7382         Icon large = Icon.createWithResource(mContext, 1);
7383         Notification n1 = new Notification.Builder(mContext, "channel")
7384                 .setSmallIcon(1).setLargeIcon(large).build();
7385         Notification n2 = new Notification.Builder(mContext, "channel")
7386                 .setSmallIcon(2).setLargeIcon(large).build();
7387 
7388         NotificationRecord r1 = notificationToRecord(n1);
7389         NotificationRecord r2 = notificationToRecord(n2);
7390 
7391         assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue();
7392     }
7393 
7394     @Test
testVisualDifference_differentLargeImage()7395     public void testVisualDifference_differentLargeImage() {
7396         Icon large1 = Icon.createWithResource(mContext, 1);
7397         Icon large2 = Icon.createWithResource(mContext, 2);
7398         Notification n1 = new Notification.Builder(mContext, "channel")
7399                 .setSmallIcon(1).setLargeIcon(large1).build();
7400         Notification n2 = new Notification.Builder(mContext, "channel")
7401                 .setSmallIcon(1).setLargeIcon(large2).build();
7402 
7403         NotificationRecord r1 = notificationToRecord(n1);
7404         NotificationRecord r2 = notificationToRecord(n2);
7405 
7406         assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue();
7407     }
7408 
7409     @Test
7410     @EnableFlags({android.app.Flags.FLAG_SORT_SECTION_BY_TIME})
testVisualDifference_userInitiatedJob()7411     public void testVisualDifference_userInitiatedJob() {
7412         Notification.Builder nb1 = new Notification.Builder(mContext, "")
7413                 .setContentTitle("foo");
7414         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7415                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7416         NotificationRecord r1 =
7417                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
7418 
7419         Notification.Builder nb2 = new Notification.Builder(mContext, "")
7420                 .setFlag(FLAG_USER_INITIATED_JOB, true)
7421                 .setContentTitle("bar");
7422         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
7423                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
7424         NotificationRecord r2 =
7425                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
7426 
7427         assertFalse(mService.isVisuallyInterruptive(r1, r2));
7428     }
7429 
notificationToRecord(Notification n)7430     private NotificationRecord notificationToRecord(Notification n) {
7431         return new NotificationRecord(
7432                 mContext,
7433                 new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, n,
7434                         UserHandle.getUserHandleForUid(mUid), null, 0),
7435                 mock(NotificationChannel.class));
7436     }
7437 
7438     @Test
testHideAndUnhideNotificationsOnSuspendedPackageBroadcast()7439     public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
7440         // post 2 notification from this package
7441         final NotificationRecord notif1 = generateNotificationRecord(
7442                 mTestNotificationChannel, 1, null, true);
7443         final NotificationRecord notif2 = generateNotificationRecord(
7444                 mTestNotificationChannel, 2, null, false);
7445         mService.addNotification(notif1);
7446         mService.addNotification(notif2);
7447 
7448         // on broadcast, hide the 2 notifications
7449         simulatePackageSuspendBroadcast(true, mPkg, notif1.getUid());
7450         ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class);
7451         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
7452         assertEquals(2, captorHide.getValue().size());
7453 
7454         // on broadcast, unhide the 2 notifications
7455         simulatePackageSuspendBroadcast(false, mPkg, notif1.getUid());
7456         ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class);
7457         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
7458         assertEquals(2, captorUnhide.getValue().size());
7459     }
7460 
7461     @Test
testNoNotificationsHiddenOnSuspendedPackageBroadcast()7462     public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() {
7463         // post 2 notification from this package
7464         final NotificationRecord notif1 = generateNotificationRecord(
7465                 mTestNotificationChannel, 1, null, true);
7466         final NotificationRecord notif2 = generateNotificationRecord(
7467                 mTestNotificationChannel, 2, null, false);
7468         mService.addNotification(notif1);
7469         mService.addNotification(notif2);
7470 
7471         // on broadcast, nothing is hidden since no notifications are of package "test_package"
7472         simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid());
7473         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
7474         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
7475         assertEquals(0, captor.getValue().size());
7476     }
7477 
7478     @Test
testNotificationFromDifferentUserHidden()7479     public void testNotificationFromDifferentUserHidden() {
7480         // post 2 notification from this package
7481         final NotificationRecord notif1 = generateNotificationRecord(
7482                 mTestNotificationChannel, 1, null, true);
7483         final NotificationRecord notif2 = generateNotificationRecord(
7484                 mTestNotificationChannel, 2, null, false);
7485         mService.addNotification(notif1);
7486         mService.addNotification(notif2);
7487 
7488         // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG
7489         simulatePackageSuspendBroadcast(true, mPkg, 10);
7490         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
7491         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
7492         assertEquals(0, captor.getValue().size());
7493     }
7494 
7495     @Test
testHideAndUnhideNotificationsOnDistractingPackageBroadcast()7496     public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() {
7497         // Post 2 notifications from 2 packages
7498         NotificationRecord pkgA = new NotificationRecord(mContext,
7499                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
7500         mService.addNotification(pkgA);
7501         NotificationRecord pkgB = new NotificationRecord(mContext,
7502                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
7503         mService.addNotification(pkgB);
7504 
7505         // on broadcast, hide one of the packages
7506         simulatePackageDistractionBroadcast(
7507                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"},
7508                 new int[] {1000});
7509         ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
7510         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
7511         assertEquals(1, captorHide.getValue().size());
7512         assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
7513 
7514         // on broadcast, unhide the package
7515         simulatePackageDistractionBroadcast(
7516                 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"},
7517                 new int[] {1000});
7518         ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
7519         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
7520         assertEquals(1, captorUnhide.getValue().size());
7521         assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName());
7522     }
7523 
7524     @Test
testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg()7525     public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() {
7526         // Post 2 notifications from 2 packages
7527         NotificationRecord pkgA = new NotificationRecord(mContext,
7528                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
7529         mService.addNotification(pkgA);
7530         NotificationRecord pkgB = new NotificationRecord(mContext,
7531                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
7532         mService.addNotification(pkgB);
7533 
7534         // on broadcast, hide one of the packages
7535         simulatePackageDistractionBroadcast(
7536                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"},
7537                 new int[] {1000, 1001});
7538         ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
7539 
7540         // should be called only once.
7541         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
7542         assertEquals(2, captorHide.getValue().size());
7543         assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
7544         assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName());
7545 
7546         // on broadcast, unhide the package
7547         simulatePackageDistractionBroadcast(
7548                 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"},
7549                 new int[] {1000, 1001});
7550         ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
7551 
7552         // should be called only once.
7553         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
7554         assertEquals(2, captorUnhide.getValue().size());
7555         assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName());
7556         assertEquals("b", captorUnhide.getValue().get(1).getSbn().getPackageName());
7557     }
7558 
7559     @Test
testNoNotificationsHiddenOnDistractingPackageBroadcast()7560     public void testNoNotificationsHiddenOnDistractingPackageBroadcast() {
7561         // post notification from this package
7562         final NotificationRecord notif1 = generateNotificationRecord(
7563                 mTestNotificationChannel, 1, null, true);
7564         mService.addNotification(notif1);
7565 
7566         // on broadcast, nothing is hidden since no notifications are of package "test_package"
7567         simulatePackageDistractionBroadcast(
7568                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"},
7569                 new int[]{notif1.getUid()});
7570         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
7571         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
7572         assertEquals(0, captor.getValue().size());
7573     }
7574 
7575     @Test
testCanUseManagedServicesNullPkg()7576     public void testCanUseManagedServicesNullPkg() {
7577         assertEquals(true, mService.canUseManagedServices(null, 0, null));
7578     }
7579 
7580 
7581     @Test
testCanUseManagedServicesNoValidPkg()7582     public void testCanUseManagedServicesNoValidPkg() {
7583         assertEquals(true, mService.canUseManagedServices("d", 0, null));
7584     }
7585 
7586     @Test
testCanUseManagedServices_hasPermission()7587     public void testCanUseManagedServices_hasPermission() throws Exception {
7588         when(mPackageManager.checkPermission("perm", "pkg", 0))
7589                 .thenReturn(PackageManager.PERMISSION_GRANTED);
7590 
7591         assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm"));
7592     }
7593 
7594     @Test
testCanUseManagedServices_noPermission()7595     public void testCanUseManagedServices_noPermission() throws Exception {
7596         when(mPackageManager.checkPermission("perm", "pkg", 0))
7597                 .thenReturn(PackageManager.PERMISSION_DENIED);
7598 
7599         assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm"));
7600     }
7601 
7602     @Test
testCanUseManagedServices_permDoesNotMatter()7603     public void testCanUseManagedServices_permDoesNotMatter() {
7604         assertEquals(true, mService.canUseManagedServices("pkg", 0, null));
7605     }
7606 
7607     @Test
testOnNotificationVisibilityChanged_triggersInterruptionUsageStat()7608     public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() {
7609         final NotificationRecord r = generateNotificationRecord(
7610                 mTestNotificationChannel, 1, null, true);
7611         r.setTextChanged(true);
7612         mService.addNotification(r);
7613 
7614         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
7615                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
7616                 new NotificationVisibility[]{});
7617 
7618         verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
7619     }
7620 
7621     @Test
testOnNotificationVisibilityChanged_triggersVisibilityLog()7622     public void testOnNotificationVisibilityChanged_triggersVisibilityLog() {
7623         final NotificationRecord r = generateNotificationRecord(
7624                 mTestNotificationChannel, 1, null, true);
7625         r.setTextChanged(true);
7626         r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7627         mService.addNotification(r);
7628 
7629         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
7630                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
7631                 new NotificationVisibility[]{});
7632 
7633         assertEquals(1, mNotificationRecordLogger.numCalls());
7634         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN,
7635                 mNotificationRecordLogger.event(0));
7636         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
7637 
7638         mService.mNotificationDelegate.onNotificationVisibilityChanged(
7639                 new NotificationVisibility[]{},
7640                 new NotificationVisibility[]
7641                         {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}
7642         );
7643 
7644         assertEquals(2, mNotificationRecordLogger.numCalls());
7645         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE,
7646                 mNotificationRecordLogger.event(1));
7647         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
7648     }
7649 
7650     @Test
testSetNotificationsShownFromListener_triggersInterruptionUsageStat()7651     public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat()
7652             throws RemoteException {
7653         final NotificationRecord r = generateNotificationRecord(
7654                 mTestNotificationChannel, 1, null, true);
7655         r.setTextChanged(true);
7656         mService.addNotification(r);
7657 
7658         mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
7659 
7660         verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
7661     }
7662 
7663     @Test
testSetNotificationsShownFromListener_protectsCrossUserInformation()7664     public void testSetNotificationsShownFromListener_protectsCrossUserInformation()
7665             throws RemoteException {
7666         Notification.Builder nb = new Notification.Builder(
7667                 mContext, mTestNotificationChannel.getId())
7668                 .setContentTitle("foo")
7669                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
7670         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
7671                 "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
7672                 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
7673                 null, 0);
7674         final NotificationRecord r =
7675                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7676         r.setTextChanged(true);
7677         mService.addNotification(r);
7678 
7679         // no security exception!
7680         mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
7681 
7682         verify(mAppUsageStats, never()).reportInterruptiveNotification(
7683                 anyString(), anyString(), anyInt());
7684     }
7685 
7686     @Test
testCancelNotificationsFromListener_protectsCrossUserInformation()7687     public void testCancelNotificationsFromListener_protectsCrossUserInformation()
7688             throws RemoteException {
7689         Notification.Builder nb = new Notification.Builder(
7690                 mContext, mTestNotificationChannel.getId())
7691                 .setContentTitle("foo")
7692                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
7693         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
7694                 "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
7695                 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
7696                 null, 0);
7697         final NotificationRecord r =
7698                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7699         r.setTextChanged(true);
7700         mService.addNotification(r);
7701 
7702         // no security exception!
7703         mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()});
7704 
7705         waitForIdle();
7706         assertEquals(1, mService.getNotificationRecordCount());
7707     }
7708 
7709     @Test
testMaybeRecordInterruptionLocked_doesNotRecordTwice()7710     public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
7711             throws RemoteException {
7712         final NotificationRecord r = generateNotificationRecord(
7713                 mTestNotificationChannel, 1, null, true);
7714         r.setInterruptive(true);
7715         mService.addNotification(r);
7716 
7717         mService.maybeRecordInterruptionLocked(r);
7718         mService.maybeRecordInterruptionLocked(r);
7719 
7720         verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
7721                 anyString(), anyString(), anyInt());
7722         verify(mHistoryManager, times(1)).addNotification(any());
7723     }
7724 
7725     @Test
testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()7726     public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()
7727             throws RemoteException {
7728         final NotificationRecord r = generateNotificationRecord(
7729                 mTestNotificationChannel, 1, null, true);
7730         r.setInterruptive(true);
7731         r.getSbn().getNotification().setSmallIcon(null);
7732         mService.addNotification(r);
7733 
7734         mService.maybeRecordInterruptionLocked(r);
7735 
7736         verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
7737                 anyString(), anyString(), anyInt());
7738         verify(mHistoryManager, never()).addNotification(any());
7739     }
7740 
7741     @Test
testBubble()7742     public void testBubble() throws Exception {
7743         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE);
7744         assertFalse(mBinderService.areBubblesAllowed(mPkg));
7745         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
7746                 BUBBLE_PREFERENCE_NONE);
7747     }
7748 
7749     @Test
testUserApprovedBubblesForPackageSelected()7750     public void testUserApprovedBubblesForPackageSelected() throws Exception {
7751         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_SELECTED);
7752         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
7753                 BUBBLE_PREFERENCE_SELECTED);
7754     }
7755 
7756     @Test
testUserApprovedBubblesForPackageAll()7757     public void testUserApprovedBubblesForPackageAll() throws Exception {
7758         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_ALL);
7759         assertTrue(mBinderService.areBubblesAllowed(mPkg));
7760         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
7761                 BUBBLE_PREFERENCE_ALL);
7762     }
7763 
7764     @Test
testUserRejectsBubblesForPackage()7765     public void testUserRejectsBubblesForPackage() throws Exception {
7766         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE);
7767         assertFalse(mBinderService.areBubblesAllowed(mPkg));
7768     }
7769 
7770     @Test
testAreBubblesEnabled()7771     public void testAreBubblesEnabled() throws Exception {
7772         Settings.Secure.putInt(mContext.getContentResolver(),
7773                 Settings.Secure.NOTIFICATION_BUBBLES, 1);
7774         mService.mPreferencesHelper.updateBubblesEnabled();
7775         assertTrue(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
7776     }
7777 
7778     @Test
testAreBubblesEnabled_false()7779     public void testAreBubblesEnabled_false() throws Exception {
7780         Settings.Secure.putInt(mContext.getContentResolver(),
7781                 Settings.Secure.NOTIFICATION_BUBBLES, 0);
7782         mService.mPreferencesHelper.updateBubblesEnabled();
7783         assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
7784     }
7785 
7786     @Test
testAreBubblesEnabled_exception()7787     public void testAreBubblesEnabled_exception() throws Exception {
7788         try {
7789             assertTrue(mBinderService.areBubblesEnabled(
7790                     UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE)));
7791             fail("Cannot call cross user without permission");
7792         } catch (SecurityException e) {
7793             // pass
7794         }
7795         // cross user, with permission, no problem
7796         enableInteractAcrossUsers();
7797         assertTrue(mBinderService.areBubblesEnabled(
7798                 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE)));
7799     }
7800 
7801     @Test
testIsCallerInstantApp_primaryUser()7802     public void testIsCallerInstantApp_primaryUser() throws Exception {
7803         ApplicationInfo info = new ApplicationInfo();
7804         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
7805         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
7806         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
7807 
7808         assertTrue(mService.isCallerInstantApp(45770, 0));
7809 
7810         info.privateFlags = 0;
7811         assertFalse(mService.isCallerInstantApp(575370, 0));
7812     }
7813 
7814     @Test
testIsCallerInstantApp_secondaryUser()7815     public void testIsCallerInstantApp_secondaryUser() throws Exception {
7816         ApplicationInfo info = new ApplicationInfo();
7817         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
7818         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
7819         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
7820         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
7821 
7822         assertTrue(mService.isCallerInstantApp(68638450, 10));
7823     }
7824 
7825     @Test
testIsCallerInstantApp_userAllNotification()7826     public void testIsCallerInstantApp_userAllNotification() throws Exception {
7827         ApplicationInfo info = new ApplicationInfo();
7828         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
7829         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM)))
7830                 .thenReturn(info);
7831         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
7832 
7833         assertTrue(mService.isCallerInstantApp(45770, UserHandle.USER_ALL));
7834 
7835         info.privateFlags = 0;
7836         assertFalse(mService.isCallerInstantApp(575370, UserHandle.USER_ALL ));
7837     }
7838 
7839     @Test
testResolveNotificationUid_sameApp_nonSystemUser()7840     public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception {
7841         ApplicationInfo info = new ApplicationInfo();
7842         info.uid = Binder.getCallingUid();
7843         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
7844         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
7845 
7846         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10);
7847 
7848         assertEquals(info.uid, actualUid);
7849     }
7850 
7851     @Test
testResolveNotificationUid_sameApp()7852     public void testResolveNotificationUid_sameApp() throws Exception {
7853         ApplicationInfo info = new ApplicationInfo();
7854         info.uid = Binder.getCallingUid();
7855         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
7856 
7857         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
7858 
7859         assertEquals(info.uid, actualUid);
7860     }
7861 
7862     @Test
testResolveNotificationUid_sameAppDiffPackage()7863     public void testResolveNotificationUid_sameAppDiffPackage() throws Exception {
7864         ApplicationInfo info = new ApplicationInfo();
7865         info.uid = Binder.getCallingUid();
7866         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
7867 
7868         int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0);
7869 
7870         assertEquals(info.uid, actualUid);
7871     }
7872 
7873     @Test
testResolveNotificationUid_sameAppWrongUid()7874     public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
7875         ApplicationInfo info = new ApplicationInfo();
7876         info.uid = 1356347;
7877         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info);
7878 
7879         try {
7880             mService.resolveNotificationUid("caller", "caller", 9, 0);
7881             fail("Incorrect uid didn't throw security exception");
7882         } catch (SecurityException e) {
7883             // yay
7884         }
7885     }
7886 
7887     @Test
testResolveNotificationUid_delegateAllowed()7888     public void testResolveNotificationUid_delegateAllowed() throws Exception {
7889         int expectedUid = 123;
7890 
7891         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
7892         mService.setPreferencesHelper(mPreferencesHelper);
7893         when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt()))
7894                 .thenReturn(true);
7895 
7896         assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0));
7897     }
7898 
7899     @Test
testResolveNotificationUid_androidAllowed()7900     public void testResolveNotificationUid_androidAllowed() throws Exception {
7901         int expectedUid = 123;
7902 
7903         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
7904         // no delegate
7905 
7906         assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0));
7907     }
7908 
7909     @Test
testPostFromAndroidForNonExistentPackage()7910     public void testPostFromAndroidForNonExistentPackage() throws Exception {
7911         final String notReal = "NOT REAL";
7912         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow(
7913                 PackageManager.NameNotFoundException.class);
7914         ApplicationInfo ai = new ApplicationInfo();
7915         ai.uid = -1;
7916         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
7917 
7918         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
7919         try {
7920             mInternalService.enqueueNotification(notReal, "android", 0, 0,
7921                     "testPostFromAndroidForNonExistentPackage",
7922                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
7923             fail("can't post notifications for nonexistent packages, even if you exist");
7924         } catch (SecurityException e) {
7925             // yay
7926         }
7927     }
7928 
7929     @Test
testCancelFromAndroidForNonExistentPackage()7930     public void testCancelFromAndroidForNonExistentPackage() throws Exception {
7931         final String notReal = "NOT REAL";
7932         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
7933                 PackageManager.NameNotFoundException.class);
7934         ApplicationInfo ai = new ApplicationInfo();
7935         ai.uid = -1;
7936         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
7937 
7938         // unlike the post case, ignore instead of throwing
7939         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
7940 
7941         mInternalService.cancelNotification(notReal, "android", 0, 0, "tag",
7942                 sbn.getId(), sbn.getUserId());
7943     }
7944 
7945     @Test
testResolveNotificationUid_delegateNotAllowed()7946     public void testResolveNotificationUid_delegateNotAllowed() throws Exception {
7947         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123);
7948         // no delegate
7949 
7950         try {
7951             mService.resolveNotificationUid("caller", "target", 9, 0);
7952             fail("Incorrect uid didn't throw security exception");
7953         } catch (SecurityException e) {
7954             // yay
7955         }
7956     }
7957 
7958     @Test
testRemoveForegroundServiceFlagFromNotification_enqueued()7959     public void testRemoveForegroundServiceFlagFromNotification_enqueued() {
7960         when(mAmi.applyForegroundServiceNotification(
7961                 any(), anyString(), anyInt(), anyString(), anyInt()))
7962                 .thenReturn(SHOW_IMMEDIATELY);
7963         Notification n = new Notification.Builder(mContext, "").build();
7964         n.flags |= FLAG_FOREGROUND_SERVICE;
7965 
7966         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
7967                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
7968         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7969 
7970         mService.addEnqueuedNotification(r);
7971 
7972         mInternalService.removeForegroundServiceFlagFromNotification(
7973                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
7974 
7975         waitForIdle();
7976 
7977         verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
7978     }
7979 
7980     @Test
testRemoveForegroundServiceFlagFromNotification_posted()7981     public void testRemoveForegroundServiceFlagFromNotification_posted() {
7982         when(mAmi.applyForegroundServiceNotification(
7983                 any(), anyString(), anyInt(), anyString(), anyInt()))
7984                 .thenReturn(SHOW_IMMEDIATELY);
7985         Notification n = new Notification.Builder(mContext, "").build();
7986         n.flags |= FLAG_FOREGROUND_SERVICE;
7987 
7988         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
7989                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
7990         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7991 
7992         mService.addNotification(r);
7993 
7994         mInternalService.removeForegroundServiceFlagFromNotification(
7995                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
7996 
7997         waitForIdle();
7998 
7999         ArgumentCaptor<NotificationRecord> captor =
8000                 ArgumentCaptor.forClass(NotificationRecord.class);
8001         verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
8002 
8003         assertEquals(0, captor.getValue().getNotification().flags);
8004     }
8005 
8006     @Test
testCannotRemoveForegroundFlagWhenOverLimit_enqueued()8007     public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() {
8008         when(mAmi.applyForegroundServiceNotification(
8009                 any(), anyString(), anyInt(), anyString(), anyInt()))
8010                 .thenReturn(SHOW_IMMEDIATELY);
8011         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
8012             Notification n = new Notification.Builder(mContext, "").build();
8013             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
8014                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
8015             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8016             mService.addEnqueuedNotification(r);
8017         }
8018         Notification n = new Notification.Builder(mContext, "").build();
8019         n.flags |= FLAG_FOREGROUND_SERVICE;
8020 
8021         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
8022                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
8023                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
8024         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8025 
8026         mService.addEnqueuedNotification(r);
8027 
8028         mInternalService.removeForegroundServiceFlagFromNotification(
8029                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
8030 
8031         waitForIdle();
8032 
8033         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
8034                 mService.getNotificationRecordCount());
8035     }
8036 
8037     @Test
testCannotRemoveForegroundFlagWhenOverLimit_posted()8038     public void testCannotRemoveForegroundFlagWhenOverLimit_posted() {
8039         when(mAmi.applyForegroundServiceNotification(
8040                 any(), anyString(), anyInt(), anyString(), anyInt()))
8041                 .thenReturn(SHOW_IMMEDIATELY);
8042         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
8043             Notification n = new Notification.Builder(mContext, "").build();
8044             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
8045                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
8046             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8047             mService.addNotification(r);
8048         }
8049         Notification n = new Notification.Builder(mContext, "").build();
8050         n.flags |= FLAG_FOREGROUND_SERVICE;
8051 
8052         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
8053                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
8054                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
8055         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8056 
8057         mService.addNotification(r);
8058 
8059         mInternalService.removeForegroundServiceFlagFromNotification(
8060                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
8061 
8062         waitForIdle();
8063 
8064         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
8065                 mService.getNotificationRecordCount());
8066     }
8067 
8068     @Test
testAllowForegroundCustomToasts()8069     public void testAllowForegroundCustomToasts() throws Exception {
8070         final String testPackage = "testPackageName";
8071         assertEquals(0, mService.mToastQueue.size());
8072         mService.isSystemUid = false;
8073         mService.isSystemAppId = false;
8074         setToastRateIsWithinQuota(true);
8075         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8076 
8077         // package is not suspended
8078         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8079                 .thenReturn(false);
8080 
8081         // notifications from this package are blocked by the user
8082         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
8083 
8084         setAppInForegroundForToasts(mUid, true);
8085 
8086         // enqueue toast -> toast should still enqueue
8087         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
8088         assertEquals(1, mService.mToastQueue.size());
8089         assertThat(wasEnqueued).isTrue();
8090     }
8091 
8092     @Test
testDisallowBackgroundCustomToasts()8093     public void testDisallowBackgroundCustomToasts() throws Exception {
8094         final String testPackage = "testPackageName";
8095         assertEquals(0, mService.mToastQueue.size());
8096         mService.isSystemUid = false;
8097         mService.isSystemAppId = false;
8098         setToastRateIsWithinQuota(true);
8099         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8100 
8101         // package is not suspended
8102         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8103                 .thenReturn(false);
8104 
8105         setAppInForegroundForToasts(mUid, false);
8106 
8107         // enqueue toast -> no toasts enqueued
8108         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
8109         assertEquals(0, mService.mToastQueue.size());
8110         assertThat(wasEnqueued).isFalse();
8111     }
8112 
8113     @Test
testDontCallShowToastAgainOnTheSameCustomToast()8114     public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception {
8115         final String testPackage = "testPackageName";
8116         assertEquals(0, mService.mToastQueue.size());
8117         mService.isSystemUid = false;
8118         mService.isSystemAppId = false;
8119         setToastRateIsWithinQuota(true);
8120         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8121 
8122         // package is not suspended
8123         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8124                 .thenReturn(false);
8125 
8126         setAppInForegroundForToasts(mUid, true);
8127 
8128         Binder token = new Binder();
8129         ITransientNotification callback = mock(ITransientNotification.class);
8130         INotificationManager nmService = (INotificationManager) mService.mService;
8131 
8132         // first time trying to show the toast, showToast gets called
8133         enqueueToast(nmService, testPackage, token, callback);
8134         verify(callback, times(1)).show(any());
8135 
8136         // second time trying to show the same toast, showToast isn't called again (total number of
8137         // invocations stays at one)
8138         enqueueToast(nmService, testPackage, token, callback);
8139         verify(callback, times(1)).show(any());
8140     }
8141 
8142     @Test
testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()8143     public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()
8144             throws Exception {
8145         final String testPackage = "testPackageName";
8146         assertEquals(0, mService.mToastQueue.size());
8147         mService.isSystemUid = false;
8148         mService.isSystemAppId = false;
8149         setToastRateIsWithinQuota(false); // rate limit reached
8150         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8151 
8152         // package is not suspended
8153         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8154                 .thenReturn(false);
8155 
8156         setAppInForegroundForToasts(mUid, true);
8157 
8158         Binder token = new Binder();
8159         ITransientNotification callback = mock(ITransientNotification.class);
8160         INotificationManager nmService = (INotificationManager) mService.mService;
8161 
8162         enqueueToast(nmService, testPackage, token, callback);
8163         verify(callback, times(1)).show(any());
8164     }
8165 
8166     @Test
testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()8167     public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()
8168             throws Exception {
8169         final String testPackage = "testPackageName";
8170         assertEquals(0, mService.mToastQueue.size());
8171         mService.isSystemUid = false;
8172         mService.isSystemAppId = false;
8173         setToastRateIsWithinQuota(true);
8174         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8175 
8176         // package is not suspended
8177         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8178                 .thenReturn(false);
8179 
8180         setAppInForegroundForToasts(mUid, true);
8181 
8182         Binder token1 = new Binder();
8183         Binder token2 = new Binder();
8184         ITransientNotification callback1 = mock(ITransientNotification.class);
8185         ITransientNotification callback2 = mock(ITransientNotification.class);
8186         INotificationManager nmService = (INotificationManager) mService.mService;
8187 
8188         enqueueToast(nmService, testPackage, token1, callback1);
8189         enqueueToast(nmService, testPackage, token2, callback2);
8190 
8191         assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued.
8192         verify(callback1, times(1)).show(any()); // First toast shown.
8193 
8194         setAppInForegroundForToasts(mUid, false);
8195 
8196         mService.cancelToastLocked(0); // Remove the first toast, and show next.
8197 
8198         assertEquals(0, mService.mToastQueue.size()); // Both toasts processed.
8199         verify(callback2, never()).show(any()); // Second toast was never shown.
8200     }
8201 
8202     @Test
testAllowForegroundTextToasts()8203     public void testAllowForegroundTextToasts() throws Exception {
8204         final String testPackage = "testPackageName";
8205         assertEquals(0, mService.mToastQueue.size());
8206         mService.isSystemUid = false;
8207         mService.isSystemAppId = false;
8208         setToastRateIsWithinQuota(true);
8209         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8210 
8211         // package is not suspended
8212         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8213                 .thenReturn(false);
8214 
8215         setAppInForegroundForToasts(mUid, true);
8216 
8217         // enqueue toast -> toast should still enqueue
8218         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
8219         assertEquals(1, mService.mToastQueue.size());
8220         assertThat(wasEnqueued).isTrue();
8221     }
8222 
8223     @Test
testAllowBackgroundTextToasts()8224     public void testAllowBackgroundTextToasts() throws Exception {
8225         final String testPackage = "testPackageName";
8226         assertEquals(0, mService.mToastQueue.size());
8227         mService.isSystemUid = false;
8228         mService.isSystemAppId = false;
8229         setToastRateIsWithinQuota(true);
8230         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8231 
8232         // package is not suspended
8233         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8234                 .thenReturn(false);
8235 
8236         setAppInForegroundForToasts(mUid, false);
8237 
8238         // enqueue toast -> toast should still enqueue
8239         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
8240         assertEquals(1, mService.mToastQueue.size());
8241         assertThat(wasEnqueued).isTrue();
8242     }
8243 
8244     @Test
testDontCallShowToastAgainOnTheSameTextToast()8245     public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception {
8246         final String testPackage = "testPackageName";
8247         assertEquals(0, mService.mToastQueue.size());
8248         mService.isSystemUid = false;
8249         mService.isSystemAppId = false;
8250         setToastRateIsWithinQuota(true);
8251         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8252 
8253         // package is not suspended
8254         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8255                 .thenReturn(false);
8256 
8257         setAppInForegroundForToasts(mUid, true);
8258 
8259         Binder token = new Binder();
8260         INotificationManager nmService = (INotificationManager) mService.mService;
8261 
8262         // first time trying to show the toast, showToast gets called
8263         enqueueTextToast(testPackage, "Text");
8264         verify(mStatusBar, times(1))
8265                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
8266 
8267         // second time trying to show the same toast, showToast isn't called again (total number of
8268         // invocations stays at one)
8269         enqueueTextToast(testPackage, "Text");
8270         verify(mStatusBar, times(1))
8271                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
8272     }
8273 
8274     @Test
testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()8275     public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()
8276             throws Exception {
8277         final String testPackage = "testPackageName";
8278         assertEquals(0, mService.mToastQueue.size());
8279         mService.isSystemUid = false;
8280         mService.isSystemAppId = false;
8281         setToastRateIsWithinQuota(false); // rate limit reached
8282         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8283         setAppInForegroundForToasts(mUid, false);
8284 
8285         // package is not suspended
8286         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8287                 .thenReturn(false);
8288 
8289         Binder token = new Binder();
8290         INotificationManager nmService = (INotificationManager) mService.mService;
8291 
8292         enqueueTextToast(testPackage, "Text");
8293         verify(mStatusBar, times(0))
8294                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
8295     }
8296 
8297     @Test
testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()8298     public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()
8299             throws Exception {
8300         final String testPackage = "testPackageName";
8301         assertEquals(0, mService.mToastQueue.size());
8302         mService.isSystemUid = false;
8303         mService.isSystemAppId = false;
8304         setToastRateIsWithinQuota(false); // rate limit reached
8305         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8306         setAppInForegroundForToasts(mUid, true);
8307 
8308         // package is not suspended
8309         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8310                 .thenReturn(false);
8311 
8312         Binder token = new Binder();
8313         INotificationManager nmService = (INotificationManager) mService.mService;
8314 
8315         enqueueTextToast(testPackage, "Text");
8316         verify(mStatusBar, times(1))
8317                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
8318     }
8319 
8320     @Test
testTextToastRateLimiterAllowsLimitAvoidanceWithPermission()8321     public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception {
8322         final String testPackage = "testPackageName";
8323         assertEquals(0, mService.mToastQueue.size());
8324         mService.isSystemUid = false;
8325         mService.isSystemAppId = false;
8326         setToastRateIsWithinQuota(false); // rate limit reached
8327         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true);
8328         setAppInForegroundForToasts(mUid, false);
8329 
8330         // package is not suspended
8331         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8332                 .thenReturn(false);
8333 
8334         Binder token = new Binder();
8335         INotificationManager nmService = (INotificationManager) mService.mService;
8336 
8337         enqueueTextToast(testPackage, "Text");
8338         verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
8339                 anyInt());
8340     }
8341 
8342     @Test
testRateLimitedToasts_windowsRemoved()8343     public void testRateLimitedToasts_windowsRemoved() throws Exception {
8344         final String testPackage = "testPackageName";
8345         assertEquals(0, mService.mToastQueue.size());
8346         mService.isSystemUid = false;
8347         mService.isSystemAppId = false;
8348         setToastRateIsWithinQuota(false); // rate limit reached
8349         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8350         setAppInForegroundForToasts(mUid, false);
8351 
8352         // package is not suspended
8353         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8354                 .thenReturn(false);
8355 
8356         Binder token = new Binder();
8357         INotificationManager nmService = (INotificationManager) mService.mService;
8358 
8359         enqueueTextToast(testPackage, "Text");
8360 
8361         // window token was added when enqueued
8362         ArgumentCaptor<Binder> binderCaptor =
8363                 ArgumentCaptor.forClass(Binder.class);
8364         verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(),
8365                 eq(TYPE_TOAST), anyInt(), eq(null));
8366 
8367         // but never shown
8368         verify(mStatusBar, times(0))
8369                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
8370 
8371         // and removed when rate limited
8372         verify(mWindowManagerInternal)
8373                 .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt());
8374     }
8375 
8376     @Test
backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast()8377     public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
8378             Exception {
8379         final String testPackage = "testPackageName";
8380         assertEquals(0, mService.mToastQueue.size());
8381         mService.isSystemUid = true;
8382         setToastRateIsWithinQuota(true);
8383         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8384 
8385         // package is not suspended
8386         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8387                 .thenReturn(false);
8388 
8389         // notifications from this package are blocked by the user
8390         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
8391 
8392         setAppInForegroundForToasts(mUid, false);
8393 
8394         // enqueue toast -> toast should still enqueue
8395         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
8396         assertEquals(1, mService.mToastQueue.size());
8397         assertThat(wasEnqueued).isTrue();
8398         verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any());
8399     }
8400 
8401     @Test
foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast()8402     public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws
8403             Exception {
8404         final String testPackage = "testPackageName";
8405         assertEquals(0, mService.mToastQueue.size());
8406         mService.isSystemUid = false;
8407         mService.isSystemAppId = false;
8408         setToastRateIsWithinQuota(true);
8409         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8410 
8411         // package is not suspended
8412         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8413                 .thenReturn(false);
8414 
8415         setAppInForegroundForToasts(mUid, true);
8416 
8417         // enqueue toast -> toast should still enqueue
8418         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
8419         assertEquals(1, mService.mToastQueue.size());
8420         assertThat(wasEnqueued).isTrue();
8421         verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());
8422     }
8423 
8424     @Test
backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast()8425     public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws
8426             Exception {
8427         final String testPackage = "testPackageName";
8428         assertEquals(0, mService.mToastQueue.size());
8429         mService.isSystemUid = false;
8430         mService.isSystemAppId = false;
8431         setToastRateIsWithinQuota(true);
8432         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8433 
8434         // package is not suspended
8435         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8436                 .thenReturn(false);
8437 
8438         setAppInForegroundForToasts(mUid, false);
8439 
8440         // enqueue toast -> toast should still enqueue
8441         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
8442         assertEquals(1, mService.mToastQueue.size());
8443         assertThat(wasEnqueued).isTrue();
8444         verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());
8445     }
8446 
8447     @Test
testTextToastsCallStatusBar()8448     public void testTextToastsCallStatusBar() throws Exception {
8449         allowTestPackageToToast();
8450 
8451         // enqueue toast -> no toasts enqueued
8452         boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text");
8453         assertThat(wasEnqueued).isTrue();
8454 
8455         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
8456     }
8457 
8458     @Test
testTextToastsCallStatusBar_nonUiContext_defaultDisplay()8459     public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay()
8460             throws Exception {
8461         allowTestPackageToToast();
8462 
8463         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY);
8464 
8465         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
8466     }
8467 
8468     @Test
testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()8469     public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()
8470             throws Exception {
8471         allowTestPackageToToast();
8472         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
8473 
8474         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID);
8475 
8476         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
8477     }
8478 
8479     @Test
testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()8480     public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()
8481             throws Exception {
8482         mockIsVisibleBackgroundUsersSupported(true);
8483         mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID);
8484         allowTestPackageToToast();
8485 
8486         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY);
8487 
8488         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
8489 
8490     }
8491 
8492     @Test
testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()8493     public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()
8494             throws Exception {
8495         mockIsVisibleBackgroundUsersSupported(true);
8496         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
8497         mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used
8498         allowTestPackageToToast();
8499 
8500         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID);
8501 
8502         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
8503     }
8504 
8505     @Test
testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()8506     public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()
8507             throws Exception {
8508         mockIsVisibleBackgroundUsersSupported(true);
8509         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
8510         mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID);
8511         allowTestPackageToToast();
8512 
8513         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY);
8514 
8515         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
8516     }
8517 
8518     @Test
testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()8519     public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()
8520             throws Exception {
8521         mockIsVisibleBackgroundUsersSupported(true);
8522         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
8523         mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used
8524         allowTestPackageToToast();
8525 
8526         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID);
8527 
8528         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
8529     }
8530 
8531     @Test
testTextToastsCallStatusBar_userNotVisibleOnDisplay()8532     public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception {
8533         final String testPackage = "testPackageName";
8534         assertEquals(0, mService.mToastQueue.size());
8535         mService.isSystemUid = false;
8536         mService.isSystemAppId = false;
8537         setToastRateIsWithinQuota(true);
8538         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8539         mockIsUserVisible(DEFAULT_DISPLAY, false);
8540 
8541         // package is not suspended
8542         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
8543                 .thenReturn(false);
8544 
8545         // enqueue toast -> no toasts enqueued
8546         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
8547         verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
8548                 anyInt());
8549         assertEquals(0, mService.mToastQueue.size());
8550         assertThat(wasEnqueued).isFalse();
8551     }
8552 
8553     @Test
testDisallowToastsFromSuspendedPackages()8554     public void testDisallowToastsFromSuspendedPackages() throws Exception {
8555         final String testPackage = "testPackageName";
8556         assertEquals(0, mService.mToastQueue.size());
8557         mService.isSystemUid = false;
8558         mService.isSystemAppId = false;
8559         setToastRateIsWithinQuota(true);
8560         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8561 
8562         // package is suspended
8563         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8564                 .thenReturn(true);
8565 
8566         // notifications from this package are NOT blocked by the user
8567         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
8568 
8569         // enqueue toast -> no toasts enqueued
8570         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
8571         verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
8572                 anyInt());
8573         assertEquals(0, mService.mToastQueue.size());
8574         assertThat(wasEnqueued).isFalse();
8575     }
8576 
8577     @Test
testDisallowToastsFromBlockedApps()8578     public void testDisallowToastsFromBlockedApps() throws Exception {
8579         final String testPackage = "testPackageName";
8580         assertEquals(0, mService.mToastQueue.size());
8581         mService.isSystemUid = false;
8582         mService.isSystemAppId = false;
8583         setToastRateIsWithinQuota(true);
8584         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8585 
8586         // package is not suspended
8587         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8588                 .thenReturn(false);
8589 
8590         // notifications from this package are blocked by the user
8591         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
8592 
8593         setAppInForegroundForToasts(mUid, false);
8594 
8595         // enqueue toast -> no toasts enqueued
8596         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
8597         assertEquals(0, mService.mToastQueue.size());
8598         assertThat(wasEnqueued).isFalse();
8599     }
8600 
8601     @Test
testAlwaysAllowSystemToasts()8602     public void testAlwaysAllowSystemToasts() throws Exception {
8603         final String testPackage = "testPackageName";
8604         assertEquals(0, mService.mToastQueue.size());
8605         mService.isSystemUid = true;
8606         setToastRateIsWithinQuota(true);
8607         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8608 
8609         // package is suspended
8610         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8611                 .thenReturn(true);
8612 
8613         // notifications from this package ARE blocked by the user
8614         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
8615 
8616         setAppInForegroundForToasts(mUid, false);
8617 
8618         // enqueue toast -> system toast can still be enqueued
8619         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
8620         assertEquals(1, mService.mToastQueue.size());
8621         assertThat(wasEnqueued).isTrue();
8622     }
8623 
8624     @Test
testLimitNumberOfQueuedToastsFromPackage()8625     public void testLimitNumberOfQueuedToastsFromPackage() throws Exception {
8626         final String testPackage = "testPackageName";
8627         assertEquals(0, mService.mToastQueue.size());
8628         mService.isSystemUid = false;
8629         mService.isSystemAppId = false;
8630         setToastRateIsWithinQuota(true);
8631         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8632 
8633         // package is not suspended
8634         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8635                 .thenReturn(false);
8636 
8637         INotificationManager nmService = (INotificationManager) mService.mService;
8638 
8639         // Trying to quickly enqueue more toast than allowed.
8640         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) {
8641             boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
8642             if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) {
8643                 assertThat(wasEnqueued).isTrue();
8644             } else {
8645                 assertThat(wasEnqueued).isFalse();
8646             }
8647         }
8648         // Only allowed number enqueued, rest ignored.
8649         assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size());
8650     }
8651 
8652     @Test
testPrioritizeSystemToasts()8653     public void testPrioritizeSystemToasts() throws Exception {
8654         // Insert non-system toasts
8655         final String testPackage = "testPackageName";
8656         assertEquals(0, mService.mToastQueue.size());
8657         mService.isSystemUid = false;
8658         mService.isSystemAppId = false;
8659         setToastRateIsWithinQuota(true);
8660         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
8661 
8662         // package is not suspended
8663         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
8664                 .thenReturn(false);
8665 
8666         INotificationManager nmService = (INotificationManager) mService.mService;
8667 
8668         // Enqueue maximum number of toasts for test package
8669         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
8670             enqueueTextToast(testPackage, "Text");
8671         }
8672 
8673         // Enqueue system toast
8674         final String testPackageSystem = "testPackageNameSystem";
8675         mService.isSystemUid = true;
8676         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false);
8677         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, mUserId))
8678                 .thenReturn(false);
8679 
8680         enqueueToast(testPackageSystem, new TestableToastCallback());
8681 
8682         // System toast is inserted at the front of the queue, behind current showing toast
8683         assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg);
8684     }
8685 
8686     @Test
testPrioritizeSystemToasts_enqueueAfterExistingSystemToast()8687     public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception {
8688         // Insert system toasts
8689         final String testPackageSystem1 = "testPackageNameSystem1";
8690         assertEquals(0, mService.mToastQueue.size());
8691         mService.isSystemUid = true;
8692         setToastRateIsWithinQuota(true);
8693         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false);
8694 
8695         // package is not suspended
8696         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, mUserId))
8697                 .thenReturn(false);
8698 
8699         INotificationManager nmService = (INotificationManager) mService.mService;
8700 
8701         // Enqueue maximum number of toasts for test package
8702         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
8703             enqueueTextToast(testPackageSystem1, "Text");
8704         }
8705 
8706         // Enqueue another system toast
8707         final String testPackageSystem2 = "testPackageNameSystem2";
8708         mService.isSystemUid = true;
8709         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false);
8710         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, mUserId))
8711                 .thenReturn(false);
8712 
8713         enqueueToast(testPackageSystem2, new TestableToastCallback());
8714 
8715         // System toast is inserted at the back of the queue, after the other system toasts
8716         assertEquals(testPackageSystem2,
8717                 mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg);
8718     }
8719 
setAppInForegroundForToasts(int uid, boolean inForeground)8720     private void setAppInForegroundForToasts(int uid, boolean inForeground) {
8721         int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE;
8722         when(mActivityManager.getUidImportance(mUid)).thenReturn(importance);
8723         when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground);
8724     }
8725 
setToastRateIsWithinQuota(boolean isWithinQuota)8726     private void setToastRateIsWithinQuota(boolean isWithinQuota) {
8727         when(mToastRateLimiter.isWithinQuota(
8728                 anyInt(),
8729                 anyString(),
8730                 eq(NotificationManagerService.TOAST_QUOTA_TAG)))
8731                 .thenReturn(isWithinQuota);
8732     }
8733 
setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission)8734     private void setIfPackageHasPermissionToAvoidToastRateLimiting(
8735             String pkg, boolean hasPermission) throws Exception {
8736         when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS,
8737                 pkg, mUserId))
8738                 .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED);
8739     }
8740 
8741     @Test
testOnPanelRevealedAndHidden()8742     public void testOnPanelRevealedAndHidden() {
8743         int items = 5;
8744         mService.mNotificationDelegate.onPanelRevealed(false, items);
8745         verify(mAssistants, times(1)).onPanelRevealed(eq(items));
8746 
8747         mService.mNotificationDelegate.onPanelHidden();
8748         verify(mAssistants, times(1)).onPanelHidden();
8749 
8750         assertEquals(2, mNotificationRecordLogger.numCalls());
8751         assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN,
8752                 mNotificationRecordLogger.event(0));
8753         assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE,
8754                 mNotificationRecordLogger.event(1));
8755     }
8756 
8757     @Test
8758     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testOnNotificationSmartReplySent()8759     public void testOnNotificationSmartReplySent() {
8760         final int replyIndex = 2;
8761         final String reply = "Hello";
8762         final boolean modifiedBeforeSending = true;
8763         final boolean generatedByAssistant = true;
8764 
8765         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8766         r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
8767         mService.addNotification(r);
8768 
8769         mService.mNotificationDelegate.onNotificationSmartReplySent(
8770                 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
8771                 modifiedBeforeSending);
8772         verify(mAssistants).notifyAssistantSuggestedReplySent(
8773                 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant));
8774         assertEquals(1, mNotificationRecordLogger.numCalls());
8775         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
8776                 mNotificationRecordLogger.event(0));
8777         // Check that r.recordSmartReplied was called.
8778         assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
8779                 .isGreaterThan(0);
8780         assertThat(r.getStats().hasSmartReplied()).isTrue();
8781     }
8782 
8783     @Test
8784     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate()8785     public void testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate() throws Exception {
8786         final int replyIndex = 2;
8787         final String reply = "Hello";
8788         final boolean modifiedBeforeSending = true;
8789         final boolean generatedByAssistant = true;
8790 
8791         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8792         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
8793         r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
8794         mService.addNotification(r);
8795 
8796         mService.mNotificationDelegate.onNotificationSmartReplySent(
8797                 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
8798                 modifiedBeforeSending);
8799         waitForIdle();
8800 
8801         // Checks that a post update is sent.
8802         verify(mWorkerHandler, times(1))
8803                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
8804         ArgumentCaptor<NotificationRecord> captor =
8805                 ArgumentCaptor.forClass(NotificationRecord.class);
8806         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
8807                 anyBoolean());
8808         assertThat(captor.getValue().getNotification().flags
8809                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
8810                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
8811         assertThat(captor.getValue().getNotification().flags
8812                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
8813         assertThat(captor.getValue().shouldPostSilently()).isTrue();
8814     }
8815 
8816     @Test
testOnNotificationActionClick()8817     public void testOnNotificationActionClick() {
8818         final int actionIndex = 2;
8819         final Notification.Action action =
8820                 new Notification.Action.Builder(null, "text", mActivityIntent).build();
8821         final boolean generatedByAssistant = false;
8822 
8823         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8824         mService.addNotification(r);
8825 
8826         NotificationVisibility notificationVisibility =
8827                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
8828         mService.mNotificationDelegate.onNotificationActionClick(
8829                 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
8830                 generatedByAssistant);
8831         verify(mAssistants).notifyAssistantActionClicked(
8832                 eq(r), eq(action), eq(generatedByAssistant));
8833 
8834         assertEquals(1, mNotificationRecordLogger.numCalls());
8835         assertEquals(
8836                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2,
8837                 mNotificationRecordLogger.event(0));
8838     }
8839 
8840     @Test
8841     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testActionClickLifetimeExtendedCancel()8842     public void testActionClickLifetimeExtendedCancel() throws Exception {
8843         final Notification.Action action =
8844                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
8845                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
8846 
8847         // Creates a notification marked as being lifetime extended.
8848         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8849         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
8850         mService.addNotification(r);
8851 
8852         StatusBarNotification[] notifs =
8853                 mBinderService.getActiveNotifications(mPkg);
8854         assertThat(notifs.length).isEqualTo(1);
8855         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
8856 
8857         // Call on action click.
8858         NotificationVisibility notificationVisibility =
8859                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
8860         mService.mNotificationDelegate.onNotificationActionClick(
8861                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
8862                 /*generatedByAssistant=*/false);
8863 
8864         // Lifetime extended flag persists.
8865         assertThat(r.getSbn().getNotification().flags
8866                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
8867 
8868         mTestableLooper.moveTimeForward(210);
8869         waitForIdle();
8870         verify(mWorkerHandler, times(1))
8871                 .scheduleCancelNotification(
8872                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
8873 
8874         // Check that the cancelation occurred and the notification is gone.
8875         notifs = mBinderService.getActiveNotifications(mPkg);
8876         assertThat(notifs.length).isEqualTo(0);
8877         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
8878     }
8879 
8880     @Test
8881     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testActionClickLifetimeExtendedCancel_PreventByNoDismiss()8882     public void testActionClickLifetimeExtendedCancel_PreventByNoDismiss() throws Exception {
8883         final Notification.Action action =
8884                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
8885                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
8886 
8887         // Creates a notification marked as being lifetime extended.
8888         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8889         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
8890         // Make the notification non-dismissable
8891         r.getSbn().getNotification().flags |= FLAG_NO_DISMISS;
8892         mService.addNotification(r);
8893 
8894         StatusBarNotification[] notifs =
8895                 mBinderService.getActiveNotifications(mPkg);
8896         assertThat(notifs.length).isEqualTo(1);
8897         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
8898 
8899         // Call on action click.
8900         NotificationVisibility notificationVisibility =
8901                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
8902         mService.mNotificationDelegate.onNotificationActionClick(
8903                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
8904                 /*generatedByAssistant=*/false);
8905 
8906         // Lifetime extended flag persists.
8907         assertThat(r.getSbn().getNotification().flags
8908                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
8909 
8910         mTestableLooper.moveTimeForward(210);
8911         waitForIdle();
8912         verify(mWorkerHandler, times(1))
8913                 .scheduleCancelNotification(
8914                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
8915 
8916         // The cancellation is dropped and the notification is still present, with the update.
8917         notifs = mBinderService.getActiveNotifications(mPkg);
8918         assertThat(notifs.length).isEqualTo(1);
8919         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
8920     }
8921 
8922     @Test
8923     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testUpdateOnActionClickDropsLifetimeExtendedCancel()8924     public void testUpdateOnActionClickDropsLifetimeExtendedCancel() throws Exception {
8925         final Notification.Action action =
8926                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
8927                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
8928 
8929         // Creates a notification marked as being lifetime extended.
8930         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8931         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
8932         mService.addNotification(r);
8933 
8934         StatusBarNotification[] notifs =
8935                 mBinderService.getActiveNotifications(mPkg);
8936         assertThat(notifs.length).isEqualTo(1);
8937         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
8938 
8939         // Call on action click.
8940         NotificationVisibility notificationVisibility =
8941                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
8942         mService.mNotificationDelegate.onNotificationActionClick(
8943                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
8944                 /*generatedByAssistant=*/false);
8945 
8946         // The "app" sends an update of the notification in response.
8947         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
8948                 r.getSbn().getId(), r.getSbn().getNotification(), r.getSbn().getUserId());
8949 
8950         mTestableLooper.moveTimeForward(210);
8951         waitForIdle();
8952         verify(mWorkerHandler, times(1))
8953                 .scheduleCancelNotification(
8954                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
8955 
8956         // The cancellation is dropped and the notification is still present, with the update.
8957         notifs = mBinderService.getActiveNotifications(mPkg);
8958         assertThat(notifs.length).isEqualTo(1);
8959         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
8960     }
8961 
8962     @Test
testOnAssistantNotificationActionClick()8963     public void testOnAssistantNotificationActionClick() {
8964         final int actionIndex = 1;
8965         final Notification.Action action =
8966                 new Notification.Action.Builder(null, "text", mActivityIntent).build();
8967         final boolean generatedByAssistant = true;
8968 
8969         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8970         mService.addNotification(r);
8971 
8972         NotificationVisibility notificationVisibility =
8973                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
8974         mService.mNotificationDelegate.onNotificationActionClick(
8975                 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
8976                 generatedByAssistant);
8977         verify(mAssistants).notifyAssistantActionClicked(
8978                 eq(r), eq(action), eq(generatedByAssistant));
8979 
8980         assertEquals(1, mNotificationRecordLogger.numCalls());
8981         assertEquals(
8982                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1,
8983                 mNotificationRecordLogger.event(0));
8984     }
8985 
8986 
8987     @Test
testLogSmartSuggestionsVisible_triggerOnExpandAndVisible()8988     public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() {
8989         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
8990         mService.addNotification(r);
8991 
8992         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
8993                 NOTIFICATION_LOCATION_UNKNOWN);
8994         NotificationVisibility[] notificationVisibility = new NotificationVisibility[] {
8995                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
8996         };
8997         mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
8998                 new NotificationVisibility[0]);
8999 
9000         assertEquals(1, mService.countLogSmartSuggestionsVisible);
9001     }
9002 
9003     @Test
testLogSmartSuggestionsVisible_noTriggerOnExpand()9004     public void testLogSmartSuggestionsVisible_noTriggerOnExpand() {
9005         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9006         mService.addNotification(r);
9007 
9008         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
9009                 NOTIFICATION_LOCATION_UNKNOWN);
9010 
9011         assertEquals(0, mService.countLogSmartSuggestionsVisible);
9012     }
9013 
9014     @Test
testLogSmartSuggestionsVisible_noTriggerOnVisible()9015     public void testLogSmartSuggestionsVisible_noTriggerOnVisible() {
9016         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9017         mService.addNotification(r);
9018 
9019         NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{
9020                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
9021         };
9022         mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
9023                 new NotificationVisibility[0]);
9024 
9025         assertEquals(0, mService.countLogSmartSuggestionsVisible);
9026     }
9027 
9028     @Test
testReportSeen_delegated()9029     public void testReportSeen_delegated() {
9030         Notification.Builder nb =
9031                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
9032                         .setContentTitle("foo")
9033                         .setSmallIcon(android.R.drawable.sym_def_app_icon);
9034 
9035         StatusBarNotification sbn = new StatusBarNotification(mPkg, "opPkg", 0, "tag", mUid, 0,
9036                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
9037         NotificationRecord r =  new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9038 
9039         mService.reportSeen(r);
9040         verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt());
9041 
9042     }
9043 
9044     @Test
testReportSeen_notDelegated()9045     public void testReportSeen_notDelegated() {
9046         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9047 
9048         mService.reportSeen(r);
9049         verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt());
9050     }
9051 
9052     @Test
testNotificationStats_notificationError()9053     public void testNotificationStats_notificationError() {
9054         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9055         mService.addNotification(r);
9056 
9057         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, r.getSbn().getId(),
9058                 r.getSbn().getTag(), mUid, 0,
9059                 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(),
9060                 UserHandle.getUserHandleForUid(mUid), null, 0);
9061         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9062         mService.addEnqueuedNotification(update);
9063         assertNull(update.getSbn().getNotification().getSmallIcon());
9064 
9065         NotificationManagerService.PostNotificationRunnable runnable =
9066                 mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(),
9067                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
9068         runnable.run();
9069         waitForIdle();
9070 
9071         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
9072         verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture());
9073         assertNotNull(captor.getValue());
9074     }
9075 
9076     @Test
testCanNotifyAsUser_crossUser()9077     public void testCanNotifyAsUser_crossUser() throws Exception {
9078         // same user no problem
9079         mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId());
9080 
9081         // cross user, no permission, problem
9082         try {
9083             mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
9084             fail("Should not be callable cross user without cross user permission");
9085         } catch (SecurityException e) {
9086             // good
9087         }
9088 
9089         // cross user, with permission, no problem
9090         enableInteractAcrossUsers();
9091         mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
9092     }
9093 
9094     @Test
testGetNotificationChannels_crossUser()9095     public void testGetNotificationChannels_crossUser() throws Exception {
9096         // same user no problem
9097         mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
9098 
9099         // cross user, no permission, problem
9100         try {
9101             mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
9102             fail("Should not be callable cross user without cross user permission");
9103         } catch (SecurityException e) {
9104             // good
9105         }
9106 
9107         // cross user, with permission, no problem
9108         enableInteractAcrossUsers();
9109         mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
9110     }
9111 
9112     @Test
setDefaultAssistantForUser_fromConfigXml()9113     public void setDefaultAssistantForUser_fromConfigXml() {
9114         ComponentName xmlConfig = new ComponentName("config", "xml");
9115         ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(xmlConfig));
9116         when(mResources
9117                 .getString(
9118                         com.android.internal.R.string.config_defaultAssistantAccessComponent))
9119                 .thenReturn(xmlConfig.flattenToString());
9120         when(mContext.getResources()).thenReturn(mResources);
9121         when(mAssistants.queryPackageForServices(eq(null), anyInt(), anyInt()))
9122                 .thenReturn(components);
9123         when(mAssistants.getDefaultComponents())
9124                 .thenReturn(components);
9125         mService.setNotificationAssistantAccessGrantedCallback(
9126                 mNotificationAssistantAccessGrantedCallback);
9127 
9128 
9129         mService.setDefaultAssistantForUser(0);
9130 
9131         verify(mNotificationAssistantAccessGrantedCallback)
9132                 .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
9133     }
9134 
9135     @Test
clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne()9136     public void clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne() throws RemoteException {
9137         ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
9138                 generateResetComponentValues();
9139         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners);
9140         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
9141         ComponentName deviceConfig1 = new ComponentName("device", "config1");
9142         ComponentName deviceConfig2 = new ComponentName("device", "config2");
9143         changes.put(true, new ArrayList(Arrays.asList(deviceConfig1, deviceConfig2)));
9144         changes.put(false, new ArrayList());
9145         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes);
9146         mService.getBinderService().clearData("device", 0, false);
9147         verify(mAssistants, times(1))
9148                 .setPackageOrComponentEnabled(
9149                         eq("device/config2"),
9150                         eq(0), eq(true), eq(false));
9151         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
9152                 eq("device"), eq(0), eq(false), eq(true));
9153     }
9154 
9155     @Test
testNASSettingUpgrade_userSetNull()9156     public void testNASSettingUpgrade_userSetNull() throws RemoteException {
9157         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component1");
9158         TestableNotificationManagerService service = spy(mService);
9159         int userId = 11;
9160         setUsers(new int[]{userId});
9161         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
9162         setNASMigrationDone(false, userId);
9163         when(mAssistants.getDefaultFromConfig())
9164                 .thenReturn(newDefaultComponent);
9165         when(mAssistants.getAllowedComponents(anyInt()))
9166                 .thenReturn(new ArrayList<>());
9167         when(mAssistants.hasUserSet(userId)).thenReturn(true);
9168 
9169         service.migrateDefaultNAS();
9170         assertTrue(service.isNASMigrationDone(userId));
9171         verify(mAssistants, times(1)).clearDefaults();
9172     }
9173 
9174     @Test
testNASSettingUpgrade_userSet()9175     public void testNASSettingUpgrade_userSet() throws RemoteException {
9176         ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1");
9177         TestableNotificationManagerService service = spy(mService);
9178         int userId = 11;
9179         setUsers(new int[]{userId});
9180         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
9181         setNASMigrationDone(false, userId);
9182         when(mAssistants.getDefaultFromConfig())
9183                 .thenReturn(defaultComponent);
9184         when(mAssistants.getAllowedComponents(anyInt()))
9185                 .thenReturn(new ArrayList(Arrays.asList(defaultComponent)));
9186         when(mAssistants.hasUserSet(userId)).thenReturn(true);
9187 
9188         service.migrateDefaultNAS();
9189         verify(mAssistants, times(1)).setUserSet(userId, false);
9190         //resetDefaultAssistantsIfNecessary should invoke from readPolicyXml() and migration
9191         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
9192     }
9193 
9194     @Test
testNASSettingUpgrade_multiUser()9195     public void testNASSettingUpgrade_multiUser() throws RemoteException {
9196         ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
9197         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
9198         TestableNotificationManagerService service = spy(mService);
9199         int userId1 = 11;
9200         int userId2 = 12;
9201         setUsers(new int[]{userId1, userId2});
9202         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1});
9203         when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2});
9204 
9205         setNASMigrationDone(false, userId1);
9206         setNASMigrationDone(false, userId2);
9207         when(mAssistants.getDefaultComponents())
9208                 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)));
9209         when(mAssistants.getDefaultFromConfig())
9210                 .thenReturn(newDefaultComponent);
9211         //User1: set different NAS
9212         when(mAssistants.getAllowedComponents(userId1))
9213                 .thenReturn(Arrays.asList(oldDefaultComponent));
9214         //User2: set to none
9215         when(mAssistants.getAllowedComponents(userId2))
9216                 .thenReturn(new ArrayList<>());
9217 
9218         when(mAssistants.hasUserSet(userId1)).thenReturn(true);
9219         when(mAssistants.hasUserSet(userId2)).thenReturn(true);
9220 
9221         service.migrateDefaultNAS();
9222         // user1's setting get reset
9223         verify(mAssistants, times(1)).setUserSet(userId1, false);
9224         verify(mAssistants, times(0)).setUserSet(eq(userId2), anyBoolean());
9225         assertTrue(service.isNASMigrationDone(userId2));
9226 
9227     }
9228 
9229     @Test
testNASSettingUpgrade_multiProfile()9230     public void testNASSettingUpgrade_multiProfile() throws RemoteException {
9231         ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
9232         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
9233         TestableNotificationManagerService service = spy(mService);
9234         int userId1 = 11;
9235         int userId2 = 12; //work profile
9236         setUsers(new int[]{userId1, userId2});
9237         when(mUm.isManagedProfile(userId2)).thenReturn(true);
9238         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2});
9239 
9240         setNASMigrationDone(false, userId1);
9241         setNASMigrationDone(false, userId2);
9242         when(mAssistants.getDefaultComponents())
9243                 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)));
9244         when(mAssistants.getDefaultFromConfig())
9245                 .thenReturn(newDefaultComponent);
9246         //Both profiles: set different NAS
9247         when(mAssistants.getAllowedComponents(userId1))
9248                 .thenReturn(Arrays.asList(oldDefaultComponent));
9249         when(mAssistants.getAllowedComponents(userId2))
9250                 .thenReturn(Arrays.asList(oldDefaultComponent));
9251 
9252         when(mAssistants.hasUserSet(userId1)).thenReturn(true);
9253         when(mAssistants.hasUserSet(userId2)).thenReturn(true);
9254 
9255         service.migrateDefaultNAS();
9256         assertFalse(service.isNASMigrationDone(userId1));
9257         assertFalse(service.isNASMigrationDone(userId2));
9258     }
9259 
9260 
9261 
9262     @Test
testNASSettingUpgrade_clearDataAfterMigrationIsDone()9263     public void testNASSettingUpgrade_clearDataAfterMigrationIsDone() throws RemoteException {
9264         ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component");
9265         TestableNotificationManagerService service = spy(mService);
9266         int userId = 12;
9267         setUsers(new int[]{userId});
9268         when(mAssistants.getDefaultComponents())
9269                 .thenReturn(new ArraySet<>(Arrays.asList(defaultComponent)));
9270         when(mAssistants.hasUserSet(userId)).thenReturn(true);
9271         setNASMigrationDone(true, userId);
9272 
9273         //Test User clear data
9274         ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
9275                 generateResetComponentValues();
9276         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners);
9277         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
9278         changes.put(true, new ArrayList(Arrays.asList(defaultComponent)));
9279         changes.put(false, new ArrayList());
9280         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes);
9281 
9282         //Clear data
9283         service.getBinderService().clearData("package", userId, false);
9284         //Test migrate flow again
9285         service.migrateDefaultNAS();
9286 
9287         //Migration should not happen again
9288         verify(mAssistants, times(0)).setUserSet(userId, false);
9289         verify(mAssistants, times(0)).clearDefaults();
9290         //resetDefaultAssistantsIfNecessary should only invoke once from readPolicyXml()
9291         verify(mAssistants, times(1)).resetDefaultAssistantsIfNecessary();
9292 
9293     }
9294 
setNASMigrationDone(boolean done, int userId)9295     private void setNASMigrationDone(boolean done, int userId) {
9296         Settings.Secure.putIntForUser(mContext.getContentResolver(),
9297                 Settings.Secure.NAS_SETTINGS_UPDATED, done ? 1 : 0, userId);
9298     }
9299 
setUsers(int[] userIds)9300     private void setUsers(int[] userIds) {
9301         List<UserInfo> users = new ArrayList<>();
9302         for (int id: userIds) {
9303             users.add(new UserInfo(id, String.valueOf(id), 0));
9304         }
9305         for (UserInfo user : users) {
9306             when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
9307         }
9308         when(mUm.getUsers()).thenReturn(users);
9309     }
9310 
9311     @Test
clearDefaultListenersPackageShouldEnableIt()9312     public void clearDefaultListenersPackageShouldEnableIt() throws RemoteException {
9313         ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants =
9314                 generateResetComponentValues();
9315         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changedAssistants);
9316         ComponentName deviceConfig = new ComponentName("device", "config");
9317         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
9318         changes.put(true, new ArrayList(Arrays.asList(deviceConfig)));
9319         changes.put(false, new ArrayList());
9320         when(mListeners.resetComponents(anyString(), anyInt()))
9321             .thenReturn(changes);
9322         mService.getBinderService().clearData("device", 0, false);
9323         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
9324                 eq("device"), eq(0), eq(false), eq(true));
9325     }
9326 
9327     @Test
clearDefaultDnDPackageShouldEnableIt()9328     public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException {
9329         ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues();
9330         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed);
9331         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed);
9332         mService.getBinderService().clearData("pkgName", 0, false);
9333         verify(mConditionProviders, times(1)).resetPackage(
9334                         eq("pkgName"), eq(0));
9335     }
9336 
9337     @Test
testFlagBubble()9338     public void testFlagBubble() throws RemoteException {
9339         setUpPrefsForBubbles(mPkg, mUid,
9340                 true /* global */,
9341                 BUBBLE_PREFERENCE_ALL /* app */,
9342                 true /* channel */);
9343 
9344         NotificationRecord nr =
9345                 generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble");
9346 
9347         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9348                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9349         waitForIdle();
9350 
9351         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9352         assertEquals(1, notifs.length);
9353         assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0);
9354         assertTrue(mService.getNotificationRecord(
9355                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9356     }
9357 
9358     @Test
testFlagBubble_noFlag_appNotAllowed()9359     public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException {
9360         setUpPrefsForBubbles(mPkg, mUid,
9361                 true /* global */,
9362                 BUBBLE_PREFERENCE_NONE /* app */,
9363                 true /* channel */);
9364 
9365         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
9366                         "testFlagBubble_noFlag_appNotAllowed");
9367 
9368         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9369                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9370         waitForIdle();
9371 
9372         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9373         assertEquals(1, notifs.length);
9374         assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0);
9375         assertFalse(mService.getNotificationRecord(
9376                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9377     }
9378 
9379     @Test
testFlagBubbleNotifs_noFlag_whenAppForeground()9380     public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException {
9381         setUpPrefsForBubbles(mPkg, mUid,
9382                 true /* global */,
9383                 BUBBLE_PREFERENCE_ALL /* app */,
9384                 true /* channel */);
9385 
9386         // Notif with bubble metadata but not our other misc requirements
9387         Notification.Builder nb = new Notification.Builder(mContext,
9388                 mTestNotificationChannel.getId())
9389                 .setContentTitle("foo")
9390                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
9391                 .setBubbleMetadata(getBubbleMetadata());
9392         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 0,
9393                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
9394         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9395 
9396         // Say we're foreground
9397         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
9398                 IMPORTANCE_FOREGROUND);
9399         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9400                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9401         waitForIdle();
9402 
9403         // if notif isn't configured properly it doesn't get to bubble just because app is
9404         // foreground.
9405         assertFalse(mService.getNotificationRecord(
9406                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9407     }
9408 
9409     @Test
testFlagBubbleNotifs_flag_messaging()9410     public void testFlagBubbleNotifs_flag_messaging() throws RemoteException {
9411         setUpPrefsForBubbles(mPkg, mUid,
9412                 true /* global */,
9413                 BUBBLE_PREFERENCE_ALL /* app */,
9414                 true /* channel */);
9415 
9416         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
9417                 "testFlagBubbleNotifs_flag_messaging");
9418 
9419         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9420                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9421         waitForIdle();
9422 
9423         // yes allowed, yes messaging, yes bubble
9424         assertTrue(mService.getNotificationRecord(
9425                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9426     }
9427 
9428     @Test
testFlagBubbleNotifs_noFlag_noShortcut()9429     public void testFlagBubbleNotifs_noFlag_noShortcut() throws RemoteException {
9430         setUpPrefsForBubbles(mPkg, mUid,
9431                 true /* global */,
9432                 BUBBLE_PREFERENCE_ALL /* app */,
9433                 true /* channel */);
9434 
9435         Notification.Builder nb = getMessageStyleNotifBuilder(true, null, false, true);
9436         nb.setShortcutId(null);
9437         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
9438                 null, mUid, 0,
9439                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
9440 
9441         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
9442                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
9443         waitForIdle();
9444 
9445         // no shortcut no bubble
9446         assertFalse(mService.getNotificationRecord(
9447                 sbn.getKey()).getNotification().isBubbleNotification());
9448     }
9449 
9450     @Test
testFlagBubbleNotifs_noFlag_messaging_appNotAllowed()9451     public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException {
9452         setUpPrefsForBubbles(mPkg, mUid,
9453                 true /* global */,
9454                 BUBBLE_PREFERENCE_NONE /* app */,
9455                 true /* channel */);
9456 
9457         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
9458                 "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed");
9459 
9460         // Post the notification
9461         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9462                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9463         waitForIdle();
9464 
9465         // not allowed, no bubble
9466         assertFalse(mService.getNotificationRecord(
9467                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9468     }
9469 
9470     @Test
testFlagBubbleNotifs_noFlag_notBubble()9471     public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException {
9472         setUpPrefsForBubbles(mPkg, mUid,
9473                 true /* global */,
9474                 BUBBLE_PREFERENCE_ALL /* app */,
9475                 true /* channel */);
9476 
9477         // Messaging notif WITHOUT bubble metadata
9478         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */,
9479                 null /* groupKey */, false /* isSummary */, true);
9480 
9481         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
9482                 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0,
9483                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
9484         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9485 
9486         // Post the notification
9487         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9488                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9489         waitForIdle();
9490 
9491         // no bubble metadata, no bubble
9492         assertFalse(mService.getNotificationRecord(
9493                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9494     }
9495 
9496     @Test
testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed()9497     public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException {
9498         setUpPrefsForBubbles(mPkg, mUid,
9499                 true /* global */,
9500                 BUBBLE_PREFERENCE_ALL /* app */,
9501                 false /* channel */);
9502 
9503         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
9504                 "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed");
9505         nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE);
9506 
9507         // Post the notification
9508         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9509                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9510         waitForIdle();
9511 
9512         // channel not allowed, no bubble
9513         assertFalse(mService.getNotificationRecord(
9514                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
9515     }
9516 
9517     @Test
testCancelNotificationsFromApp_cancelsBubbles()9518     public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception {
9519         final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
9520         nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
9521 
9522         // Post the notification
9523         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
9524                 "testAppCancelNotifications_cancelsBubbles",
9525                 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(),
9526                 nrBubble.getSbn().getUserId());
9527         waitForIdle();
9528 
9529         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9530         assertEquals(1, notifs.length);
9531         assertEquals(1, mService.getNotificationRecordCount());
9532 
9533         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
9534                 "testAppCancelNotifications_cancelsBubbles", nrBubble.getSbn().getId(),
9535                 nrBubble.getSbn().getUserId());
9536         waitForIdle();
9537 
9538         StatusBarNotification[] notifs2 = mBinderService.getActiveNotifications(mPkg);
9539         assertEquals(0, notifs2.length);
9540         assertEquals(0, mService.getNotificationRecordCount());
9541     }
9542 
9543     @Test
testCancelAllNotificationsFromApp_cancelsBubble()9544     public void testCancelAllNotificationsFromApp_cancelsBubble() throws Exception {
9545         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
9546         nr.getSbn().getNotification().flags |= FLAG_BUBBLE;
9547         mService.addNotification(nr);
9548 
9549         mBinderService.cancelAllNotifications(mPkg, nr.getSbn().getUserId());
9550         waitForIdle();
9551 
9552         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9553         assertEquals(0, notifs.length);
9554         assertEquals(0, mService.getNotificationRecordCount());
9555     }
9556 
9557     @Test
testCancelAllNotificationsFromListener_ignoresBubbles()9558     public void testCancelAllNotificationsFromListener_ignoresBubbles() throws Exception {
9559         final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel);
9560         final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
9561         nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
9562 
9563         mService.addNotification(nrNormal);
9564         mService.addNotification(nrBubble);
9565 
9566         mService.getBinderService().cancelNotificationsFromListener(null, null);
9567         waitForIdle();
9568 
9569         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9570         assertEquals(1, notifs.length);
9571         assertEquals(1, mService.getNotificationRecordCount());
9572     }
9573 
9574     @Test
testCancelNotificationsFromListener_cancelsNonBubble()9575     public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception {
9576         // Add non-bubble notif
9577         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
9578         mService.addNotification(nr);
9579 
9580         // Cancel via listener
9581         String[] keys = {nr.getSbn().getKey()};
9582         mService.getBinderService().cancelNotificationsFromListener(null, keys);
9583         waitForIdle();
9584 
9585         // Notif not active anymore
9586         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9587         assertEquals(0, notifs.length);
9588         assertEquals(0, mService.getNotificationRecordCount());
9589         // Cancel event is logged
9590         assertEquals(1, mNotificationRecordLogger.numCalls());
9591         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
9592             .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
9593     }
9594 
9595     @Test
testCancelNotificationsFromListener_suppressesBubble()9596     public void testCancelNotificationsFromListener_suppressesBubble() throws Exception {
9597         // Add bubble notif
9598         setUpPrefsForBubbles(mPkg, mUid,
9599             true /* global */,
9600             BUBBLE_PREFERENCE_ALL /* app */,
9601             true /* channel */);
9602         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
9603 
9604         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
9605             nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
9606         waitForIdle();
9607 
9608         // Cancel via listener
9609         String[] keys = {nr.getSbn().getKey()};
9610         mService.getBinderService().cancelNotificationsFromListener(null, keys);
9611         waitForIdle();
9612 
9613         // Bubble notif active and suppressed
9614         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9615         assertEquals(1, notifs.length);
9616         assertEquals(1, mService.getNotificationRecordCount());
9617         assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed());
9618     }
9619 
9620     @Test
testCancelAllNotificationsFromStatusBar_ignoresBubble()9621     public void testCancelAllNotificationsFromStatusBar_ignoresBubble() throws Exception {
9622         // GIVEN a notification bubble
9623         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
9624         nr.getSbn().getNotification().flags |= FLAG_BUBBLE;
9625         mService.addNotification(nr);
9626 
9627         // WHEN the status bar clears all notifications
9628         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
9629                 nr.getSbn().getUserId());
9630         waitForIdle();
9631 
9632         // THEN the bubble notification does not get removed
9633         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
9634         assertEquals(1, notifs.length);
9635         assertEquals(1, mService.getNotificationRecordCount());
9636     }
9637 
9638 
9639     @Test
testGetAllowedAssistantAdjustments()9640     public void testGetAllowedAssistantAdjustments() throws Exception {
9641         List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null);
9642         assertNotNull(adjustments);
9643     }
9644 
9645     @Test
testAdjustRestrictedKey()9646     public void testAdjustRestrictedKey() throws Exception {
9647         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9648         mService.addNotification(r);
9649         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
9650 
9651         when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true);
9652         when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false);
9653 
9654         Bundle signals = new Bundle();
9655         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
9656         signals.putInt(KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
9657         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
9658                "", r.getUser().getIdentifier());
9659 
9660         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
9661         r.applyAdjustments();
9662 
9663         assertEquals(IMPORTANCE_LOW, r.getAssistantImportance());
9664         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
9665     }
9666 
9667     @Test
testAutomaticZenRuleValidation_policyFilterAgreement()9668     public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception {
9669         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
9670                 .thenReturn(true);
9671         mService.setZenHelper(mock(ZenModeHelper.class));
9672         ComponentName owner = new ComponentName(mContext, this.getClass());
9673         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
9674         boolean isEnabled = true;
9675         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
9676                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
9677 
9678         try {
9679             mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
9680             fail("Zen policy only applies to priority only mode");
9681         } catch (IllegalArgumentException e) {
9682             // yay
9683         }
9684 
9685         rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
9686                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
9687         mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
9688 
9689         rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
9690                 null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
9691         mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
9692     }
9693 
9694     @Test
testAddAutomaticZenRule_systemCallTakesPackageFromOwner()9695     public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
9696         mService.isSystemUid = true;
9697         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
9698         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
9699                 .thenReturn(true);
9700         mService.setZenHelper(mockZenModeHelper);
9701         ComponentName owner = new ComponentName("android", "ProviderName");
9702         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
9703         boolean isEnabled = true;
9704         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
9705                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
9706         mBinderService.addAutomaticZenRule(rule, "com.android.settings", false);
9707 
9708         // verify that zen mode helper gets passed in a package name of "android"
9709         verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule),
9710                 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), anyInt());
9711     }
9712 
9713     @Test
testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner()9714     public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception {
9715         // The multi-user case: where the calling uid doesn't match the system uid, but the calling
9716         // *appid* is the system.
9717         mService.isSystemUid = false;
9718         mService.isSystemAppId = true;
9719         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
9720         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
9721                 .thenReturn(true);
9722         mService.setZenHelper(mockZenModeHelper);
9723         ComponentName owner = new ComponentName("android", "ProviderName");
9724         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
9725         boolean isEnabled = true;
9726         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
9727                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
9728         mBinderService.addAutomaticZenRule(rule, "com.android.settings", false);
9729 
9730         // verify that zen mode helper gets passed in a package name of "android"
9731         verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule),
9732                 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), anyInt());
9733     }
9734 
9735     @Test
testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg()9736     public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
9737         mService.isSystemUid = false;
9738         mService.isSystemAppId = false;
9739         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
9740         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
9741                 .thenReturn(true);
9742         mService.setZenHelper(mockZenModeHelper);
9743         ComponentName owner = new ComponentName("android", "ProviderName");
9744         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
9745         boolean isEnabled = true;
9746         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
9747                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
9748         mBinderService.addAutomaticZenRule(rule, "another.package", false);
9749 
9750         // verify that zen mode helper gets passed in the package name from the arg, not the owner
9751         verify(mockZenModeHelper).addAutomaticZenRule(
9752                 eq("another.package"), eq(rule), eq(ZenModeConfig.UPDATE_ORIGIN_APP),
9753                 anyString(), anyInt());  // doesn't count as a system/systemui call
9754     }
9755 
9756     @Test
9757     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners()9758     public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception {
9759         ZenModeHelper zenModeHelper = setUpMockZenTest();
9760         mService.setCallerIsNormalPackage();
9761 
9762         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
9763                 .setType(AutomaticZenRule.TYPE_MANAGED)
9764                 .setOwner(new ComponentName(mPkg, "cls"))
9765                 .build();
9766         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
9767 
9768         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
9769 
9770         verify(zenModeHelper).addAutomaticZenRule(eq(mPkg), eq(rule), anyInt(), any(), anyInt());
9771     }
9772 
9773     @Test
9774     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeManagedCanBeUsedBySystem()9775     public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception {
9776         addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED);
9777     }
9778 
9779     @Test
9780     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps()9781     public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception {
9782         addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
9783                 AutomaticZenRule.TYPE_MANAGED);
9784     }
9785 
9786     @Test
9787     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing()9788     public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception {
9789         ZenModeHelper zenModeHelper = setUpMockZenTest();
9790         mService.setCallerIsNormalPackage();
9791         reset(mPackageManagerInternal);
9792         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
9793         when(mResources
9794                 .getString(com.android.internal.R.string.config_systemWellbeing))
9795                 .thenReturn(mPkg);
9796         when(mContext.getResources()).thenReturn(mResources);
9797 
9798         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
9799                 .setType(AutomaticZenRule.TYPE_BEDTIME)
9800                 .setOwner(new ComponentName(mPkg, "cls"))
9801                 .build();
9802 
9803         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
9804 
9805         verify(zenModeHelper).addAutomaticZenRule(eq(mPkg), eq(rule), anyInt(), any(), anyInt());
9806     }
9807 
9808     @Test
9809     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem()9810     public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception {
9811         reset(mPackageManagerInternal);
9812         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
9813         addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME);
9814     }
9815 
9816     @Test
9817     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps()9818     public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception {
9819         reset(mPackageManagerInternal);
9820         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
9821         addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
9822                 AutomaticZenRule.TYPE_BEDTIME);
9823     }
9824 
addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( @utomaticZenRule.Type int ruleType)9825     private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(
9826             @AutomaticZenRule.Type int ruleType) throws Exception {
9827         ZenModeHelper zenModeHelper = setUpMockZenTest();
9828         mService.isSystemUid = true;
9829 
9830         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
9831                 .setType(ruleType)
9832                 .setOwner(new ComponentName(mPkg, "cls"))
9833                 .build();
9834         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
9835 
9836         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
9837 
9838         verify(zenModeHelper).addAutomaticZenRule(eq(mPkg), eq(rule), anyInt(), any(), anyInt());
9839     }
9840 
addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( @utomaticZenRule.Type int ruleType)9841     private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
9842             @AutomaticZenRule.Type int ruleType) {
9843         mService.setCallerIsNormalPackage();
9844         mService.setZenHelper(mock(ZenModeHelper.class));
9845         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
9846                 .thenReturn(true);
9847 
9848         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
9849                 .setType(ruleType)
9850                 .setOwner(new ComponentName(mPkg, "cls"))
9851                 .build();
9852         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false);
9853 
9854         assertThrows(IllegalArgumentException.class,
9855                 () -> mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false));
9856     }
9857 
9858     @Test
9859     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromUser_mappedToOriginUser()9860     public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception {
9861         ZenModeHelper zenModeHelper = setUpMockZenTest();
9862         mService.isSystemUid = true;
9863 
9864         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true);
9865 
9866         verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(SOME_ZEN_RULE),
9867                 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyString(), anyInt());
9868     }
9869 
9870     @Test
9871     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem()9872     public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception {
9873         ZenModeHelper zenModeHelper = setUpMockZenTest();
9874         mService.isSystemUid = true;
9875 
9876         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false);
9877 
9878         verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(SOME_ZEN_RULE),
9879                 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), anyInt());
9880     }
9881 
9882     @Test
9883     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromApp_mappedToOriginApp()9884     public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception {
9885         ZenModeHelper zenModeHelper = setUpMockZenTest();
9886         mService.setCallerIsNormalPackage();
9887 
9888         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false);
9889 
9890         verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(SOME_ZEN_RULE),
9891                 eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyString(), anyInt());
9892     }
9893 
9894     @Test
9895     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromAppFromUser_blocked()9896     public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception {
9897         setUpMockZenTest();
9898         mService.setCallerIsNormalPackage();
9899 
9900         assertThrows(SecurityException.class, () ->
9901                 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true));
9902     }
9903 
9904     @Test
9905     @EnableFlags(android.app.Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromUserFromSystem_allowed()9906     public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
9907         ZenModeHelper zenModeHelper = setUpMockZenTest();
9908         mService.isSystemUid = true;
9909 
9910         mBinderService.updateAutomaticZenRule("id", SOME_ZEN_RULE, /* fromUser= */ true);
9911 
9912         verify(zenModeHelper).updateAutomaticZenRule(eq("id"), eq(SOME_ZEN_RULE),
9913                 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyString(), anyInt());
9914     }
9915 
9916     @Test
9917     @EnableFlags(android.app.Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromUserFromApp_blocked()9918     public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
9919         setUpMockZenTest();
9920         mService.setCallerIsNormalPackage();
9921 
9922         assertThrows(SecurityException.class, () ->
9923                 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true));
9924     }
9925 
9926     @Test
9927     @EnableFlags(android.app.Flags.FLAG_MODES_API)
removeAutomaticZenRule_fromUserFromSystem_allowed()9928     public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
9929         ZenModeHelper zenModeHelper = setUpMockZenTest();
9930         mService.isSystemUid = true;
9931 
9932         mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true);
9933 
9934         verify(zenModeHelper).removeAutomaticZenRule(eq("id"),
9935                 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyString(), anyInt());
9936     }
9937 
9938     @Test
9939     @EnableFlags(android.app.Flags.FLAG_MODES_API)
removeAutomaticZenRule_fromUserFromApp_blocked()9940     public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
9941         setUpMockZenTest();
9942         mService.setCallerIsNormalPackage();
9943 
9944         assertThrows(SecurityException.class, () ->
9945                 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true));
9946     }
9947 
9948     @Test
9949     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_conditionFromUser_mappedToOriginUser()9950     public void setAutomaticZenRuleState_conditionFromUser_mappedToOriginUser() throws Exception {
9951         ZenModeHelper zenModeHelper = setUpMockZenTest();
9952         mService.setCallerIsNormalPackage();
9953 
9954         Condition withSourceUser = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
9955                 SOURCE_USER_ACTION);
9956         mBinderService.setAutomaticZenRuleState("id", withSourceUser);
9957 
9958         verify(zenModeHelper).setAutomaticZenRuleState(eq("id"), eq(withSourceUser),
9959                 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyInt());
9960     }
9961 
9962     @Test
9963     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_fromAppWithConditionNotFromUser_mappedToOriginApp()9964     public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_mappedToOriginApp()
9965             throws Exception {
9966         ZenModeHelper zenModeHelper = setUpMockZenTest();
9967         mService.setCallerIsNormalPackage();
9968 
9969         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
9970                 SOURCE_CONTEXT);
9971         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
9972 
9973         verify(zenModeHelper).setAutomaticZenRuleState(eq("id"), eq(withSourceContext),
9974                 eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyInt());
9975     }
9976 
9977     @Test
9978     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_mappedToOriginSystem()9979     public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_mappedToOriginSystem()
9980             throws Exception {
9981         ZenModeHelper zenModeHelper = setUpMockZenTest();
9982         mService.isSystemUid = true;
9983 
9984         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
9985                 SOURCE_CONTEXT);
9986         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
9987 
9988         verify(zenModeHelper).setAutomaticZenRuleState(eq("id"), eq(withSourceContext),
9989                 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyInt());
9990     }
9991 
9992     /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */
setUpMockZenTest()9993     private ZenModeHelper setUpMockZenTest() {
9994         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
9995         mService.setZenHelper(zenModeHelper);
9996         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
9997                 .thenReturn(true);
9998         return zenModeHelper;
9999     }
10000 
10001     @Test
onZenModeChanged_sendsBroadcasts()10002     public void onZenModeChanged_sendsBroadcasts() throws Exception {
10003         when(mAmi.getCurrentUserId()).thenReturn(100);
10004         when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
10005         when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
10006             @Override
10007             public List<String> answer(InvocationOnMock invocation) {
10008                 int userId = invocation.getArgument(0);
10009                 switch (userId) {
10010                     case 100:
10011                         return Lists.newArrayList("a", "b", "c");
10012                     case 101:
10013                         return Lists.newArrayList();
10014                     case 102:
10015                         return Lists.newArrayList("b");
10016                     default:
10017                         throw new IllegalArgumentException(
10018                                 "Why would you ask for packages of userId " + userId + "?");
10019                 }
10020             }
10021         });
10022 
10023         mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
10024                 "testing!", false);
10025         waitForIdle();
10026 
10027         InOrder inOrder = inOrder(mContext);
10028         // Verify broadcasts for registered receivers
10029         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
10030                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
10031                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null));
10032         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
10033                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
10034                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null));
10035         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
10036                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
10037                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null));
10038 
10039         // Verify broadcast for packages that manage DND.
10040         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
10041                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags(
10042                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
10043         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
10044                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
10045                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
10046         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
10047                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags(
10048                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
10049         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
10050                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
10051                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102)));
10052     }
10053 
eqIntent(Intent wanted)10054     private static Intent eqIntent(Intent wanted) {
10055         return ArgumentMatchers.argThat(
10056                 new ArgumentMatcher<Intent>() {
10057                     @Override
10058                     public boolean matches(Intent argument) {
10059                         return wanted.filterEquals(argument)
10060                                 && wanted.getFlags() == argument.getFlags();
10061                     }
10062 
10063                     @Override
10064                     public String toString() {
10065                         return wanted.toString();
10066                     }
10067                 });
10068     }
10069 
10070     @Test
10071     public void testAreNotificationsEnabledForPackage() throws Exception {
10072         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
10073                 mUid);
10074 
10075         verify(mPermissionHelper).hasPermission(mUid);
10076     }
10077 
10078     @Test
10079     public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
10080         try {
10081             mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
10082                     mUid + UserHandle.PER_USER_RANGE);
10083             fail("Cannot call cross user without permission");
10084         } catch (SecurityException e) {
10085             // pass
10086         }
10087         verify(mPermissionHelper, never()).hasPermission(anyInt());
10088 
10089         // cross user, with permission, no problem
10090         enableInteractAcrossUsers();
10091         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
10092                 mUid + UserHandle.PER_USER_RANGE);
10093 
10094         verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
10095     }
10096 
10097     @Test
10098     public void testAreNotificationsEnabledForPackage_viaInternalService() {
10099         mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
10100         verify(mPermissionHelper).hasPermission(mUid);
10101     }
10102 
10103     @Test
10104     public void testGetPackageImportance() throws Exception {
10105         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
10106         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
10107                 .isEqualTo(IMPORTANCE_DEFAULT);
10108 
10109         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
10110         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
10111                 .isEqualTo(IMPORTANCE_NONE);
10112     }
10113 
10114     @Test
10115     public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
10116         try {
10117             mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
10118                     mUid + UserHandle.PER_USER_RANGE);
10119             fail("Cannot call cross user without permission");
10120         } catch (SecurityException e) {
10121             // pass
10122         }
10123 
10124         // cross user, with permission, no problem
10125         enableInteractAcrossUsers();
10126         mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
10127                 mUid + UserHandle.PER_USER_RANGE);
10128     }
10129 
10130     private void enableInteractAcrossUsers() {
10131         TestablePermissions perms = mContext.getTestablePermissions();
10132         perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
10133     }
10134 
10135     @Test
10136     public void testNotificationBubbleChanged_false() throws Exception {
10137         setUpPrefsForBubbles(mPkg, mUid,
10138                 true /* global */,
10139                 BUBBLE_PREFERENCE_ALL /* app */,
10140                 true /* channel */);
10141 
10142         // Notif with bubble metadata
10143         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10144                 "testNotificationBubbleChanged_false");
10145 
10146         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10147                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10148         waitForIdle();
10149 
10150         // Reset as this is called when the notif is first sent
10151         reset(mListeners);
10152 
10153         // First we were a bubble
10154         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
10155         assertEquals(1, notifsBefore.length);
10156         assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0);
10157 
10158         // Notify we're not a bubble
10159         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
10160         waitForIdle();
10161 
10162         // Make sure we are not a bubble
10163         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10164         assertEquals(1, notifsAfter.length);
10165         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
10166     }
10167 
10168     @Test
10169     public void testNotificationBubbleChanged_true() throws Exception {
10170         setUpPrefsForBubbles(mPkg, mUid,
10171                 true /* global */,
10172                 BUBBLE_PREFERENCE_ALL /* app */,
10173                 true /* channel */);
10174 
10175         // Notif that is not a bubble
10176         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
10177                 1, null, false);
10178         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10179                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10180         waitForIdle();
10181 
10182         // Would be a normal notification because wouldn't have met requirements to bubble
10183         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
10184         assertEquals(1, notifsBefore.length);
10185         assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
10186 
10187         // Update the notification to be message style / meet bubble requirements
10188         NotificationRecord nr2 = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10189                 nr.getSbn().getTag());
10190         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr2.getSbn().getTag(),
10191                 nr2.getSbn().getId(), nr2.getSbn().getNotification(), nr2.getSbn().getUserId());
10192         waitForIdle();
10193 
10194         // Reset as this is called when the notif is first sent
10195         reset(mListeners);
10196 
10197         // Notify we are now a bubble
10198         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
10199         waitForIdle();
10200 
10201         // Make sure we are a bubble
10202         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10203         assertEquals(1, notifsAfter.length);
10204         assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
10205     }
10206 
10207     @Test
10208     public void testNotificationBubbleChanged_true_notAllowed() throws Exception {
10209         setUpPrefsForBubbles(mPkg, mUid,
10210                 true /* global */,
10211                 BUBBLE_PREFERENCE_ALL /* app */,
10212                 true /* channel */);
10213 
10214         // Notif that is not a bubble
10215         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10216         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10217                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10218         waitForIdle();
10219 
10220         // Reset as this is called when the notif is first sent
10221         reset(mListeners);
10222 
10223         // Would be a normal notification because wouldn't have met requirements to bubble
10224         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
10225         assertEquals(1, notifsBefore.length);
10226         assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
10227 
10228         // Notify we are now a bubble
10229         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
10230         waitForIdle();
10231 
10232         // We still wouldn't be a bubble because the notification didn't meet requirements
10233         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10234         assertEquals(1, notifsAfter.length);
10235         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
10236     }
10237 
10238     @Test
10239     public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception {
10240         setUpPrefsForBubbles(mPkg, mUid,
10241                 true /* global */,
10242                 BUBBLE_PREFERENCE_ALL /* app */,
10243                 true /* channel */);
10244 
10245         // Notif with bubble metadata
10246         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10247                 "testNotificationBubbleIsFlagRemoved_resetOnUpdate");
10248 
10249         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10250                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10251         waitForIdle();
10252         // Flag shouldn't be modified
10253         NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
10254         assertFalse(recordToCheck.isFlagBubbleRemoved());
10255 
10256         // Notify we're not a bubble
10257         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
10258         waitForIdle();
10259         // Flag should be modified
10260         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
10261         assertTrue(recordToCheck.isFlagBubbleRemoved());
10262 
10263 
10264         // Update the notif
10265         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10266                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10267         waitForIdle();
10268         // And the flag is reset
10269         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
10270         assertFalse(recordToCheck.isFlagBubbleRemoved());
10271     }
10272 
10273     @Test
10274     public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception {
10275         setUpPrefsForBubbles(mPkg, mUid,
10276                 true /* global */,
10277                 BUBBLE_PREFERENCE_ALL /* app */,
10278                 true /* channel */);
10279 
10280         // Notif with bubble metadata
10281         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10282                 "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue");
10283 
10284         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10285                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10286         waitForIdle();
10287         // Flag shouldn't be modified
10288         NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
10289         assertFalse(recordToCheck.isFlagBubbleRemoved());
10290 
10291         // Notify we're not a bubble
10292         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
10293         waitForIdle();
10294         // Flag should be modified
10295         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
10296         assertTrue(recordToCheck.isFlagBubbleRemoved());
10297 
10298         // Notify we are a bubble
10299         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
10300         waitForIdle();
10301         // And the flag is reset
10302         assertFalse(recordToCheck.isFlagBubbleRemoved());
10303     }
10304 
10305     @Test
10306     public void testOnBubbleMetadataFlagChanged() throws Exception {
10307         setUpPrefsForBubbles(mPkg, mUid,
10308                 true /* global */,
10309                 BUBBLE_PREFERENCE_ALL /* app */,
10310                 true /* channel */);
10311 
10312         // Post a bubble notification
10313         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
10314         // Set this so that the bubble can be suppressed
10315         nr.getNotification().getBubbleMetadata().setFlags(
10316                 Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE);
10317         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10318                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10319         waitForIdle();
10320 
10321         // Check the flags
10322         Notification n =  mBinderService.getActiveNotifications(mPkg)[0].getNotification();
10323         assertFalse(n.getBubbleMetadata().isNotificationSuppressed());
10324         assertFalse(n.getBubbleMetadata().getAutoExpandBubble());
10325         assertFalse(n.getBubbleMetadata().isBubbleSuppressed());
10326         assertTrue(n.getBubbleMetadata().isBubbleSuppressable());
10327 
10328         // Reset as this is called when the notif is first sent
10329         reset(mListeners);
10330 
10331         // Test: change the flags
10332         int flags = Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE;
10333         flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
10334         flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
10335         flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
10336         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), flags);
10337         waitForIdle();
10338 
10339         // Check
10340         n =  mBinderService.getActiveNotifications(mPkg)[0].getNotification();
10341         assertEquals(flags, n.getBubbleMetadata().getFlags());
10342 
10343         // Reset to check again
10344         reset(mListeners);
10345 
10346         // Test: clear flags
10347         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 0);
10348         waitForIdle();
10349 
10350         // Check
10351         n = mBinderService.getActiveNotifications(mPkg)[0].getNotification();
10352         assertEquals(0, n.getBubbleMetadata().getFlags());
10353     }
10354 
10355     @Test
10356     public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped()
10357             throws RemoteException {
10358 
10359         setUpPrefsForBubbles(mPkg, mUid,
10360                 true /* global */,
10361                 BUBBLE_PREFERENCE_ALL /* app */,
10362                 true /* channel */);
10363 
10364         // Post a bubble notification
10365         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
10366         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10367                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10368         waitForIdle();
10369 
10370         // Test: suppress notification via bubble metadata update
10371         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(),
10372                 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
10373         waitForIdle();
10374 
10375         // Check audio is stopped
10376         verify(mAttentionHelper).clearEffectsLocked(nr.getKey());
10377     }
10378 
10379     @Test
10380     public void testGrantInlineReplyUriPermission_recordExists() throws Exception {
10381         int userId = UserManager.isHeadlessSystemUserMode()
10382                 ? UserHandle.getUserId(UID_HEADLESS)
10383                 : USER_SYSTEM;
10384 
10385         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
10386         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
10387                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10388         waitForIdle();
10389 
10390         // A notification exists for the given record
10391         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
10392         assertEquals(1, notifsBefore.length);
10393 
10394         reset(mPackageManager);
10395 
10396         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
10397 
10398         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10399                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
10400                 nr.getSbn().getUid());
10401 
10402         // Grant permission called for the UID of SystemUI under the target user ID
10403         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
10404                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
10405                 anyInt(), eq(nr.getSbn().getUserId()));
10406     }
10407 
10408     @Test
10409     public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception {
10410         int userId = UserManager.isHeadlessSystemUserMode()
10411                 ? UserHandle.getUserId(UID_HEADLESS)
10412                 : USER_SYSTEM;
10413 
10414         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
10415         waitForIdle();
10416 
10417         // No notifications exist for the given record
10418         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
10419         assertEquals(0, notifsBefore.length);
10420 
10421         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
10422 
10423         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10424                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
10425                 nr.getSbn().getUid());
10426 
10427         // Grant permission still called if no NotificationRecord exists for the given key
10428         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
10429                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
10430                 anyInt(), eq(nr.getSbn().getUserId()));
10431     }
10432 
10433     @Test
10434     public void testGrantInlineReplyUriPermission_userAll() throws Exception {
10435         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
10436         NotificationRecord nr =
10437                 generateNotificationRecord(mTestNotificationChannel, UserHandle.USER_ALL);
10438         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
10439                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10440         waitForIdle();
10441 
10442         // A notification exists for the given record
10443         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
10444         assertEquals(1, notifsBefore.length);
10445 
10446         reset(mPackageManager);
10447 
10448         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
10449 
10450         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10451                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
10452                 nr.getSbn().getUid());
10453 
10454         // Target user for the grant is USER_ALL instead of USER_SYSTEM
10455         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
10456                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
10457                 anyInt(), UserManager.isHeadlessSystemUserMode()
10458                         ? eq(UserHandle.getUserId(UID_HEADLESS))
10459                         : eq(USER_SYSTEM));
10460     }
10461 
10462     @Test
10463     public void testGrantInlineReplyUriPermission_acrossUsers() throws Exception {
10464         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
10465         int otherUserId = 11;
10466         NotificationRecord nr =
10467                 generateNotificationRecord(mTestNotificationChannel, otherUserId);
10468         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
10469                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10470         waitForIdle();
10471 
10472         // A notification exists for the given record
10473         List<StatusBarNotification> notifsBefore =
10474                 mBinderService.getAppActiveNotifications(mPkg, nr.getSbn().getUserId()).getList();
10475         assertEquals(1, notifsBefore.size());
10476 
10477         reset(mPackageManager);
10478 
10479         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
10480 
10481         int uid = 0; // sysui on primary user
10482         int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user
10483         String sysuiPackage = "sysui";
10484         final String[] sysuiPackages = new String[] { sysuiPackage };
10485         when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages);
10486 
10487         // Make sure to mock call for USER_SYSTEM and not USER_ALL, since it's been replaced by the
10488         // time this is called
10489         when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId))
10490                 .thenReturn(otherUserUid);
10491 
10492         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10493                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), uid);
10494 
10495         // Target user for the grant is USER_ALL instead of USER_SYSTEM
10496         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
10497                 eq(otherUserUid), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), anyInt(),
10498                 eq(otherUserId));
10499     }
10500 
10501     @Test
10502     public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception {
10503         int userId = UserManager.isHeadlessSystemUserMode()
10504                 ? UserHandle.getUserId(UID_HEADLESS)
10505                 : USER_SYSTEM;
10506 
10507         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
10508         reset(mPackageManager);
10509 
10510         Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
10511         Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2);
10512 
10513         // create an inline record with two uris in it
10514         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10515                 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
10516                 nr.getSbn().getUid());
10517         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10518                 nr.getKey(), uri2, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
10519                 nr.getSbn().getUid());
10520 
10521         InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
10522         assertNotNull(record); // record exists
10523         assertEquals(record.getUris().size(), 2); // record has two uris in it
10524 
10525         mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(),
10526                 nr.getSbn().getUid());
10527 
10528         // permissionOwner destroyed
10529         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
10530                 eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId()));
10531     }
10532 
10533 
10534     @Test
10535     public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception {
10536         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0);
10537         reset(mPackageManager);
10538 
10539         mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(),
10540                 nr.getSbn().getUid());
10541 
10542         // no permissionOwner destroyed
10543         verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner(
10544                 any(), eq(null), eq(~0), eq(nr.getUserId()));
10545     }
10546 
10547     @Test
10548     public void testClearInlineReplyUriPermission_userAll() throws Exception {
10549         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
10550                 UserHandle.USER_ALL);
10551         reset(mPackageManager);
10552 
10553         Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
10554 
10555         // create an inline record a uri in it
10556         mService.mNotificationDelegate.grantInlineReplyUriPermission(
10557                 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
10558                 nr.getSbn().getUid());
10559 
10560         InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
10561         assertNotNull(record); // record exists
10562 
10563         mService.mNotificationDelegate.clearInlineReplyUriPermissions(
10564                 nr.getKey(), nr.getSbn().getUid());
10565 
10566         // permissionOwner destroyed for USER_SYSTEM, not USER_ALL
10567         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
10568                 eq(record.getPermissionOwner()), eq(null), eq(~0),
10569                 UserManager.isHeadlessSystemUserMode()
10570                         ? eq(UserHandle.getUserId(UID_HEADLESS))
10571                         : eq(USER_SYSTEM));
10572     }
10573 
10574     @Test
10575     public void testNotificationBubbles_disabled_lowRamDevice() throws Exception {
10576         setUpPrefsForBubbles(mPkg, mUid,
10577                 true /* global */,
10578                 BUBBLE_PREFERENCE_ALL /* app */,
10579                 true /* channel */);
10580 
10581         // And we are low ram
10582         when(mActivityManager.isLowRamDevice()).thenReturn(true);
10583 
10584         // Notification that would typically bubble
10585         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10586                 "testNotificationBubbles_disabled_lowRamDevice");
10587         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10588                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10589         waitForIdle();
10590 
10591         // But we wouldn't be a bubble because the device is low ram & all bubbles are disabled.
10592         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10593         assertEquals(1, notifsAfter.length);
10594         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
10595     }
10596 
10597     @Test
10598     @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
10599     public void testRemoveLargeRemoteViews() throws Exception {
10600         int removeSize = mContext.getResources().getInteger(
10601                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
10602 
10603         RemoteViews rv = mock(RemoteViews.class);
10604         when(rv.estimateMemoryUsage()).thenReturn(removeSize);
10605         when(rv.clone()).thenReturn(rv);
10606         RemoteViews rv1 = mock(RemoteViews.class);
10607         when(rv1.estimateMemoryUsage()).thenReturn(removeSize);
10608         when(rv1.clone()).thenReturn(rv1);
10609         RemoteViews rv2 = mock(RemoteViews.class);
10610         when(rv2.estimateMemoryUsage()).thenReturn(removeSize);
10611         when(rv2.clone()).thenReturn(rv2);
10612         RemoteViews rv3 = mock(RemoteViews.class);
10613         when(rv3.estimateMemoryUsage()).thenReturn(removeSize);
10614         when(rv3.clone()).thenReturn(rv3);
10615         RemoteViews rv4 = mock(RemoteViews.class);
10616         when(rv4.estimateMemoryUsage()).thenReturn(removeSize);
10617         when(rv4.clone()).thenReturn(rv4);
10618         // note: different!
10619         RemoteViews rv5 = mock(RemoteViews.class);
10620         when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1);
10621         when(rv5.clone()).thenReturn(rv5);
10622 
10623         Notification np = new Notification.Builder(mContext, "test")
10624                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
10625                 .setContentText("test")
10626                 .setCustomContentView(rv)
10627                 .setCustomBigContentView(rv1)
10628                 .setCustomHeadsUpContentView(rv2)
10629                 .build();
10630         Notification n = new Notification.Builder(mContext, "test")
10631                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
10632                 .setContentText("test")
10633                 .setCustomContentView(rv3)
10634                 .setCustomBigContentView(rv4)
10635                 .setCustomHeadsUpContentView(rv5)
10636                 .setPublicVersion(np)
10637                 .build();
10638 
10639         assertNotNull(np.contentView);
10640         assertNotNull(np.bigContentView);
10641         assertNotNull(np.headsUpContentView);
10642 
10643         assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
10644         assertNotNull(n.publicVersion.contentView);
10645         assertNotNull(n.publicVersion.bigContentView);
10646         assertNotNull(n.publicVersion.headsUpContentView);
10647 
10648         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
10649 
10650         assertNull(n.contentView);
10651         assertNull(n.bigContentView);
10652         assertNotNull(n.headsUpContentView);
10653         assertNull(n.publicVersion.contentView);
10654         assertNull(n.publicVersion.bigContentView);
10655         assertNull(n.publicVersion.headsUpContentView);
10656 
10657         verify(mUsageStats, times(5)).registerImageRemoved(mPkg);
10658     }
10659 
10660     @Test
10661     @EnableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
10662     public void testRemoveRemoteViews() throws Exception {
10663         Notification np = new Notification.Builder(mContext, "test")
10664                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
10665                 .setContentText("test")
10666                 .setCustomContentView(mock(RemoteViews.class))
10667                 .setCustomBigContentView(mock(RemoteViews.class))
10668                 .setCustomHeadsUpContentView(mock(RemoteViews.class))
10669                 .build();
10670         Notification n = new Notification.Builder(mContext, "test")
10671                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
10672                 .setContentText("test")
10673                 .setCustomContentView(mock(RemoteViews.class))
10674                 .setCustomBigContentView(mock(RemoteViews.class))
10675                 .setCustomHeadsUpContentView(mock(RemoteViews.class))
10676                 .setPublicVersion(np)
10677                 .build();
10678 
10679         assertNotNull(n.contentView);
10680         assertNotNull(n.bigContentView);
10681         assertNotNull(n.headsUpContentView);
10682 
10683         assertTrue(np.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
10684         assertNotNull(np.contentView);
10685         assertNotNull(np.bigContentView);
10686         assertNotNull(np.headsUpContentView);
10687 
10688         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
10689 
10690         assertNull(n.contentView);
10691         assertNull(n.bigContentView);
10692         assertNull(n.headsUpContentView);
10693         assertNull(n.publicVersion.contentView);
10694         assertNull(n.publicVersion.bigContentView);
10695         assertNull(n.publicVersion.headsUpContentView);
10696 
10697         verify(mUsageStats, times(1)).registerImageRemoved(mPkg);
10698     }
10699 
10700     @Test
10701     public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground()
10702             throws Exception {
10703         setUpPrefsForBubbles(mPkg, mUid,
10704                 true /* global */,
10705                 BUBBLE_PREFERENCE_ALL /* app */,
10706                 true /* channel */);
10707 
10708         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10709                 "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground");
10710         // Modify metadata flags
10711         nr.getSbn().getNotification().getBubbleMetadata().setFlags(
10712                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
10713                         | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
10714 
10715         // Ensure we're not foreground
10716         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
10717                 IMPORTANCE_VISIBLE);
10718 
10719         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10720                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10721         waitForIdle();
10722 
10723         // yes allowed, yes messaging, yes bubble
10724         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
10725         assertTrue(notif.isBubbleNotification());
10726 
10727         // The flag should have failed since we're not foreground
10728         assertFalse(notif.getBubbleMetadata().getAutoExpandBubble());
10729     }
10730 
10731     @Test
10732     public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground()
10733             throws RemoteException {
10734         setUpPrefsForBubbles(mPkg, mUid,
10735                 true /* global */,
10736                 BUBBLE_PREFERENCE_ALL /* app */,
10737                 true /* channel */);
10738 
10739         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10740                 "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground");
10741         // Modify metadata flags
10742         nr.getSbn().getNotification().getBubbleMetadata().setFlags(
10743                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
10744                         | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
10745 
10746         // Ensure we are in the foreground
10747         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
10748                 IMPORTANCE_FOREGROUND);
10749 
10750         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10751                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10752         waitForIdle();
10753 
10754         // yes allowed, yes messaging, yes bubble
10755         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
10756         assertTrue(notif.isBubbleNotification());
10757 
10758         // Our flags should have passed since we are foreground
10759         assertTrue(notif.getBubbleMetadata().getAutoExpandBubble());
10760         assertTrue(notif.getBubbleMetadata().isNotificationSuppressed());
10761     }
10762 
10763     @Test
10764     public void testNotificationBubbles_flagRemoved_whenShortcutRemoved()
10765             throws RemoteException {
10766         setUpPrefsForBubbles(mPkg, mUid,
10767                 true /* global */,
10768                 BUBBLE_PREFERENCE_ALL /* app */,
10769                 true /* channel */);
10770 
10771         ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
10772                 ArgumentCaptor.forClass(LauncherApps.Callback.class);
10773 
10774         // Messaging notification with shortcut info
10775         Notification.BubbleMetadata metadata =
10776                 new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build();
10777         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
10778                 null /* groupKey */, false /* isSummary */, true);
10779         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
10780         nb.setBubbleMetadata(metadata);
10781         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
10782                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10783         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10784 
10785         // Test: Send the bubble notification
10786         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10787                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10788         waitForIdle();
10789 
10790         // Verify:
10791 
10792         // Make sure we register the callback for shortcut changes
10793         verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
10794 
10795         // yes allowed, yes messaging w/shortcut, yes bubble
10796         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
10797         assertTrue(notif.isBubbleNotification());
10798 
10799         // Make sure the shortcut is cached.
10800         verify(mShortcutServiceInternal).cacheShortcuts(
10801                 anyInt(), any(), eq(mPkg), eq(singletonList(VALID_CONVO_SHORTCUT_ID)),
10802                 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
10803 
10804         // Test: Remove the shortcut
10805         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
10806         launcherAppsCallback.getValue().onShortcutsChanged(mPkg, emptyList(),
10807                 UserHandle.getUserHandleForUid(mUid));
10808         waitForIdle();
10809 
10810         // Verify:
10811 
10812         // Make sure callback is unregistered
10813         verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
10814 
10815         // We're no longer a bubble
10816         NotificationRecord notif2 = mService.getNotificationRecord(
10817                 nr.getSbn().getKey());
10818         assertNull(notif2.getShortcutInfo());
10819         assertFalse(notif2.getNotification().isBubbleNotification());
10820     }
10821 
10822     @Test
10823     public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved()
10824             throws RemoteException {
10825         final String shortcutId = "someshortcutId";
10826         setUpPrefsForBubbles(mPkg, mUid,
10827                 true /* global */,
10828                 BUBBLE_PREFERENCE_ALL /* app */,
10829                 true /* channel */);
10830 
10831         ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
10832                 ArgumentCaptor.forClass(LauncherApps.Callback.class);
10833 
10834         // Messaging notification with shortcut info
10835         Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
10836                 shortcutId).build();
10837         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
10838                 null /* groupKey */, false /* isSummary */, true);
10839         nb.setShortcutId(shortcutId);
10840         nb.setBubbleMetadata(metadata);
10841         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
10842                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10843         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10844 
10845         // Pretend the shortcut exists
10846         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
10847         ShortcutInfo info = mock(ShortcutInfo.class);
10848         when(info.getPackage()).thenReturn(mPkg);
10849         when(info.getId()).thenReturn(shortcutId);
10850         when(info.getUserId()).thenReturn(USER_SYSTEM);
10851         when(info.isLongLived()).thenReturn(true);
10852         when(info.isEnabled()).thenReturn(true);
10853         shortcutInfos.add(info);
10854         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
10855         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
10856                 anyString(), anyInt(), any())).thenReturn(true);
10857 
10858         // Test: Send the bubble notification
10859         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10860                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10861         waitForIdle();
10862 
10863         // Verify:
10864 
10865         // Make sure we register the callback for shortcut changes
10866         verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
10867 
10868         // yes allowed, yes messaging w/shortcut, yes bubble
10869         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
10870         assertTrue(notif.isBubbleNotification());
10871 
10872         // Make sure the shortcut is cached.
10873         verify(mShortcutServiceInternal).cacheShortcuts(
10874                 anyInt(), any(), eq(mPkg), eq(singletonList(shortcutId)),
10875                 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
10876 
10877         // Test: Remove the notification
10878         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10879                 nr.getSbn().getId(), nr.getSbn().getUserId());
10880         waitForIdle();
10881 
10882         // Verify:
10883 
10884         // Make sure callback is unregistered
10885         verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
10886     }
10887 
10888     @Test
10889     public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed()
10890             throws Exception {
10891         setUpPrefsForBubbles(mPkg, mUid,
10892                 true /* global */,
10893                 BUBBLE_PREFERENCE_ALL /* app */,
10894                 true /* channel */);
10895 
10896         NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
10897                 true /* summaryAutoCancel */);
10898 
10899         // Dismiss summary
10900         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
10901                 true);
10902         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg,
10903                 nrSummary.getUserId(), nrSummary.getKey(),
10904                 NotificationStats.DISMISSAL_SHADE,
10905                 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv);
10906         waitForIdle();
10907 
10908         // The bubble should still exist
10909         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10910         assertEquals(1, notifsAfter.length);
10911     }
10912 
10913     @Test
10914     public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked()
10915             throws Exception {
10916         setUpPrefsForBubbles(mPkg, mUid,
10917                 true /* global */,
10918                 BUBBLE_PREFERENCE_ALL /* app */,
10919                 true /* channel */);
10920 
10921         NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
10922                 true /* summaryAutoCancel */);
10923 
10924         // Click summary
10925         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
10926                 true);
10927         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
10928                 nrSummary.getKey(), nv);
10929         waitForIdle();
10930 
10931         // The bubble should still exist
10932         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10933         assertEquals(1, notifsAfter.length);
10934 
10935         // Check we got the click log and associated dismissal logs
10936         assertEquals(6, mNotificationRecordLogger.numCalls());
10937         // Skip the notification-creation logs
10938         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
10939                 mNotificationRecordLogger.event(3));
10940         assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK,
10941                 mNotificationRecordLogger.event(4));
10942         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
10943                         .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED,
10944                 mNotificationRecordLogger.event(5));
10945     }
10946 
10947     @Test
10948     public void testNotificationBubbles_bubbleStays_whenClicked()
10949             throws Exception {
10950         setUpPrefsForBubbles(mPkg, mUid,
10951                 true /* global */,
10952                 BUBBLE_PREFERENCE_ALL /* app */,
10953                 true /* channel */);
10954 
10955         // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble
10956         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10957         nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL;
10958         mService.addNotification(nr);
10959 
10960         // WHEN we click the notification
10961         final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true);
10962         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
10963                 nr.getKey(), nv);
10964         waitForIdle();
10965 
10966         // THEN the bubble should still exist
10967         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
10968         assertEquals(1, notifsAfter.length);
10969 
10970         // Check we got the click log
10971         assertEquals(1, mNotificationRecordLogger.numCalls());
10972         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
10973                 mNotificationRecordLogger.event(0));
10974     }
10975 
10976     /**
10977      * When something is bubble'd and the bubble is dismissed, but the notification is still
10978      * visible, clicking on the notification shouldn't auto-cancel it because clicking on
10979      * it will produce a bubble.
10980      */
10981     @Test
10982     public void testNotificationBubbles_bubbleStays_whenClicked_afterBubbleDismissed()
10983             throws Exception {
10984         setUpPrefsForBubbles(mPkg, mUid,
10985                 true /* global */,
10986                 BUBBLE_PREFERENCE_ALL /* app */,
10987                 true /* channel */);
10988 
10989         // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble
10990         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10991         nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL;
10992         nr.setAllowBubble(true);
10993         mService.addNotification(nr);
10994 
10995         // And the bubble is dismissed
10996         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(),
10997                 false /* isBubble */, 0 /* bubbleFlags */);
10998         waitForIdle();
10999         assertTrue(nr.isFlagBubbleRemoved());
11000 
11001         // WHEN we click the notification
11002         final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true);
11003         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
11004                 nr.getKey(), nv);
11005         waitForIdle();
11006 
11007         // THEN the bubble should still exist
11008         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11009         assertEquals(1, notifsAfter.length);
11010 
11011         // Check we got the click log
11012         assertEquals(1, mNotificationRecordLogger.numCalls());
11013         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
11014                 mNotificationRecordLogger.event(0));
11015     }
11016 
11017     @Test
11018     public void testLoadDefaultApprovedServices_emptyResources() {
11019         TestableResources tr = mContext.getOrCreateTestableResources();
11020         tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, "");
11021         tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "");
11022         tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, "");
11023 
11024         mService.loadDefaultApprovedServices(USER_SYSTEM);
11025 
11026         verify(mListeners, never()).addDefaultComponentOrPackage(anyString());
11027         verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString());
11028         verify(mAssistants, never()).addDefaultComponentOrPackage(anyString());
11029     }
11030 
11031     @Test
11032     public void testLoadDefaultApprovedServices_dnd() {
11033         TestableResources tr = mContext.getOrCreateTestableResources();
11034         tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test");
11035         when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
11036                 .thenReturn(new ArraySet<>());
11037 
11038         mService.loadDefaultApprovedServices(USER_SYSTEM);
11039 
11040         verify(mConditionProviders, times(1)).loadDefaultsFromConfig();
11041     }
11042 
11043     // TODO: add tests for the rest of the non-empty cases
11044 
11045     @Test
11046     public void testOnUnlockUser() {
11047         UserInfo ui = new UserInfo();
11048         ui.id = 10;
11049         mService.onUserUnlocked(new TargetUser(ui));
11050         waitForIdle();
11051 
11052         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
11053     }
11054 
11055     @Test
11056     public void testOnStopUser() {
11057         UserInfo ui = new UserInfo();
11058         ui.id = 10;
11059         mService.onUserStopping(new TargetUser(ui));
11060         waitForIdle();
11061 
11062         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
11063     }
11064 
11065     @Test
11066     public void testHandleOnPackageChanged() {
11067         String[] pkgs = new String[] {mPkg, PKG_N_MR1};
11068         int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1};
11069 
11070         mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids);
11071 
11072         verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString());
11073 
11074         mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids);
11075 
11076         verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]);
11077         verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]);
11078     }
11079 
11080     @Test
11081     public void testHandleOnPackageRemoved_ClearsHistory() throws Exception {
11082         // Enables Notification History setting
11083         setUpPrefsForHistory(mUserId, true /* =enabled */);
11084 
11085         // Posts a notification to the mTestNotificationChannel.
11086         final NotificationRecord notif = generateNotificationRecord(
11087                 mTestNotificationChannel, 1, null, false);
11088         mService.addNotification(notif);
11089         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(
11090                 notif.getSbn().getPackageName());
11091         assertEquals(1, notifs.length);
11092 
11093         // Cancels all notifications.
11094         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
11095                 notif.getUserId(), REASON_CANCEL);
11096         waitForIdle();
11097         notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
11098         assertEquals(0, notifs.length);
11099 
11100         // Checks that notification history's recently canceled archive contains the notification.
11101         notifs = mBinderService.getHistoricalNotificationsWithAttribution(mPkg,
11102                         mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
11103         waitForIdle();
11104         assertEquals(1, notifs.length);
11105 
11106         // Remove sthe package that contained the channel
11107         simulatePackageRemovedBroadcast(mPkg, mUid);
11108         waitForIdle();
11109 
11110         // Checks that notification history no longer contains the notification.
11111         notifs = mBinderService.getHistoricalNotificationsWithAttribution(
11112                 mPkg, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
11113         waitForIdle();
11114         assertEquals(0, notifs.length);
11115     }
11116 
11117     @Test
11118     public void testNotificationHistory_addNoisyNotification() throws Exception {
11119         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
11120                 null /* tvExtender */);
11121         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11122                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11123         waitForIdle();
11124 
11125         verify(mHistoryManager, times(1)).addNotification(any());
11126     }
11127 
11128     @Test
11129     public void createConversationNotificationChannel() throws Exception {
11130         int userId = UserManager.isHeadlessSystemUserMode()
11131                 ? UserHandle.getUserId(UID_HEADLESS)
11132                 : USER_SYSTEM;
11133 
11134         NotificationChannel original = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
11135         original.setAllowBubbles(!original.canBubble());
11136         original.setShowBadge(!original.canShowBadge());
11137 
11138         Parcel parcel = Parcel.obtain();
11139         original.writeToParcel(parcel, 0);
11140         parcel.setDataPosition(0);
11141         NotificationChannel orig = NotificationChannel.CREATOR.createFromParcel(parcel);
11142         assertEquals(original, orig);
11143         assertFalse(TextUtils.isEmpty(orig.getName()));
11144 
11145         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(Arrays.asList(
11146                 orig)));
11147 
11148         mBinderService.createConversationNotificationChannelForPackage(
11149                 mPkg, mUid, orig, "friend");
11150 
11151         NotificationChannel friendChannel = mBinderService.getConversationNotificationChannel(
11152                 mPkg, userId, mPkg, original.getId(), false, "friend");
11153 
11154         assertEquals(original.getName(), friendChannel.getName());
11155         assertEquals(original.getId(), friendChannel.getParentChannelId());
11156         assertEquals("friend", friendChannel.getConversationId());
11157         assertEquals(null, original.getConversationId());
11158         assertEquals(original.canShowBadge(), friendChannel.canShowBadge());
11159         assertFalse(friendChannel.canBubble()); // can't be modified by app
11160         assertFalse(original.getId().equals(friendChannel.getId()));
11161         assertNotNull(friendChannel.getId());
11162     }
11163 
11164     @Test
11165     public void testCorrectCategory_systemOn_appCannotTurnOff() {
11166         int requested = 0;
11167         int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
11168 
11169         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
11170                 system);
11171 
11172         assertEquals(PRIORITY_CATEGORY_CONVERSATIONS, actual);
11173     }
11174 
11175     @Test
11176     public void testCorrectCategory_systemOff_appTurnOff_noChanges() {
11177         int requested = PRIORITY_CATEGORY_CALLS;
11178         int system = PRIORITY_CATEGORY_CALLS;
11179 
11180         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
11181                 system);
11182 
11183         assertEquals(PRIORITY_CATEGORY_CALLS, actual);
11184     }
11185 
11186     @Test
11187     public void testCorrectCategory_systemOn_appTurnOn_noChanges() {
11188         int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
11189         int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
11190 
11191         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
11192                 system);
11193 
11194         assertEquals(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS, actual);
11195     }
11196 
11197     @Test
11198     public void testCorrectCategory_systemOff_appCannotTurnOn() {
11199         int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
11200         int system = PRIORITY_CATEGORY_CALLS;
11201 
11202         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
11203                 system);
11204 
11205         assertEquals(PRIORITY_CATEGORY_CALLS, actual);
11206     }
11207 
11208     @Test
11209     public void testRestoreConversationChannel_deleted() throws Exception {
11210         // Create parent channel
11211         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
11212         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
11213                 IMPORTANCE_DEFAULT);
11214         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
11215                 NotificationChannel.CREATOR);
11216         assertEquals(originalChannel, parentChannel);
11217         mBinderService.createNotificationChannels(mPkg,
11218                 new ParceledListSlice(Arrays.asList(parentChannel)));
11219 
11220         //Create deleted conversation channel
11221         mBinderService.createConversationNotificationChannelForPackage(
11222                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
11223         final NotificationChannel conversationChannel =
11224                 mBinderService.getConversationNotificationChannel(
11225                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
11226         conversationChannel.setDeleted(true);
11227 
11228         //Create notification record
11229         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11230                 null /* groupKey */, false /* isSummary */, true);
11231         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
11232         nb.setChannelId(originalChannel.getId());
11233         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
11234                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
11235         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
11236         assertThat(nr.getChannel()).isEqualTo(originalChannel);
11237 
11238         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11239                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11240         waitForIdle();
11241 
11242         // Verify that the channel was changed to the conversation channel and restored
11243         assertThat(mService.getNotificationRecord(nr.getKey()).isConversation()).isTrue();
11244         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
11245                 conversationChannel);
11246         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().isDeleted()).isFalse();
11247         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().getDeletedTimeMs())
11248                 .isEqualTo(-1);
11249     }
11250 
11251     @Test
11252     public void testDoNotRestoreParentChannel_deleted() throws Exception {
11253         // Create parent channel and set as deleted
11254         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
11255         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
11256                 IMPORTANCE_DEFAULT);
11257         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
11258                 NotificationChannel.CREATOR);
11259         assertEquals(originalChannel, parentChannel);
11260         mBinderService.createNotificationChannels(mPkg,
11261                 new ParceledListSlice(Arrays.asList(parentChannel)));
11262         parentChannel.setDeleted(true);
11263 
11264         //Create notification record
11265         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11266                 null /* groupKey */, false /* isSummary */, true);
11267         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
11268         nb.setChannelId(originalChannel.getId());
11269         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
11270                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
11271         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
11272         assertThat(nr.getChannel()).isEqualTo(originalChannel);
11273 
11274         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
11275 
11276         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11277                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11278         waitForIdle();
11279 
11280         // Verify that the channel was not restored and the notification was not posted
11281         assertThat(mService.mChannelToastsSent).contains(mUid);
11282         assertThat(mService.getNotificationRecord(nr.getKey())).isNull();
11283         assertThat(parentChannel.isDeleted()).isTrue();
11284     }
11285 
11286     @Test
11287     public void testEnqueueToConversationChannel_notDeleted_doesNotRestore() throws Exception {
11288         TestableNotificationManagerService service = spy(mService);
11289         PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper);
11290         service.setPreferencesHelper(preferencesHelper);
11291         // Create parent channel
11292         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
11293         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
11294                 IMPORTANCE_DEFAULT);
11295         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
11296                 NotificationChannel.CREATOR);
11297         assertEquals(originalChannel, parentChannel);
11298         mBinderService.createNotificationChannels(mPkg,
11299                 new ParceledListSlice(Arrays.asList(parentChannel)));
11300 
11301         //Create conversation channel
11302         mBinderService.createConversationNotificationChannelForPackage(
11303                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
11304         final NotificationChannel conversationChannel =
11305                 mBinderService.getConversationNotificationChannel(
11306                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
11307 
11308         //Create notification record
11309         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11310                 null /* groupKey */, false /* isSummary */, true);
11311         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
11312         nb.setChannelId(originalChannel.getId());
11313         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
11314                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
11315         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
11316         assertThat(nr.getChannel()).isEqualTo(originalChannel);
11317 
11318         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11319                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11320         waitForIdle();
11321 
11322         // Verify that the channel was changed to the conversation channel and not restored
11323         assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isTrue();
11324         assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
11325                 conversationChannel);
11326         verify(service, never()).handleSavePolicyFile();
11327         verify(preferencesHelper, never()).createNotificationChannel(anyString(),
11328                 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean());
11329     }
11330 
11331     @Test
11332     public void testEnqueueToParentChannel_notDeleted_doesNotRestore() throws Exception {
11333         TestableNotificationManagerService service = spy(mService);
11334         PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper);
11335         service.setPreferencesHelper(preferencesHelper);
11336         // Create parent channel
11337         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
11338         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
11339                 IMPORTANCE_DEFAULT);
11340         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
11341                 NotificationChannel.CREATOR);
11342         assertEquals(originalChannel, parentChannel);
11343         mBinderService.createNotificationChannels(mPkg,
11344                 new ParceledListSlice(Arrays.asList(parentChannel)));
11345 
11346         //Create deleted conversation channel
11347         mBinderService.createConversationNotificationChannelForPackage(
11348                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
11349         final NotificationChannel conversationChannel =
11350                 mBinderService.getConversationNotificationChannel(
11351                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
11352 
11353         //Create notification record without a shortcutId
11354         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11355                 null /* groupKey */, false /* isSummary */, true);
11356         nb.setShortcutId(null);
11357         nb.setChannelId(originalChannel.getId());
11358         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
11359                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
11360         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
11361         assertThat(nr.getChannel()).isEqualTo(originalChannel);
11362 
11363         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11364                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11365         waitForIdle();
11366 
11367         // Verify that the channel is the parent channel and no channel was restored
11368         //assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isFalse();
11369         assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
11370                 parentChannel);
11371         verify(service, never()).handleSavePolicyFile();
11372         verify(preferencesHelper, never()).createNotificationChannel(anyString(),
11373                 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean());
11374     }
11375 
11376     @Test
11377     public void testGetConversationsForPackage_hasShortcut() throws Exception {
11378         mService.setPreferencesHelper(mPreferencesHelper);
11379         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
11380         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
11381         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
11382         channel1.setConversationId("parent1", "convo 1");
11383         convo1.setNotificationChannel(channel1);
11384         convos.add(convo1);
11385 
11386         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
11387         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
11388         channel2.setConversationId("parent1", "convo 2");
11389         convo2.setNotificationChannel(channel2);
11390         convos.add(convo2);
11391         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
11392 
11393         ShortcutInfo si = mock(ShortcutInfo.class);
11394         when(si.getPackage()).thenReturn(PKG_P);
11395         when(si.getId()).thenReturn("convo");
11396         when(si.getUserId()).thenReturn(USER_SYSTEM);
11397         when(si.getLabel()).thenReturn("Hello");
11398         when(si.isLongLived()).thenReturn(true);
11399         when(si.isEnabled()).thenReturn(true);
11400         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
11401         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
11402                 anyString(), anyInt(), any())).thenReturn(true);
11403 
11404         List<ConversationChannelWrapper> conversations =
11405                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
11406         assertEquals(si, conversations.get(0).getShortcutInfo());
11407         assertEquals(si, conversations.get(1).getShortcutInfo());
11408 
11409         // Returns null shortcuts when locked.
11410         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(false);
11411         conversations =
11412                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
11413         assertThat(conversations.get(0).getShortcutInfo()).isNull();
11414         assertThat(conversations.get(1).getShortcutInfo()).isNull();
11415     }
11416 
11417     @Test
11418     public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception {
11419         mService.setPreferencesHelper(mPreferencesHelper);
11420         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
11421         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
11422         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
11423         channel1.setConversationId("parent1", "convo 1");
11424         convo1.setNotificationChannel(channel1);
11425         convos.add(convo1);
11426 
11427         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
11428         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
11429         channel2.setConversationId("parent1", "convo 2");
11430         convo2.setNotificationChannel(channel2);
11431         convos.add(convo2);
11432         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
11433 
11434         ShortcutInfo si = mock(ShortcutInfo.class);
11435         when(si.getPackage()).thenReturn(PKG_P);
11436         when(si.getId()).thenReturn("convo");
11437         when(si.getUserId()).thenReturn(USER_SYSTEM);
11438         when(si.getLabel()).thenReturn("Hello");
11439         when(si.isLongLived()).thenReturn(false);
11440         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
11441 
11442         List<ConversationChannelWrapper> conversations =
11443                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
11444         assertNull(conversations.get(0).getShortcutInfo());
11445         assertNull(conversations.get(1).getShortcutInfo());
11446     }
11447 
11448     @Test
11449     public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception {
11450         mService.setPreferencesHelper(mPreferencesHelper);
11451         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
11452         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
11453         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
11454         channel1.setConversationId("parent1", "convo 1");
11455         convo1.setNotificationChannel(channel1);
11456         convos.add(convo1);
11457 
11458         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
11459         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
11460         channel2.setConversationId("parent1", "convo 2");
11461         convo2.setNotificationChannel(channel2);
11462         convos.add(convo2);
11463         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
11464         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
11465 
11466         List<ConversationChannelWrapper> conversations =
11467                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
11468         assertNull(conversations.get(0).getShortcutInfo());
11469         assertNull(conversations.get(1).getShortcutInfo());
11470     }
11471 
11472     @Test
11473     public void testShortcutHelperNull_doesntCrashEnqueue() throws RemoteException {
11474         mService.setShortcutHelper(null);
11475         NotificationRecord nr =
11476                 generateMessageBubbleNotifRecord(mTestNotificationChannel,
11477                         "testShortcutHelperNull_doesntCrashEnqueue");
11478         try {
11479             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11480                     nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11481             waitForIdle();
11482         } catch (Exception e) {
11483             fail(e.getMessage());
11484         }
11485     }
11486 
11487     @Test
11488     public void testRecordMessages_invalidMsg() throws RemoteException {
11489         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11490                 null /* groupKey */, false /* isSummary */, true);
11491         nb.setShortcutId(null);
11492         StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
11493                 "testRecordMessages_invalidMsg", mUid, 0, nb.build(),
11494                 UserHandle.getUserHandleForUid(mUid), null, 0);
11495         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
11496 
11497         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
11498         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
11499                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11500         waitForIdle();
11501 
11502         assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
11503     }
11504 
11505     @Test
11506     public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException {
11507         Notification.Builder nb = new Notification.Builder(mContext,
11508                 mTestNotificationChannel.getId())
11509                 .setContentTitle("foo")
11510                 .setShortcutId(null)
11511                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
11512                 .setCategory(Notification.CATEGORY_MESSAGE);
11513         StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1,
11514                 "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(),
11515                 UserHandle.getUserHandleForUid(mUid), null, 0);
11516         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
11517 
11518         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
11519         mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(),
11520                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11521         waitForIdle();
11522 
11523         // PKG_O is allowed to be in conversation space b/c of override in
11524         // TestableNotificationManagerService
11525         assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid));
11526     }
11527 
11528     @Test
11529     public void testRecordMessages_validMsg() throws RemoteException {
11530         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11531                 null /* groupKey */, false /* isSummary */, true);
11532         nb.setShortcutId(null);
11533         StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
11534                 "testRecordMessages_validMsg", mUid, 0, nb.build(),
11535                 UserHandle.getUserHandleForUid(mUid), null, 0);
11536         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
11537 
11538         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
11539                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11540         waitForIdle();
11541 
11542         assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
11543 
11544         nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11545                 "testRecordMessages_validMsg");
11546 
11547         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
11548                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11549         waitForIdle();
11550 
11551         assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid));
11552     }
11553 
11554     @Test
11555     public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException {
11556         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11557                 "testRecordMessages_invalidMsg_afterValidMsg_1");
11558         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11559                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11560         waitForIdle();
11561         assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation());
11562 
11563         mBinderService.cancelAllNotifications(mPkg, mUid);
11564         waitForIdle();
11565 
11566         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
11567                 null /* groupKey */, false /* isSummary */, true);
11568         nb.setShortcutId(null);
11569         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
11570                 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
11571                 UserHandle.getUserHandleForUid(mUid), null, 0);
11572          nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
11573 
11574         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11575                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11576         waitForIdle();
11577 
11578         assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation());
11579     }
11580 
11581     @Test
11582     public void testCanPostFgsWhenOverLimit() throws RemoteException {
11583         when(mAmi.applyForegroundServiceNotification(
11584                 any(), anyString(), anyInt(), anyString(), anyInt()))
11585                 .thenReturn(SHOW_IMMEDIATELY);
11586         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
11587             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
11588                     i, null, false).getSbn();
11589             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
11590                     "testCanPostFgsWhenOverLimit",
11591                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
11592         }
11593 
11594         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
11595         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
11596         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
11597                 "testCanPostFgsWhenOverLimit - fgs over limit!",
11598                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
11599 
11600         waitForIdle();
11601 
11602         StatusBarNotification[] notifs =
11603                 mBinderService.getActiveNotifications(sbn.getPackageName());
11604         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
11605         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
11606                 mService.getNotificationRecordCount());
11607     }
11608 
11609     @Test
11610     public void testCannotPostNonFgsWhenOverLimit() throws RemoteException {
11611         when(mAmi.applyForegroundServiceNotification(
11612                 any(), anyString(), anyInt(), anyString(), anyInt()))
11613                 .thenReturn(SHOW_IMMEDIATELY);
11614         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
11615             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
11616                     i, null, false).getSbn();
11617             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
11618                     "testCanPostFgsWhenOverLimit",
11619                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
11620             waitForIdle();
11621         }
11622 
11623         final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
11624                 100, null, false).getSbn();
11625         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
11626         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
11627                 "testCanPostFgsWhenOverLimit - fgs over limit!",
11628                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
11629 
11630         final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
11631                 101, null, false).getSbn();
11632         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
11633                 "testCanPostFgsWhenOverLimit - non fgs over limit!",
11634                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
11635 
11636 
11637         when(mAmi.applyForegroundServiceNotification(
11638                 any(), anyString(), anyInt(), anyString(), anyInt()))
11639                 .thenReturn(NOT_FOREGROUND_SERVICE);
11640         final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
11641                 101, null, false).getSbn();
11642         sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
11643         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
11644                 "testCanPostFgsWhenOverLimit - fake fgs over limit!",
11645                 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
11646 
11647         waitForIdle();
11648 
11649         StatusBarNotification[] notifs =
11650                 mBinderService.getActiveNotifications(sbn.getPackageName());
11651         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
11652         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
11653                 mService.getNotificationRecordCount());
11654     }
11655 
11656     @Test
11657     public void testIsVisibleToListener_notEnabled() {
11658         StatusBarNotification sbn = mock(StatusBarNotification.class);
11659         when(sbn.getUserId()).thenReturn(10);
11660         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
11661         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
11662         info.userid = 10;
11663         when(info.isSameUser(anyInt())).thenReturn(true);
11664         when(assistant.isSameUser(anyInt())).thenReturn(true);
11665         when(info.enabledAndUserMatches(info.userid)).thenReturn(false);
11666         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
11667 
11668         assertFalse(mService.isVisibleToListener(sbn, 0, info));
11669     }
11670 
11671     @Test
11672     public void testIsVisibleToListener_noAssistant() {
11673         StatusBarNotification sbn = mock(StatusBarNotification.class);
11674         when(sbn.getUserId()).thenReturn(10);
11675         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
11676         info.userid = 10;
11677         when(info.isSameUser(anyInt())).thenReturn(true);
11678         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
11679         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null);
11680 
11681         assertTrue(mService.isVisibleToListener(sbn, 0, info));
11682     }
11683 
11684     @Test
11685     public void testIsVisibleToListener_assistant_differentUser() {
11686         StatusBarNotification sbn = mock(StatusBarNotification.class);
11687         when(sbn.getUserId()).thenReturn(10);
11688         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
11689         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
11690         info.userid = 0;
11691         when(info.isSameUser(anyInt())).thenReturn(true);
11692         when(assistant.isSameUser(anyInt())).thenReturn(true);
11693         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
11694         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
11695 
11696         assertFalse(mService.isVisibleToListener(sbn, 0, info));
11697     }
11698 
11699     @Test
11700     public void testIsVisibleToListener_assistant_sameUser() {
11701         StatusBarNotification sbn = mock(StatusBarNotification.class);
11702         when(sbn.getUserId()).thenReturn(10);
11703         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
11704         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
11705         info.userid = 10;
11706         when(info.isSameUser(anyInt())).thenReturn(true);
11707         when(assistant.isSameUser(anyInt())).thenReturn(true);
11708         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
11709         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
11710 
11711         assertTrue(mService.isVisibleToListener(sbn, 0, info));
11712     }
11713 
11714     @Test
11715     public void testIsVisibleToListener_mismatchedType() {
11716         when(mNlf.isTypeAllowed(anyInt())).thenReturn(false);
11717 
11718         StatusBarNotification sbn = mock(StatusBarNotification.class);
11719         when(sbn.getUserId()).thenReturn(10);
11720         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
11721         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
11722         info.userid = 10;
11723         when(info.isSameUser(anyInt())).thenReturn(true);
11724         when(assistant.isSameUser(anyInt())).thenReturn(true);
11725         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
11726         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
11727 
11728         assertFalse(mService.isVisibleToListener(sbn, 0, info));
11729     }
11730 
11731     @Test
11732     public void testIsVisibleToListener_disallowedPackage() {
11733         when(mNlf.isPackageAllowed(any())).thenReturn(false);
11734 
11735         StatusBarNotification sbn = mock(StatusBarNotification.class);
11736         when(sbn.getUserId()).thenReturn(10);
11737         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
11738         ManagedServices.ManagedServiceInfo assistant =
11739                 mock(ManagedServices.ManagedServiceInfo.class);
11740         info.userid = 10;
11741         when(info.isSameUser(anyInt())).thenReturn(true);
11742         when(assistant.isSameUser(anyInt())).thenReturn(true);
11743         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
11744         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
11745 
11746         assertFalse(mService.isVisibleToListener(sbn, 0, info));
11747     }
11748 
11749     @Test
11750     public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() {
11751         final NotificationRecord parent = spy(generateNotificationRecord(
11752                 mTestNotificationChannel, 1, "group", true));
11753         final NotificationRecord child = spy(generateNotificationRecord(
11754                 mTestNotificationChannel, 2, "group", false));
11755         mService.addNotification(parent);
11756         mService.addNotification(child);
11757 
11758         InOrder inOrder = inOrder(parent, child);
11759 
11760         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
11761                 parent.getUserId());
11762         waitForIdle();
11763         inOrder.verify(parent).recordDismissalSentiment(anyInt());
11764         inOrder.verify(child).recordDismissalSentiment(anyInt());
11765     }
11766 
11767     @Test
11768     public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() {
11769         final NotificationRecord parent = spy(generateNotificationRecord(
11770                 mTestNotificationChannel, 1, "group", true));
11771         final NotificationRecord child = spy(generateNotificationRecord(
11772                 mTestNotificationChannel, 2, "group", false));
11773         mService.addNotification(child);
11774         mService.addNotification(parent);
11775 
11776         InOrder inOrder = inOrder(parent, child);
11777 
11778         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
11779                 parent.getUserId());
11780         waitForIdle();
11781         inOrder.verify(parent).recordDismissalSentiment(anyInt());
11782         inOrder.verify(child).recordDismissalSentiment(anyInt());
11783     }
11784 
11785     @Test
11786     public void testImmutableBubbleIntent() throws Exception {
11787         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
11788         NotificationRecord r = generateMessageBubbleNotifRecord(true,
11789                 mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false, false);
11790         try {
11791             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
11792                     r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
11793 
11794             waitForIdle();
11795             fail("Allowed a bubble with an immutable intent to be posted");
11796         } catch (IllegalArgumentException e) {
11797             // good
11798         }
11799     }
11800 
11801     @Test
11802     public void testMutableBubbleIntent() throws Exception {
11803         NotificationRecord r = generateMessageBubbleNotifRecord(true,
11804                 mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false, true);
11805 
11806         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
11807                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
11808 
11809         waitForIdle();
11810         StatusBarNotification[] notifs =
11811                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
11812         assertEquals(1, notifs.length);
11813     }
11814 
11815     @Test
11816     public void testImmutableDirectReplyActionIntent() throws Exception {
11817         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
11818         NotificationRecord r = generateMessageBubbleNotifRecord(false,
11819                 mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false,
11820                 false);
11821         try {
11822             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
11823                     r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
11824 
11825             waitForIdle();
11826             fail("Allowed a direct reply with an immutable intent to be posted");
11827         } catch (IllegalArgumentException e) {
11828             // good
11829         }
11830     }
11831 
11832     @Test
11833     public void testMutableDirectReplyActionIntent() throws Exception {
11834         NotificationRecord r = generateMessageBubbleNotifRecord(false,
11835                 mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false,
11836                 true);
11837         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
11838                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
11839 
11840         waitForIdle();
11841         StatusBarNotification[] notifs =
11842                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
11843         assertEquals(1, notifs.length);
11844     }
11845 
11846     @Test
11847     public void testImmutableDirectReplyContextualActionIntent() throws Exception {
11848         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
11849         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
11850 
11851         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
11852         ArrayList<Notification.Action> extraAction = new ArrayList<>();
11853         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
11854         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
11855         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
11856                 mActivityIntentImmutable).addRemoteInput(remoteInput)
11857                 .build();
11858         extraAction.add(replyAction);
11859         Bundle signals = new Bundle();
11860         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
11861         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
11862                 r.getUser());
11863         r.addAdjustment(adjustment);
11864         r.applyAdjustments();
11865 
11866         try {
11867             mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
11868                     r.getSbn().getTag(), r, false, false);
11869             fail("Allowed a contextual direct reply with an immutable intent to be posted");
11870         } catch (IllegalArgumentException e) {
11871             // good
11872         }
11873     }
11874 
11875     @Test
11876     public void testMutableDirectReplyContextualActionIntent() throws Exception {
11877         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
11878         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
11879         ArrayList<Notification.Action> extraAction = new ArrayList<>();
11880         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
11881         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
11882         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
11883                 mActivityIntent).addRemoteInput(remoteInput)
11884                 .build();
11885         extraAction.add(replyAction);
11886         Bundle signals = new Bundle();
11887         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
11888         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
11889                 r.getUser());
11890         r.addAdjustment(adjustment);
11891         r.applyAdjustments();
11892 
11893         mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
11894                 r.getSbn().getTag(), r, false, false);
11895     }
11896 
11897     @Test
11898     public void testImmutableActionIntent() throws Exception {
11899         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
11900         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
11901         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
11902                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
11903 
11904         waitForIdle();
11905         StatusBarNotification[] notifs =
11906                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
11907         assertEquals(1, notifs.length);
11908     }
11909 
11910     @Test
11911     public void testImmutableContextualActionIntent() throws Exception {
11912         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
11913         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
11914         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
11915         ArrayList<Notification.Action> extraAction = new ArrayList<>();
11916         extraAction.add(new Notification.Action(0, "hello", mActivityIntentImmutable));
11917         Bundle signals = new Bundle();
11918         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
11919         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
11920                 r.getUser());
11921         r.addAdjustment(adjustment);
11922         r.applyAdjustments();
11923 
11924         mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
11925                     r.getSbn().getTag(), r, false, false);
11926     }
11927 
11928     @Test
11929     public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception {
11930         int uid = 9000;
11931         int[] userIds = new int[] {mUserId, 1000};
11932         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
11933         List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
11934         for (int userId : userIds) {
11935             for (String pkg : disallowedApps) {
11936                 when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++);
11937             }
11938         }
11939 
11940         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
11941                 new NotificationListenerFilter());
11942 
11943         mBinderService.migrateNotificationFilter(null,
11944                 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
11945                 disallowedApps);
11946 
11947         ArgumentCaptor<NotificationListenerFilter> captor =
11948                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
11949         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
11950 
11951         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
11952                 captor.getValue().getTypes());
11953         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000)));
11954         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002)));
11955         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003)));
11956 
11957         // hypothetical other user untouched
11958         assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000)));
11959     }
11960 
11961     @Test
11962     public void testMigrateNotificationFilter_invalidPackage() throws Exception {
11963         int[] userIds = new int[] {mUserId, 1000};
11964         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
11965         List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
11966         for (int userId : userIds) {
11967             when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow(
11968                     new RemoteException(""));
11969             when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000);
11970             when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001);
11971         }
11972 
11973         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
11974                 new NotificationListenerFilter());
11975 
11976         mBinderService.migrateNotificationFilter(null,
11977                 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
11978                 disallowedApps);
11979 
11980         ArgumentCaptor<NotificationListenerFilter> captor =
11981                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
11982         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
11983 
11984         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
11985                 captor.getValue().getTypes());
11986         // valid values stay
11987         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000)));
11988         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001)));
11989         // don't store invalid values
11990         for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) {
11991             assertNotEquals("apples", vp.getPackageName());
11992         }
11993     }
11994 
11995     @Test
11996     public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception {
11997         int[] userIds = new int[] {mUserId};
11998         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
11999         List<String> disallowedApps = ImmutableList.of("apples");
12000         when(mPackageManager.getPackageUid("apples", 0, mUserId))
12001                 .thenReturn(1001);
12002 
12003         when(mListeners.getNotificationListenerFilter(any())).thenReturn(null);
12004 
12005         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
12006                 disallowedApps);
12007 
12008         ArgumentCaptor<NotificationListenerFilter> captor =
12009                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
12010         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
12011 
12012         assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
12013         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
12014     }
12015 
12016     @Test
12017     public void testMigrateNotificationFilter_existingTypeFilter() throws Exception {
12018         int[] userIds = new int[] {mUserId};
12019         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
12020         List<String> disallowedApps = ImmutableList.of("apples");
12021         when(mPackageManager.getPackageUid("apples", 0, mUserId))
12022                 .thenReturn(1001);
12023 
12024         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
12025                 new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>()));
12026 
12027         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
12028                 disallowedApps);
12029 
12030         ArgumentCaptor<NotificationListenerFilter> captor =
12031                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
12032         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
12033 
12034         // type isn't saved but pkg list is
12035         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes());
12036         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
12037     }
12038 
12039     @Test
12040     public void testMigrateNotificationFilter_existingPkgFilter() throws Exception {
12041         int[] userIds = new int[] {mUserId};
12042         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
12043         List<String> disallowedApps = ImmutableList.of("apples");
12044         when(mPackageManager.getPackageUid("apples", 0, mUserId))
12045                 .thenReturn(1001);
12046 
12047         NotificationListenerFilter preexisting = new NotificationListenerFilter();
12048         preexisting.addPackage(new VersionedPackage("test", 1002));
12049         when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting);
12050 
12051         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
12052                 disallowedApps);
12053 
12054         ArgumentCaptor<NotificationListenerFilter> captor =
12055                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
12056         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
12057 
12058         // type is saved but pkg list isn't
12059         assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
12060         assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
12061         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002)));
12062     }
12063 
12064     @Test
12065     public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
12066         mService.setPreferencesHelper(mPreferencesHelper);
12067 
12068         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
12069 
12070         assertThat(mBinderService.getNotificationChannelsBypassingDnd(mPkg, mUid).getList())
12071                 .isEmpty();
12072         verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid);
12073     }
12074 
12075     @Test
12076     public void testGetPackagesBypassingDnd_empty() throws RemoteException {
12077         mService.setPreferencesHelper(mPreferencesHelper);
12078         List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true);
12079         assertThat(result).isEmpty();
12080     }
12081 
12082     @Test
12083     public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException {
12084         mService.setPreferencesHelper(mPreferencesHelper);
12085 
12086         // Set packages
12087         PackageInfo pkg0 = new PackageInfo();
12088         pkg0.packageName = "pkg0";
12089         pkg0.applicationInfo = new ApplicationInfo();
12090         pkg0.applicationInfo.uid = mUid;
12091         PackageInfo pkg1 = new PackageInfo();
12092         pkg1.packageName = "pkg1";
12093         pkg1.applicationInfo = new ApplicationInfo();
12094         pkg1.applicationInfo.uid = mUid;
12095         PackageInfo pkg2 = new PackageInfo();
12096         pkg2.packageName = "pkg2";
12097         pkg2.applicationInfo = new ApplicationInfo();
12098         pkg2.applicationInfo.uid = mUid;
12099 
12100         when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId))
12101                 .thenReturn(List.of(pkg0, pkg1, pkg2));
12102 
12103         // Conversation channels
12104         NotificationChannel nc0 = new NotificationChannel("id0", "id0",
12105                 NotificationManager.IMPORTANCE_HIGH);
12106         nc0.setConversationId("parentChannel", "conversationId");
12107 
12108         // Demoted conversation channel
12109         NotificationChannel nc1 = new NotificationChannel("id1", "id1",
12110                 NotificationManager.IMPORTANCE_HIGH);
12111         nc1.setConversationId("parentChannel", "conversationId");
12112         nc1.setDemoted(true);
12113 
12114         // Non-conversation channels
12115         NotificationChannel nc2 = new NotificationChannel("id2", "id2",
12116                 NotificationManager.IMPORTANCE_HIGH);
12117         NotificationChannel nc3 = new NotificationChannel("id3", "id3",
12118                 NotificationManager.IMPORTANCE_HIGH);
12119 
12120         ParceledListSlice<NotificationChannel> pls0 =
12121                 new ParceledListSlice(ImmutableList.of(nc0));
12122         ParceledListSlice<NotificationChannel> pls1 =
12123                 new ParceledListSlice(ImmutableList.of(nc1));
12124         ParceledListSlice<NotificationChannel> pls2 =
12125                 new ParceledListSlice(ImmutableList.of(nc2, nc3));
12126 
12127         when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid))
12128                 .thenReturn(pls0);
12129         when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid))
12130                 .thenReturn(pls1);
12131         when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid))
12132                 .thenReturn(pls2);
12133 
12134         List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false);
12135 
12136         assertThat(result).containsExactly("pkg1", "pkg2");
12137     }
12138 
12139     @Test
12140     public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException {
12141         mService.setPreferencesHelper(mPreferencesHelper);
12142 
12143         // Set packages
12144         PackageInfo pkg0 = new PackageInfo();
12145         pkg0.packageName = "pkg0";
12146         pkg0.applicationInfo = new ApplicationInfo();
12147         pkg0.applicationInfo.uid = mUid;
12148         PackageInfo pkg1 = new PackageInfo();
12149         pkg1.packageName = "pkg1";
12150         pkg1.applicationInfo = new ApplicationInfo();
12151         pkg1.applicationInfo.uid = mUid;
12152         PackageInfo pkg2 = new PackageInfo();
12153         pkg2.packageName = "pkg2";
12154         pkg2.applicationInfo = new ApplicationInfo();
12155         pkg2.applicationInfo.uid = mUid;
12156 
12157         when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId))
12158                 .thenReturn(List.of(pkg0, pkg1, pkg2));
12159 
12160         // Conversation channels
12161         NotificationChannel nc0 = new NotificationChannel("id0", "id0",
12162                 NotificationManager.IMPORTANCE_HIGH);
12163         nc0.setConversationId("parentChannel", "conversationId");
12164 
12165         // Demoted conversation channel
12166         NotificationChannel nc1 = new NotificationChannel("id1", "id1",
12167                 NotificationManager.IMPORTANCE_HIGH);
12168         nc1.setConversationId("parentChannel", "conversationId");
12169         nc1.setDemoted(true);
12170 
12171         // Non-conversation channels
12172         NotificationChannel nc2 = new NotificationChannel("id2", "id2",
12173                 NotificationManager.IMPORTANCE_HIGH);
12174         NotificationChannel nc3 = new NotificationChannel("id3", "id3",
12175                 NotificationManager.IMPORTANCE_HIGH);
12176 
12177         ParceledListSlice<NotificationChannel> pls0 =
12178                 new ParceledListSlice(ImmutableList.of(nc0));
12179         ParceledListSlice<NotificationChannel> pls1 =
12180                 new ParceledListSlice(ImmutableList.of(nc1));
12181         ParceledListSlice<NotificationChannel> pls2 =
12182                 new ParceledListSlice(ImmutableList.of(nc2, nc3));
12183 
12184         when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid))
12185                 .thenReturn(pls0);
12186         when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid))
12187                 .thenReturn(pls1);
12188         when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid))
12189                 .thenReturn(pls2);
12190 
12191         List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true);
12192 
12193         assertThat(result).containsExactly("pkg0", "pkg1", "pkg2");
12194     }
12195 
12196     @Test
12197     public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception {
12198         // set the testable NMS to not system uid/appid
12199         mService.isSystemUid = false;
12200         mService.isSystemAppId = false;
12201 
12202         // make sure a caller without listener access or read_contacts permission can't call
12203         // matchesCallFilter.
12204         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
12205         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
12206                 eq("android.permission.READ_CONTACTS"), anyString());
12207 
12208         try {
12209             // shouldn't matter what we're passing in, if we get past this line fail immediately
12210             ((INotificationManager) mService.mService).matchesCallFilter(null);
12211             fail("call to matchesCallFilter with no permissions should fail");
12212         } catch (SecurityException e) {
12213             // pass
12214         }
12215     }
12216 
12217     @Test
12218     public void testMatchesCallFilter_hasSystemPermission() throws Exception {
12219         // set the testable NMS to system uid
12220         mService.isSystemUid = true;
12221 
12222         // make sure caller doesn't have listener access or read_contacts permission
12223         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
12224         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
12225                 eq("android.permission.READ_CONTACTS"), anyString());
12226 
12227         try {
12228             ((INotificationManager) mService.mService).matchesCallFilter(null);
12229             // pass, but check that we actually checked for system permissions
12230             assertTrue(mService.countSystemChecks > 0);
12231         } catch (SecurityException e) {
12232             fail("call to matchesCallFilter with just system permissions should work");
12233         }
12234     }
12235 
12236     @Test
12237     public void testMatchesCallFilter_hasListenerPermission() throws Exception {
12238         mService.isSystemUid = false;
12239         mService.isSystemAppId = false;
12240 
12241         // make sure a caller with only listener access and not read_contacts permission can call
12242         // matchesCallFilter.
12243         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(true);
12244         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
12245                 eq("android.permission.READ_CONTACTS"), anyString());
12246 
12247         try {
12248             ((INotificationManager) mService.mService).matchesCallFilter(null);
12249             // pass, this is not a functionality test
12250         } catch (SecurityException e) {
12251             fail("call to matchesCallFilter with listener permissions should work");
12252         }
12253     }
12254 
12255     @Test
12256     public void testMatchesCallFilter_hasContactsPermission() throws Exception {
12257         mService.isSystemUid = false;
12258         mService.isSystemAppId = false;
12259 
12260         // make sure a caller with only read_contacts permission and not listener access can call
12261         // matchesCallFilter.
12262         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
12263         doNothing().when(mContext).enforceCallingPermission(
12264                 eq("android.permission.READ_CONTACTS"), anyString());
12265 
12266         try {
12267             ((INotificationManager) mService.mService).matchesCallFilter(null);
12268             // pass, this is not a functionality test
12269         } catch (SecurityException e) {
12270             fail("call to matchesCallFilter with listener permissions should work");
12271         }
12272     }
12273 
12274     @Test
12275     public void testMediaNotificationsBypassBlock() throws Exception {
12276         when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
12277                 .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
12278         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
12279 
12280         Notification.Builder nb = new Notification.Builder(
12281                 mContext, mTestNotificationChannel.getId())
12282                 .setContentTitle("foo")
12283                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12284                 .addAction(new Notification.Action.Builder(null, "test", null).build());
12285         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12286                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12287         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12288 
12289         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
12290 
12291         // normal blocked notifications - blocked
12292         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12293                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
12294 
12295         // just using the style - blocked
12296         nb.setStyle(new Notification.MediaStyle());
12297         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12298                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12299         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12300 
12301         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12302                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
12303 
12304         // using the style, but incorrect type in session - blocked
12305         nb.setStyle(new Notification.MediaStyle());
12306         Bundle extras = new Bundle();
12307         extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
12308         nb.addExtras(extras);
12309         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12310                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12311         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12312 
12313         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12314                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
12315 
12316         // style + media session - bypasses block
12317         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
12318         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12319                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12320         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12321 
12322         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12323                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
12324     }
12325 
12326     @Test
12327     public void testMediaNotificationsBypassBlock_atPost() throws Exception {
12328         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12329         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
12330 
12331         Notification.Builder nb = new Notification.Builder(
12332                 mContext, mTestNotificationChannel.getId())
12333                 .setContentTitle("foo")
12334                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12335                 .addAction(new Notification.Action.Builder(null, "test", null).build());
12336         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12337                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12338         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12339 
12340         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
12341 
12342         mService.addEnqueuedNotification(r);
12343         NotificationManagerService.PostNotificationRunnable runnable =
12344                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
12345                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
12346         runnable.run();
12347         waitForIdle();
12348 
12349         verify(mUsageStats).registerBlocked(any());
12350         verify(mUsageStats, never()).registerPostedByApp(any());
12351 
12352         // just using the style - blocked
12353         mService.clearNotifications();
12354         reset(mUsageStats);
12355         nb.setStyle(new Notification.MediaStyle());
12356         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12357                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12358         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12359 
12360         mService.addEnqueuedNotification(r);
12361         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
12362                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
12363         runnable.run();
12364         waitForIdle();
12365 
12366         verify(mUsageStats).registerBlocked(any());
12367         verify(mUsageStats, never()).registerPostedByApp(any());
12368 
12369         // style + media session - bypasses block
12370         mService.clearNotifications();
12371         reset(mUsageStats);
12372         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
12373         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12374                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12375         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12376 
12377         mService.addEnqueuedNotification(r);
12378         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
12379                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
12380         runnable.run();
12381         waitForIdle();
12382 
12383         verify(mUsageStats, never()).registerBlocked(any());
12384         verify(mUsageStats).registerPostedByApp(any());
12385     }
12386 
12387     @Test
12388     public void testCallNotificationsBypassBlock() throws Exception {
12389         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
12390 
12391         Notification.Builder nb = new Notification.Builder(
12392                 mContext, mTestNotificationChannel.getId())
12393                 .setContentTitle("foo")
12394                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12395                 .addAction(new Notification.Action.Builder(null, "test", null).build());
12396         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12397                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12398         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12399 
12400         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
12401 
12402         // normal blocked notifications - blocked
12403         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12404                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
12405 
12406         // just using the style - blocked
12407         Person person = new Person.Builder()
12408                 .setName("caller")
12409                 .build();
12410         nb.setStyle(Notification.CallStyle.forOngoingCall(
12411                 person, mActivityIntent));
12412         nb.setFullScreenIntent(mActivityIntent, true);
12413         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12414                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12415         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12416 
12417         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12418                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
12419 
12420         // style + managed call - bypasses block
12421         when(mTelecomManager.isInManagedCall()).thenReturn(true);
12422         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12423                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
12424 
12425         // style + self managed call - bypasses block
12426         when(mTelecomManager.isInSelfManagedCall(
12427                 r.getSbn().getPackageName(), UserHandle.ALL)).thenReturn(true);
12428         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12429                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
12430 
12431         // set telecom manager to null - blocked
12432         mService.setTelecomManager(null);
12433         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12434                            r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
12435                 .isFalse();
12436 
12437         // set telecom feature to false - blocked
12438         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
12439         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12440                            r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
12441                 .isFalse();
12442 
12443         // telecom manager is not ready - blocked
12444         mService.setTelecomManager(mTelecomManager);
12445         when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
12446         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
12447                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
12448                 .isFalse();
12449     }
12450 
12451     @Test
12452     public void testCallNotificationsBypassBlock_atPost() throws Exception {
12453         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12454         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
12455 
12456         Notification.Builder nb =
12457                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
12458                         .setContentTitle("foo")
12459                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
12460                         .addAction(new Notification.Action.Builder(null, "test", null).build());
12461         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
12462                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12463         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12464 
12465         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
12466 
12467         // normal blocked notifications - blocked
12468         mService.addEnqueuedNotification(r);
12469         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12470                 mPostNotificationTrackerFactory.newTracker(null)).run();
12471         waitForIdle();
12472 
12473         verify(mUsageStats).registerBlocked(any());
12474         verify(mUsageStats, never()).registerPostedByApp(any());
12475 
12476         // just using the style - blocked
12477         mService.clearNotifications();
12478         reset(mUsageStats);
12479         Person person = new Person.Builder().setName("caller").build();
12480         nb.setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent));
12481         nb.setFullScreenIntent(mActivityIntent, true);
12482         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, nb.build(),
12483                 UserHandle.getUserHandleForUid(mUid), null, 0);
12484         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12485 
12486         mService.addEnqueuedNotification(r);
12487         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12488                 mPostNotificationTrackerFactory.newTracker(null)).run();
12489         waitForIdle();
12490 
12491         verify(mUsageStats).registerBlocked(any());
12492         verify(mUsageStats, never()).registerPostedByApp(any());
12493 
12494         // style + managed call - bypasses block
12495         mService.clearNotifications();
12496         reset(mUsageStats);
12497         when(mTelecomManager.isInManagedCall()).thenReturn(true);
12498 
12499         mService.addEnqueuedNotification(r);
12500         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12501                 mPostNotificationTrackerFactory.newTracker(null)).run();
12502         waitForIdle();
12503 
12504         verify(mUsageStats, never()).registerBlocked(any());
12505         verify(mUsageStats).registerPostedByApp(any());
12506 
12507         // style + self managed call - bypasses block
12508         mService.clearNotifications();
12509         reset(mUsageStats);
12510         when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), UserHandle.ALL))
12511                 .thenReturn(true);
12512 
12513         mService.addEnqueuedNotification(r);
12514         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12515                 mPostNotificationTrackerFactory.newTracker(null)).run();
12516         waitForIdle();
12517 
12518         verify(mUsageStats, never()).registerBlocked(any());
12519         verify(mUsageStats).registerPostedByApp(any());
12520 
12521         // set telecom manager to null - notifications should be blocked
12522         // but post notifications runnable should not crash
12523         mService.clearNotifications();
12524         reset(mUsageStats);
12525         mService.setTelecomManager(null);
12526 
12527         mService.addEnqueuedNotification(r);
12528         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12529                 mPostNotificationTrackerFactory.newTracker(null)).run();
12530         waitForIdle();
12531 
12532         verify(mUsageStats).registerBlocked(any());
12533         verify(mUsageStats, never()).registerPostedByApp(any());
12534 
12535         // set FEATURE_TELECOM to false - notifications should be blocked
12536         // but post notifications runnable should not crash
12537         mService.setTelecomManager(mTelecomManager);
12538         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
12539         reset(mUsageStats);
12540         mService.setTelecomManager(null);
12541 
12542         mService.addEnqueuedNotification(r);
12543         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12544                 mPostNotificationTrackerFactory.newTracker(null)).run();
12545         waitForIdle();
12546 
12547         verify(mUsageStats).registerBlocked(any());
12548         verify(mUsageStats, never()).registerPostedByApp(any());
12549 
12550         // telecom is not ready - notifications should be blocked but no crashes
12551         mService.setTelecomManager(mTelecomManager);
12552         when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
12553         reset(mUsageStats);
12554 
12555         mService.addEnqueuedNotification(r);
12556         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
12557                 mPostNotificationTrackerFactory.newTracker(null)).run();
12558         waitForIdle();
12559 
12560         verify(mUsageStats).registerBlocked(any());
12561         verify(mUsageStats, never()).registerPostedByApp(any());
12562     }
12563 
12564     @Test
12565     public void testGetAllUsersNotificationPermissions() {
12566         // In this case, there are multiple users each with notification permissions (and also,
12567         // for good measure, some without).
12568         // make sure the collection returned contains info for all of them
12569         final List<UserInfo> userInfos = new ArrayList<>();
12570         userInfos.add(new UserInfo(0, "user0", 0));
12571         userInfos.add(new UserInfo(1, "user1", 0));
12572         userInfos.add(new UserInfo(2, "user2", 0));
12573         when(mUm.getUsers()).thenReturn(userInfos);
12574 
12575         // construct the permissions for each of them
12576         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
12577                 permissions1 = new ArrayMap<>();
12578         permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
12579         permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
12580         permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
12581         permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
12582         when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
12583         when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
12584         when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
12585 
12586         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
12587                 mService.getAllUsersNotificationPermissions();
12588         assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
12589         assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
12590         assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
12591         assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
12592         assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
12593         assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
12594         assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
12595         assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
12596     }
12597 
12598     @Test
12599     public void testGetActiveNotification_filtersUsers() throws Exception {
12600         when(mUm.getProfileIds(mUserId, false)).thenReturn(new int[]{mUserId, 10});
12601 
12602         NotificationRecord nr0 =
12603                 generateNotificationRecord(mTestNotificationChannel, mUserId);
12604         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
12605                 nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());
12606 
12607         NotificationRecord nr10 =
12608                 generateNotificationRecord(mTestNotificationChannel, 10);
12609         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag10",
12610                 nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());
12611 
12612         NotificationRecord nr11 =
12613                 generateNotificationRecord(mTestNotificationChannel, 11);
12614         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag11",
12615                 nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
12616         waitForIdle();
12617 
12618         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
12619         assertEquals(2, notifs.length);
12620         for (StatusBarNotification sbn : notifs) {
12621             if (sbn.getUserId() == 11) {
12622                 fail("leaked data across users");
12623             }
12624         }
12625     }
12626 
12627     @Test
12628     public void testGetActiveNotificationsFromListener_redactNotification() throws Exception {
12629         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
12630         NotificationRecord r =
12631                 generateNotificationRecord(mTestNotificationChannel, 0, 0);
12632         mService.addNotification(r);
12633         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
12634         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
12635         StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
12636         when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted);
12637         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12638         info.userid = 0;
12639         when(info.isSameUser(anyInt())).thenReturn(true);
12640         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
12641         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
12642         List<StatusBarNotification> notifications = mBinderService
12643                 .getActiveNotificationsFromListener(mock(INotificationListener.class), null, -1)
12644                 .getList();
12645 
12646         boolean foundRedactedSbn = false;
12647         for (StatusBarNotification sbn: notifications) {
12648             String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString();
12649             if (REDACTED_TEXT.equals(text)) {
12650                 foundRedactedSbn = true;
12651                 break;
12652             }
12653         }
12654         assertTrue("expect to find a redacted notification", foundRedactedSbn);
12655     }
12656 
12657     @Test
12658     public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception {
12659         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
12660         NotificationRecord r =
12661                 generateNotificationRecord(mTestNotificationChannel, 0, 0);
12662         when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r));
12663         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
12664         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
12665         StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
12666         when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted);
12667         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12668         info.userid = 0;
12669         when(info.isSameUser(anyInt())).thenReturn(true);
12670         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
12671         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
12672         List<StatusBarNotification> notifications = mBinderService
12673                 .getSnoozedNotificationsFromListener(mock(INotificationListener.class), -1)
12674                 .getList();
12675 
12676         boolean foundRedactedSbn = false;
12677         for (StatusBarNotification sbn: notifications) {
12678             String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString();
12679             if (REDACTED_TEXT.equals(text)) {
12680                 foundRedactedSbn = true;
12681                 break;
12682             }
12683         }
12684         assertTrue("expect to find a redacted notification", foundRedactedSbn);
12685     }
12686 
12687     @Test
12688     public void testUngroupingOngoingAutoSummary() throws Exception {
12689         NotificationRecord nr0 =
12690                 generateNotificationRecord(mTestNotificationChannel, 0);
12691         NotificationRecord nr1 =
12692                 generateNotificationRecord(mTestNotificationChannel, 0);
12693         nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT;
12694 
12695         mService.addNotification(nr0);
12696         mService.addNotification(nr1);
12697 
12698         // grouphelper is a mock here, so make the calls it would make
12699 
12700         // add summary
12701         mService.addNotification(
12702                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
12703                     nr1.getKey(), GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
12704                     VISIBILITY_PRIVATE));
12705 
12706         // cancel both children
12707         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
12708                 nr0.getSbn().getId(), nr0.getSbn().getUserId());
12709         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
12710                 nr1.getSbn().getId(), nr1.getSbn().getUserId());
12711         waitForIdle();
12712 
12713         // group helper would send 'remove summary' event
12714         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName());
12715         waitForIdle();
12716 
12717         // make sure the summary was removed and not re-posted
12718         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
12719     }
12720 
12721     @Test
12722     public void testUngroupingAutoSummary_differentUsers() throws Exception {
12723         NotificationRecord nr0 =
12724                 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM);
12725         NotificationRecord nr1 =
12726                 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM);
12727 
12728         // add notifications + summary for USER_SYSTEM
12729         mService.addNotification(nr0);
12730         mService.addNotification(nr1);
12731         mService.addNotification(
12732                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
12733                 nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE));
12734 
12735         // add notifications + summary for USER_ALL
12736         NotificationRecord nr0_all =
12737                 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL);
12738         NotificationRecord nr1_all =
12739                 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL);
12740 
12741         mService.addNotification(nr0_all);
12742         mService.addNotification(nr1_all);
12743         mService.addNotification(
12744                 mService.createAutoGroupSummary(nr0_all.getUserId(),
12745                 nr0_all.getSbn().getPackageName(),
12746                 nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE));
12747 
12748         // cancel both children for USER_ALL
12749         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(),
12750                 nr0_all.getSbn().getId(), UserHandle.USER_ALL);
12751         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(),
12752                 nr1_all.getSbn().getId(), UserHandle.USER_ALL);
12753         waitForIdle();
12754 
12755         // group helper would send 'remove summary' event
12756         mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL,
12757                 nr0_all.getSbn().getPackageName());
12758         waitForIdle();
12759 
12760         // make sure the right summary was removed
12761         assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(),
12762                 UserHandle.USER_ALL, 0, null)).isEqualTo(0);
12763 
12764         // the USER_SYSTEM notifications + summary were not removed
12765         assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(),
12766                 USER_SYSTEM, 0, null)).isEqualTo(3);
12767     }
12768 
12769     @Test
12770     public void testStrongAuthTracker_isInLockDownMode() {
12771         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
12772                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
12773         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
12774         assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
12775         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId());
12776         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
12777         assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
12778     }
12779 
12780     @Test
12781     public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() {
12782         // post 2 notifications from 2 packages
12783         NotificationRecord pkgA = new NotificationRecord(mContext,
12784                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
12785         mService.addNotification(pkgA);
12786         NotificationRecord pkgB = new NotificationRecord(mContext,
12787                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
12788         mService.addNotification(pkgB);
12789 
12790         // when entering the lockdown mode, cancel the 2 notifications.
12791         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
12792                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
12793         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
12794         assertTrue(mStrongAuthTracker.isInLockDownMode(0));
12795 
12796         // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
12797         ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
12798         verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
12799         assertEquals(REASON_LOCKDOWN, captor.getValue().intValue());
12800 
12801         // exit lockdown mode.
12802         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
12803         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
12804         assertFalse(mStrongAuthTracker.isInLockDownMode(0));
12805 
12806         // the notifyPostedLocked function is called twice.
12807         verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong());
12808     }
12809 
12810     @Test
12811     public void testMakeRankingUpdateLockedInLockDownMode() {
12812         // post 2 notifications from a same package
12813         NotificationRecord pkgA = new NotificationRecord(mContext,
12814                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
12815         mService.addNotification(pkgA);
12816         NotificationRecord pkgB = new NotificationRecord(mContext,
12817                 generateSbn("a", 1000, 9, 1), mTestNotificationChannel);
12818         mService.addNotification(pkgB);
12819 
12820         mService.setIsVisibleToListenerReturnValue(true);
12821         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null);
12822         assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
12823 
12824         // when only user 0 entering the lockdown mode, its notification will be suppressed.
12825         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
12826                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
12827         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
12828         assertTrue(mStrongAuthTracker.isInLockDownMode(0));
12829         assertFalse(mStrongAuthTracker.isInLockDownMode(1));
12830 
12831         nru = mService.makeRankingUpdateLocked(null);
12832         assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
12833 
12834         // User 0 exits lockdown mode. Its notification will be resumed.
12835         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
12836         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
12837         assertFalse(mStrongAuthTracker.isInLockDownMode(0));
12838         assertFalse(mStrongAuthTracker.isInLockDownMode(1));
12839 
12840         nru = mService.makeRankingUpdateLocked(null);
12841         assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
12842     }
12843 
12844     @Test
12845     public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() {
12846         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
12847         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
12848         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
12849         NotificationRecord pkgA = new NotificationRecord(mContext,
12850                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
12851         addSmartActionsAndReplies(pkgA);
12852         mService.addNotification(pkgA);
12853         NotificationRecord pkgB = new NotificationRecord(mContext,
12854                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
12855         addSmartActionsAndReplies(pkgB);
12856         mService.addNotification(pkgB);
12857 
12858         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12859         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
12860         when(info.isSameUser(anyInt())).thenReturn(true);
12861         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
12862         NotificationListenerService.Ranking ranking =
12863                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
12864         assertEquals(0, ranking.getSmartActions().size());
12865         assertEquals(0, ranking.getSmartReplies().size());
12866         NotificationListenerService.Ranking ranking2 =
12867                 nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey());
12868         assertEquals(0, ranking2.getSmartActions().size());
12869         assertEquals(0, ranking2.getSmartReplies().size());
12870     }
12871 
12872     @Test
12873     public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() {
12874         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
12875         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
12876         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
12877         NotificationRecord pkgA = new NotificationRecord(mContext,
12878                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
12879         addSmartActionsAndReplies(pkgA);
12880 
12881         mService.addNotification(pkgA);
12882         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12883         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
12884         when(info.isSameUser(anyInt())).thenReturn(true);
12885         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
12886         NotificationListenerService.Ranking ranking =
12887                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
12888         assertEquals(1, ranking.getSmartActions().size());
12889         assertEquals(1, ranking.getSmartReplies().size());
12890     }
12891 
12892     @Test
12893     public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() {
12894         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
12895         NotificationRecord pkgA = new NotificationRecord(mContext,
12896                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
12897         addSmartActionsAndReplies(pkgA);
12898 
12899         mService.addNotification(pkgA);
12900         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12901         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
12902         when(info.isSameUser(anyInt())).thenReturn(true);
12903 
12904         // No sensitive content, no redaction
12905         when(mListeners.isUidTrusted(eq(1000))).thenReturn(false);
12906         when(mListeners.hasSensitiveContent(any())).thenReturn(false);
12907         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
12908         NotificationListenerService.Ranking ranking =
12909                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
12910         assertEquals(1, ranking.getSmartActions().size());
12911         assertEquals(1, ranking.getSmartReplies().size());
12912 
12913         // trusted listener, no redaction
12914         when(mListeners.isUidTrusted(eq(1000))).thenReturn(true);
12915         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
12916         nru = mService.makeRankingUpdateLocked(info);
12917         ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
12918         assertEquals(1, ranking.getSmartActions().size());
12919         assertEquals(1, ranking.getSmartReplies().size());
12920     }
12921 
12922     private void addSmartActionsAndReplies(NotificationRecord record) {
12923         Bundle b = new Bundle();
12924         ArrayList<Notification.Action> actions = new ArrayList<>();
12925         actions.add(new Notification.Action(0, "", null));
12926         b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions);
12927         ArrayList<CharSequence> replies = new ArrayList<>(List.of("test"));
12928         b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies);
12929         Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(),
12930                 b, "", record.getUserId());
12931         record.addAdjustment(a);
12932         record.applyAdjustments();
12933     }
12934 
12935     @Test
12936     public void testMaybeShowReviewPermissionsNotification_flagOff() {
12937         mService.setShowReviewPermissionsNotification(false);
12938         reset(mMockNm);
12939 
12940         // If state is SHOULD_SHOW, it would show, but not if the flag is off!
12941         Settings.Global.putInt(mContext.getContentResolver(),
12942                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
12943                 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW);
12944         mService.maybeShowInitialReviewPermissionsNotification();
12945         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
12946     }
12947 
12948     @Test
12949     public void testMaybeShowReviewPermissionsNotification_unknown() {
12950         mService.setShowReviewPermissionsNotification(true);
12951         reset(mMockNm);
12952 
12953         // Set up various possible states of the settings int and confirm whether or not the
12954         // notification is shown as expected
12955 
12956         // Initial state: default/unknown setting, make sure nothing happens
12957         Settings.Global.putInt(mContext.getContentResolver(),
12958                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
12959                 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN);
12960         mService.maybeShowInitialReviewPermissionsNotification();
12961         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
12962     }
12963 
12964     @Test
12965     public void testMaybeShowReviewPermissionsNotification_shouldShow() {
12966         mService.setShowReviewPermissionsNotification(true);
12967         reset(mMockNm);
12968 
12969         // If state is SHOULD_SHOW, it ... should show
12970         Settings.Global.putInt(mContext.getContentResolver(),
12971                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
12972                 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW);
12973         mService.maybeShowInitialReviewPermissionsNotification();
12974         verify(mMockNm, times(1)).notify(eq(TAG),
12975                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
12976                 any(Notification.class));
12977     }
12978 
12979     @Test
12980     public void testMaybeShowReviewPermissionsNotification_alreadyShown() {
12981         mService.setShowReviewPermissionsNotification(true);
12982         reset(mMockNm);
12983 
12984         // If state is either USER_INTERACTED or DISMISSED, we should not show this on boot
12985         Settings.Global.putInt(mContext.getContentResolver(),
12986                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
12987                 NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED);
12988         mService.maybeShowInitialReviewPermissionsNotification();
12989 
12990         Settings.Global.putInt(mContext.getContentResolver(),
12991                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
12992                 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED);
12993         mService.maybeShowInitialReviewPermissionsNotification();
12994 
12995         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
12996     }
12997 
12998     @Test
12999     public void testMaybeShowReviewPermissionsNotification_reshown() {
13000         mService.setShowReviewPermissionsNotification(true);
13001         reset(mMockNm);
13002 
13003         // If we have re-shown the notification and the user did not subsequently interacted with
13004         // it, then make sure we show when trying on boot
13005         Settings.Global.putInt(mContext.getContentResolver(),
13006                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
13007                 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN);
13008         mService.maybeShowInitialReviewPermissionsNotification();
13009         verify(mMockNm, times(1)).notify(eq(TAG),
13010                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
13011                 any(Notification.class));
13012     }
13013 
13014     @Test
13015     public void testRescheduledReviewPermissionsNotification() {
13016         mService.setShowReviewPermissionsNotification(true);
13017         reset(mMockNm);
13018 
13019         // when rescheduled, the notification goes through the NotificationManagerInternal service
13020         // this call doesn't need to know anything about previously scheduled state -- if called,
13021         // it should send the notification & write the appropriate int to Settings
13022         mInternalService.sendReviewPermissionsNotification();
13023 
13024         // Notification should be sent
13025         verify(mMockNm, times(1)).notify(eq(TAG),
13026                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
13027                 any(Notification.class));
13028 
13029         // write STATE_RESHOWN to settings
13030         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN,
13031                 Settings.Global.getInt(mContext.getContentResolver(),
13032                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
13033                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
13034     }
13035 
13036     @Test
13037     public void testRescheduledReviewPermissionsNotification_flagOff() {
13038         mService.setShowReviewPermissionsNotification(false);
13039         reset(mMockNm);
13040 
13041         // no notification should be sent if the flag is off
13042         mInternalService.sendReviewPermissionsNotification();
13043         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
13044     }
13045 
13046     private void verifyStickyHun(int permissionState, boolean appRequested,
13047             boolean isSticky) throws Exception {
13048 
13049         when(mPermissionHelper.hasRequestedPermission(Manifest.permission.USE_FULL_SCREEN_INTENT,
13050                 mPkg, mUserId)).thenReturn(appRequested);
13051 
13052         when(mPermissionManager.checkPermissionForDataDelivery(
13053                 eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any()))
13054                 .thenReturn(permissionState);
13055 
13056         Notification n = new Notification.Builder(mContext, "test")
13057                 .setFullScreenIntent(mActivityIntent, true)
13058                 .build();
13059 
13060         mService.fixNotification(n, mPkg, "tag", 9, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
13061 
13062         final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
13063 
13064         if (isSticky) {
13065             assertNotSame(0, stickyFlag);
13066         } else {
13067             assertSame(0, stickyFlag);
13068         }
13069     }
13070 
13071     @Test
13072     public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun()
13073             throws Exception {
13074 
13075         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_HARD_DENIED, true,
13076                 /* isSticky= */ true);
13077     }
13078 
13079     @Test
13080     public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun()
13081             throws Exception {
13082 
13083         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, true,
13084                 /* isSticky= */ true);
13085     }
13086 
13087     @Test
13088     public void testFixNotification_fsiPermissionSoftDenied_appNotRequest_noShowStickyHun()
13089             throws Exception {
13090         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, false,
13091                 /* isSticky= */ false);
13092     }
13093 
13094 
13095     @Test
13096     public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi()
13097             throws Exception {
13098 
13099         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_GRANTED, true,
13100                 /* isSticky= */ false);
13101     }
13102 
13103     @Test
13104     public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception {
13105         final ApplicationInfo applicationInfo = new ApplicationInfo();
13106         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
13107                 .thenReturn(applicationInfo);
13108 
13109         Notification n = new Notification.Builder(mContext, "test")
13110                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
13111                 .setFlag(FLAG_CAN_COLORIZE, true)
13112                 .build();
13113 
13114         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13115 
13116         assertFalse(n.isForegroundService());
13117         assertFalse(n.hasColorizedPermission());
13118     }
13119 
13120     @Test
13121     public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception {
13122         Person person = new Person.Builder().setName("caller").build();
13123         Notification n = new Notification.Builder(mContext, "test")
13124                 .setStyle(Notification.CallStyle.forOngoingCall(
13125                         person, mActivityIntent))
13126                 .build();
13127         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13128                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13129         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13130 
13131         try {
13132             mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13133                     r.getSbn().getId(), r.getSbn().getTag(), r, false, false);
13134             assertFalse("CallStyle should not be allowed without a valid use case", true);
13135         } catch (IllegalArgumentException error) {
13136             assertThat(error.getMessage()).contains("CallStyle");
13137         }
13138     }
13139 
13140     @Test
13141     public void checkCallStyleNotification_allowedForFgs() throws Exception {
13142         Person person = new Person.Builder().setName("caller").build();
13143         Notification n = new Notification.Builder(mContext, "test")
13144                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
13145                 .setStyle(Notification.CallStyle.forOngoingCall(
13146                         person, mActivityIntent))
13147                 .build();
13148         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13149                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13150         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13151 
13152         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13153                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13154     }
13155 
13156     private NotificationRecord createBigPictureRecord(boolean isBigPictureStyle, boolean hasImage,
13157                                                       boolean isImageBitmap, boolean isExpired) {
13158         Notification.Builder builder = new Notification.Builder(mContext);
13159         Notification.BigPictureStyle style = new Notification.BigPictureStyle();
13160 
13161         if (isBigPictureStyle && hasImage) {
13162             if (isImageBitmap) {
13163                 style = style.bigPicture(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888));
13164             } else {
13165                 style = style.bigPicture(Icon.createWithResource(mContext, R.drawable.btn_plus));
13166             }
13167         }
13168         if (isBigPictureStyle) {
13169             builder.setStyle(style);
13170         }
13171 
13172         Notification notification = builder.setChannelId(TEST_CHANNEL_ID).build();
13173 
13174         long timePostedMs = System.currentTimeMillis();
13175         if (isExpired) {
13176             timePostedMs -= BITMAP_DURATION.toMillis();
13177         }
13178         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13179                 notification, UserHandle.getUserHandleForUid(mUid), null, timePostedMs);
13180 
13181         return new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13182     }
13183 
13184     private void addRecordAndRemoveBitmaps(NotificationRecord record) {
13185         mService.addNotification(record);
13186         mInternalService.removeBitmaps();
13187         waitForIdle();
13188     }
13189 
13190     @Test
13191     public void testRemoveBitmaps_notBigPicture_noRepost() {
13192         addRecordAndRemoveBitmaps(
13193                 createBigPictureRecord(
13194                         /* isBigPictureStyle= */ false,
13195                         /* hasImage= */ false,
13196                         /* isImageBitmap= */ false,
13197                         /* isExpired= */ false));
13198         verify(mWorkerHandler, never())
13199                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
13200     }
13201 
13202     @Test
13203     public void testRemoveBitmaps_bigPictureNoImage_noRepost() {
13204         addRecordAndRemoveBitmaps(
13205                 createBigPictureRecord(
13206                         /* isBigPictureStyle= */ true,
13207                         /* hasImage= */ false,
13208                         /* isImageBitmap= */ false,
13209                         /* isExpired= */ false));
13210         verify(mWorkerHandler, never())
13211                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
13212     }
13213 
13214     @Test
13215     public void testRemoveBitmaps_notExpired_noRepost() {
13216         addRecordAndRemoveBitmaps(
13217                 createBigPictureRecord(
13218                         /* isBigPictureStyle= */ true,
13219                         /* hasImage= */ true,
13220                         /* isImageBitmap= */ true,
13221                         /* isExpired= */ false));
13222         verify(mWorkerHandler, never())
13223                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
13224     }
13225 
13226     @Test
13227     public void testRemoveBitmaps_bitmapExpired_repost() {
13228         addRecordAndRemoveBitmaps(
13229                 createBigPictureRecord(
13230                         /* isBigPictureStyle= */ true,
13231                         /* hasImage= */ true,
13232                         /* isImageBitmap= */ true,
13233                         /* isExpired= */ true));
13234         verify(mWorkerHandler, times(1))
13235                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
13236     }
13237 
13238     @Test
13239     public void testRemoveBitmaps_bitmapExpired_bitmapGone() {
13240         NotificationRecord record = createBigPictureRecord(
13241                 /* isBigPictureStyle= */ true,
13242                 /* hasImage= */ true,
13243                 /* isImageBitmap= */ true,
13244                 /* isExpired= */ true);
13245         addRecordAndRemoveBitmaps(record);
13246         assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE)).isTrue();
13247         final Parcelable picture = record.getNotification().extras.getParcelable(EXTRA_PICTURE);
13248         assertThat(picture).isNull();
13249     }
13250 
13251     @Test
13252     public void testRemoveBitmaps_bitmapExpired_silent() {
13253         NotificationRecord record = createBigPictureRecord(
13254                 /* isBigPictureStyle= */ true,
13255                 /* hasImage= */ true,
13256                 /* isImageBitmap= */ true,
13257                 /* isExpired= */ true);
13258         addRecordAndRemoveBitmaps(record);
13259         assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
13260     }
13261 
13262     @Test
13263     public void testRemoveBitmaps_iconExpired_repost() {
13264         addRecordAndRemoveBitmaps(
13265                 createBigPictureRecord(
13266                         /* isBigPictureStyle= */ true,
13267                         /* hasImage= */ true,
13268                         /* isImageBitmap= */ false,
13269                         /* isExpired= */ true));
13270         verify(mWorkerHandler, times(1))
13271                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
13272     }
13273 
13274     @Test
13275     public void testRemoveBitmaps_iconExpired_iconGone() {
13276         NotificationRecord record = createBigPictureRecord(
13277                 /* isBigPictureStyle= */ true,
13278                 /* hasImage= */ true,
13279                 /* isImageBitmap= */ false,
13280                 /* isExpired= */ true);
13281         addRecordAndRemoveBitmaps(record);
13282         assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE_ICON)).isTrue();
13283         final Parcelable pictureIcon =
13284                 record.getNotification().extras.getParcelable(EXTRA_PICTURE_ICON);
13285         assertThat(pictureIcon).isNull();
13286     }
13287 
13288     @Test
13289     public void testRemoveBitmaps_iconExpired_silent() {
13290         NotificationRecord record = createBigPictureRecord(
13291                 /* isBigPictureStyle= */ true,
13292                 /* hasImage= */ true,
13293                 /* isImageBitmap= */ false,
13294                 /* isExpired= */ true);
13295         addRecordAndRemoveBitmaps(record);
13296         assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
13297     }
13298 
13299     @Test
13300     public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
13301         Person person = new Person.Builder().setName("caller").build();
13302         Notification n = new Notification.Builder(mContext, "test")
13303                 // Without FLAG_FOREGROUND_SERVICE.
13304                 //.setFlag(FLAG_FOREGROUND_SERVICE, true)
13305                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
13306                 .build();
13307         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13308                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13309         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13310 
13311         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13312                 r.getSbn().getId(), r.getSbn().getTag(), r, false,
13313                 true /* byForegroundService */)).isTrue();
13314     }
13315 
13316     @Test
13317     public void checkCallStyleNotification_allowedForUij() throws Exception {
13318         Person person = new Person.Builder().setName("caller").build();
13319         Notification n = new Notification.Builder(mContext, "test")
13320                 .setFlag(FLAG_USER_INITIATED_JOB, true)
13321                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
13322                 .build();
13323         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13324                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13325         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13326 
13327         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13328                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13329     }
13330 
13331     @Test
13332     public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception {
13333         Person person = new Person.Builder().setName("caller").build();
13334         Notification n = new Notification.Builder(mContext, "test")
13335                 .setFullScreenIntent(mActivityIntent, true)
13336                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
13337                 .build();
13338         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13339                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13340         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13341 
13342         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13343                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13344     }
13345 
13346     @Test
13347     public void checkCallStyleNotification_allowedForFsiDenied() throws Exception {
13348         Person person = new Person.Builder().setName("caller").build();
13349         Notification n = new Notification.Builder(mContext, "test")
13350                 .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true)
13351                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
13352                 .build();
13353         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13354                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13355         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13356 
13357         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13358                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13359     }
13360 
13361     @Test
13362     public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible()
13363             throws Exception {
13364         final ApplicationInfo ai = new ApplicationInfo();
13365         ai.packageName = "pkg";
13366         ai.uid = mUid;
13367         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
13368 
13369         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
13370                 .thenReturn(ai);
13371         when(mAppOpsManager.checkOpNoThrow(
13372                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
13373                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
13374         // Given: a notification from an app on the system partition has the flag
13375         // FLAG_ONGOING_EVENT set
13376         Notification n = new Notification.Builder(mContext, "test")
13377                 .setOngoing(true)
13378                 .build();
13379 
13380         // When: fix the notification with NotificationManagerService
13381         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13382 
13383         // Then: the notification's flag FLAG_NO_DISMISS should not be set
13384         assertSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13385     }
13386 
13387     @Test
13388     public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible()
13389             throws Exception {
13390         // Given: a media notification has the flag FLAG_ONGOING_EVENT set
13391         Notification n = new Notification.Builder(mContext, "test")
13392                 .setOngoing(true)
13393                 .setStyle(new Notification.MediaStyle()
13394                         .setMediaSession(mock(MediaSession.Token.class)))
13395                 .build();
13396 
13397         // When: fix the notification with NotificationManagerService
13398         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13399 
13400         // Then: the notification's flag FLAG_NO_DISMISS should be set
13401         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13402     }
13403 
13404     @Test
13405     public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible()
13406             throws Exception {
13407         final ApplicationInfo ai = new ApplicationInfo();
13408         ai.packageName = SEARCH_SELECTOR_PKG;
13409         ai.uid = mUid;
13410         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
13411 
13412         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
13413                 .thenReturn(ai);
13414         when(mAppOpsManager.checkOpNoThrow(
13415                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
13416                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
13417         // Given: a notification from an app on the system partition has the flag
13418         // FLAG_ONGOING_EVENT set
13419         Notification n = new Notification.Builder(mContext, "test")
13420                 .setOngoing(true)
13421                 .build();
13422 
13423         // When: fix the notification with NotificationManagerService
13424         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13425 
13426         // Then: the notification's flag FLAG_NO_DISMISS should be set
13427         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13428     }
13429 
13430     @Test
13431     public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible()
13432             throws Exception {
13433         final ApplicationInfo ai = new ApplicationInfo();
13434         ai.packageName = ADSERVICES_APK_PKG;
13435         ai.uid = mUid;
13436         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
13437 
13438         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
13439                 .thenReturn(ai);
13440         when(mAppOpsManager.checkOpNoThrow(
13441                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
13442                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
13443         // Given: a notification from an app on the system partition has the flag
13444         // FLAG_ONGOING_EVENT set
13445         Notification n = new Notification.Builder(mContext, "test")
13446                 .setOngoing(true)
13447                 .build();
13448 
13449         // When: fix the notification with NotificationManagerService
13450         mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE,
13451                  true);
13452 
13453         // Then: the notification's flag FLAG_NO_DISMISS should be set
13454         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13455     }
13456 
13457     @Test
13458     public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible()
13459             throws Exception {
13460         // Given: a call notification has the flag FLAG_ONGOING_EVENT set
13461         Person person = new Person.Builder()
13462                 .setName("caller")
13463                 .build();
13464         Notification n = new Notification.Builder(mContext, "test")
13465                 .setOngoing(true)
13466                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
13467                 .build();
13468 
13469         // When: fix the notification with NotificationManagerService
13470         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13471 
13472         // Then: the notification's flag FLAG_NO_DISMISS should be set
13473         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13474     }
13475 
13476 
13477     @Test
13478     public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception {
13479         // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
13480         Notification n = new Notification.Builder(mContext, "test")
13481                 .setOngoing(true)
13482                 .build();
13483 
13484         // When: fix the notification with NotificationManagerService
13485         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13486 
13487         // Then: the notification's flag FLAG_NO_DISMISS should not be set
13488         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
13489     }
13490 
13491     @Test
13492     public void fixNonExemptNotification_withNoDismissFlag_shouldBeDismissible()
13493             throws Exception {
13494         // Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is
13495         // not allowed)
13496         Notification n = new Notification.Builder(mContext, "test")
13497                 .build();
13498         n.flags |= Notification.FLAG_NO_DISMISS;
13499 
13500         // When: fix the notification with NotificationManagerService
13501         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13502 
13503         // Then: the notification's flag FLAG_NO_DISMISS should be cleared
13504         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
13505     }
13506 
13507     @Test
13508     public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception {
13509         // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set
13510         Notification n = new Notification.Builder(mContext, "test")
13511                 .setOngoing(false)
13512                 .setStyle(new Notification.MediaStyle()
13513                         .setMediaSession(mock(MediaSession.Token.class)))
13514                 .build();
13515 
13516         // When: fix the notification with NotificationManagerService
13517         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13518 
13519         // Then: the notification's flag FLAG_NO_DISMISS should not be set
13520         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
13521     }
13522 
13523     @Test
13524     public void fixMediaNotification_withoutOnGoingFlag_withNoDismissFlag_shouldBeDismissible()
13525             throws Exception {
13526         // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set,
13527         // but has the flag FLAG_NO_DISMISS set
13528         Notification n = new Notification.Builder(mContext, "test")
13529                 .setOngoing(false)
13530                 .setStyle(new Notification.MediaStyle()
13531                         .setMediaSession(mock(MediaSession.Token.class)))
13532                 .build();
13533         n.flags |= Notification.FLAG_NO_DISMISS;
13534 
13535         // When: fix the notification with NotificationManagerService
13536         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13537 
13538         // Then: the notification's flag FLAG_NO_DISMISS should be cleared
13539         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
13540     }
13541 
13542     @Test
13543     public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible()
13544             throws Exception {
13545         // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
13546         Notification n = new Notification.Builder(mContext, "test")
13547                 .setOngoing(false)
13548                 .build();
13549 
13550         // When: fix the notification with NotificationManagerService
13551         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13552 
13553         // Then: the notification's flag FLAG_NO_DISMISS should not be set
13554         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
13555     }
13556 
13557     @Test
13558     public void fixOrganizationAdminNotification_withOnGoingFlag_shouldBeNonDismissible()
13559             throws Exception {
13560         when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true);
13561         // Given: a notification has the flag FLAG_ONGOING_EVENT set
13562         Notification n = new Notification.Builder(mContext, "test")
13563                 .setOngoing(true)
13564                 .build();
13565 
13566         // When: fix the notification with NotificationManagerService
13567         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13568 
13569         // Then: the notification's flag FLAG_NO_DISMISS should be set
13570         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13571     }
13572 
13573     @Test
13574     public void fixExemptAppOpNotification_withFlag_shouldBeNonDismissible()
13575             throws Exception {
13576         final ApplicationInfo ai = new ApplicationInfo();
13577         ai.packageName = mPkg;
13578         ai.uid = mUid;
13579         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
13580 
13581         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
13582                 .thenReturn(ai);
13583         when(mAppOpsManager.checkOpNoThrow(
13584                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
13585                 mPkg)).thenReturn(AppOpsManager.MODE_ALLOWED);
13586         // Given: a notification has the flag FLAG_ONGOING_EVENT set
13587         Notification n = new Notification.Builder(mContext, "test")
13588                 .setOngoing(true)
13589                 .build();
13590 
13591         // When: fix the notification with NotificationManagerService
13592         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13593 
13594         // Then: the notification's flag FLAG_NO_DISMISS should be set
13595         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13596     }
13597 
13598     @Test
13599     public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible()
13600             throws Exception {
13601         when(mAppOpsManager.checkOpNoThrow(
13602                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
13603                 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED);
13604         // Given: a notification has the flag FLAG_ONGOING_EVENT set
13605         Notification n = new Notification.Builder(mContext, "test")
13606                 .setOngoing(true)
13607                 .build();
13608 
13609         // When: fix the notification with NotificationManagerService
13610         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
13611 
13612         // Then: the notification's flag FLAG_NO_DISMISS should not be set
13613         assertSame(0, n.flags & Notification.FLAG_NO_DISMISS);
13614     }
13615 
13616     @Test
13617     public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception {
13618         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13619                 .thenReturn(true);
13620         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
13621         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13622         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13623                 "testCancelAllNotifications_IgnoreUserInitiatedJob",
13624                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13625         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
13626         waitForIdle();
13627         StatusBarNotification[] notifs =
13628                 mBinderService.getActiveNotifications(sbn.getPackageName());
13629         assertEquals(1, notifs.length);
13630         assertEquals(1, mService.getNotificationRecordCount());
13631     }
13632 
13633     @Test
13634     public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception {
13635         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13636                 .thenReturn(false);
13637         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
13638         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13639         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13640                 "testCancelAllNotifications_UijFlag_NoUij_Allowed",
13641                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13642         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
13643         waitForIdle();
13644         StatusBarNotification[] notifs =
13645                 mBinderService.getActiveNotifications(sbn.getPackageName());
13646         assertEquals(0, notifs.length);
13647     }
13648 
13649     @Test
13650     public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception {
13651         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13652                 .thenReturn(true);
13653         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
13654         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13655         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13656                 "testCancelAllNotifications_IgnoreOtherPackages",
13657                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13658         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
13659         waitForIdle();
13660         StatusBarNotification[] notifs =
13661                 mBinderService.getActiveNotifications(sbn.getPackageName());
13662         assertEquals(1, notifs.length);
13663         assertEquals(1, mService.getNotificationRecordCount());
13664     }
13665 
13666     @Test
13667     public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception {
13668         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13669                 .thenReturn(true);
13670         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
13671                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13672                 .build();
13673         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
13674                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
13675         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13676         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null,
13677                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13678         mInternalService.removeUserInitiatedJobFlagFromNotification(mPkg, sbn.getId(),
13679                 sbn.getUserId());
13680         waitForIdle();
13681         StatusBarNotification[] notifs =
13682                 mBinderService.getActiveNotifications(sbn.getPackageName());
13683         assertFalse(notifs[0].getNotification().isUserInitiatedJob());
13684     }
13685 
13686     @Test
13687     public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception {
13688         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
13689         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB;
13690         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
13691                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13692         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
13693         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
13694                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13695         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
13696                 sbn.getUserId());
13697         waitForIdle();
13698         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
13699         assertEquals(0, mService.getNotificationRecordCount());
13700     }
13701 
13702     @Test
13703     public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception {
13704         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13705                 .thenReturn(true);
13706         mService.isSystemUid = false;
13707         mService.isSystemAppId = false;
13708         final NotificationRecord parent = generateNotificationRecord(
13709                 mTestNotificationChannel, 1, "group", true);
13710         final NotificationRecord child = generateNotificationRecord(
13711                 mTestNotificationChannel, 2, "group", false);
13712         final NotificationRecord child2 = generateNotificationRecord(
13713                 mTestNotificationChannel, 3, "group", false);
13714         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13715         mService.addNotification(parent);
13716         mService.addNotification(child);
13717         mService.addNotification(child2);
13718         mService.getBinderService().cancelNotificationWithTag(
13719                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
13720                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
13721         waitForIdle();
13722         StatusBarNotification[] notifs =
13723                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13724         assertEquals(1, notifs.length);
13725     }
13726 
13727     @Test
13728     public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception {
13729         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13730                 .thenReturn(true);
13731         mService.isSystemUid = false;
13732         mService.isSystemAppId = false;
13733         final NotificationRecord parent = generateNotificationRecord(
13734                 mTestNotificationChannel, 1, "group", true);
13735         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13736         final NotificationRecord child = generateNotificationRecord(
13737                 mTestNotificationChannel, 2, "group", false);
13738         final NotificationRecord child2 = generateNotificationRecord(
13739                 mTestNotificationChannel, 3, "group", false);
13740         mService.addNotification(parent);
13741         mService.addNotification(child);
13742         mService.addNotification(child2);
13743         mService.getBinderService().cancelNotificationWithTag(
13744                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
13745                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
13746         waitForIdle();
13747         StatusBarNotification[] notifs =
13748                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13749         assertEquals(3, notifs.length);
13750     }
13751 
13752     @Test
13753     public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception {
13754         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13755                 .thenReturn(true);
13756         mService.isSystemUid = false;
13757         mService.isSystemAppId = false;
13758         final NotificationRecord parent = generateNotificationRecord(
13759                 mTestNotificationChannel, 1, "group", true);
13760         final NotificationRecord child = generateNotificationRecord(
13761                 mTestNotificationChannel, 2, "group", false);
13762         final NotificationRecord child2 = generateNotificationRecord(
13763                 mTestNotificationChannel, 3, "group", false);
13764         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13765         final NotificationRecord newGroup = generateNotificationRecord(
13766                 mTestNotificationChannel, 4, "group2", false);
13767         mService.addNotification(parent);
13768         mService.addNotification(child);
13769         mService.addNotification(child2);
13770         mService.addNotification(newGroup);
13771         mService.getBinderService().cancelAllNotifications(
13772                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
13773         waitForIdle();
13774         StatusBarNotification[] notifs =
13775                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13776         assertEquals(1, notifs.length);
13777     }
13778 
13779     @Test
13780     public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception {
13781         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13782                 .thenReturn(true);
13783         mService.isSystemUid = false;
13784         mService.isSystemAppId = false;
13785         final NotificationRecord parent = generateNotificationRecord(
13786                 mTestNotificationChannel, 1, "group", true);
13787         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13788         final NotificationRecord child = generateNotificationRecord(
13789                 mTestNotificationChannel, 2, "group", false);
13790         final NotificationRecord child2 = generateNotificationRecord(
13791                 mTestNotificationChannel, 3, "group", false);
13792         final NotificationRecord newGroup = generateNotificationRecord(
13793                 mTestNotificationChannel, 4, "group2", false);
13794         mService.addNotification(parent);
13795         mService.addNotification(child);
13796         mService.addNotification(child2);
13797         mService.addNotification(newGroup);
13798         mService.getBinderService().cancelAllNotifications(
13799                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
13800         waitForIdle();
13801         StatusBarNotification[] notifs =
13802                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13803         assertEquals(1, notifs.length);
13804     }
13805 
13806     @Test
13807     public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception {
13808         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13809                 .thenReturn(true);
13810         final NotificationRecord parent = generateNotificationRecord(
13811                 mTestNotificationChannel, 1, "group", true);
13812         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13813         final NotificationRecord child = generateNotificationRecord(
13814                 mTestNotificationChannel, 2, "group", false);
13815         final NotificationRecord child2 = generateNotificationRecord(
13816                 mTestNotificationChannel, 3, "group", false);
13817         final NotificationRecord newGroup = generateNotificationRecord(
13818                 mTestNotificationChannel, 4, "group2", false);
13819         mService.addNotification(parent);
13820         mService.addNotification(child);
13821         mService.addNotification(child2);
13822         mService.addNotification(newGroup);
13823         mService.getBinderService().cancelNotificationsFromListener(null, null);
13824         waitForIdle();
13825         StatusBarNotification[] notifs =
13826                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13827         assertEquals(0, notifs.length);
13828     }
13829 
13830     @Test
13831     public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception {
13832         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13833                 .thenReturn(true);
13834         final NotificationRecord parent = generateNotificationRecord(
13835                 mTestNotificationChannel, 1, "group", true);
13836         final NotificationRecord child = generateNotificationRecord(
13837                 mTestNotificationChannel, 2, "group", false);
13838         final NotificationRecord child2 = generateNotificationRecord(
13839                 mTestNotificationChannel, 3, "group", false);
13840         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13841         final NotificationRecord newGroup = generateNotificationRecord(
13842                 mTestNotificationChannel, 4, "group2", false);
13843         mService.addNotification(parent);
13844         mService.addNotification(child);
13845         mService.addNotification(child2);
13846         mService.addNotification(newGroup);
13847         mService.getBinderService().cancelNotificationsFromListener(null, null);
13848         waitForIdle();
13849         StatusBarNotification[] notifs =
13850                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13851         assertEquals(0, notifs.length);
13852     }
13853 
13854     @Test
13855     public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception {
13856         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13857                 .thenReturn(true);
13858         final NotificationRecord child2 = generateNotificationRecord(
13859                 mTestNotificationChannel, 3, null, false);
13860         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13861         mService.addNotification(child2);
13862         mService.getBinderService().cancelNotificationsFromListener(null, null);
13863         waitForIdle();
13864         StatusBarNotification[] notifs =
13865                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
13866         assertEquals(0, notifs.length);
13867     }
13868 
13869     @Test
13870     public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception {
13871         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13872                 .thenReturn(true);
13873         final NotificationRecord parent = generateNotificationRecord(
13874                 mTestNotificationChannel, 1, "group", true);
13875         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13876         final NotificationRecord child = generateNotificationRecord(
13877                 mTestNotificationChannel, 2, "group", false);
13878         final NotificationRecord child2 = generateNotificationRecord(
13879                 mTestNotificationChannel, 3, "group", false);
13880         final NotificationRecord newGroup = generateNotificationRecord(
13881                 mTestNotificationChannel, 4, "group2", false);
13882         mService.addNotification(parent);
13883         mService.addNotification(child);
13884         mService.addNotification(child2);
13885         mService.addNotification(newGroup);
13886         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
13887                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
13888         mService.getBinderService().cancelNotificationsFromListener(null, keys);
13889         waitForIdle();
13890         StatusBarNotification[] notifs =
13891                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13892         assertEquals(0, notifs.length);
13893     }
13894 
13895     @Test
13896     public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception {
13897         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13898                 .thenReturn(true);
13899         final NotificationRecord parent = generateNotificationRecord(
13900                 mTestNotificationChannel, 1, "group", true);
13901         final NotificationRecord child = generateNotificationRecord(
13902                 mTestNotificationChannel, 2, "group", false);
13903         final NotificationRecord child2 = generateNotificationRecord(
13904                 mTestNotificationChannel, 3, "group", false);
13905         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13906         final NotificationRecord newGroup = generateNotificationRecord(
13907                 mTestNotificationChannel, 4, "group2", false);
13908         mService.addNotification(parent);
13909         mService.addNotification(child);
13910         mService.addNotification(child2);
13911         mService.addNotification(newGroup);
13912         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
13913                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
13914         mService.getBinderService().cancelNotificationsFromListener(null, keys);
13915         waitForIdle();
13916         StatusBarNotification[] notifs =
13917                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13918         assertEquals(0, notifs.length);
13919     }
13920 
13921     @Test
13922     public void testCancelNotificationsFromListener_byKey_Uij() throws Exception {
13923         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13924                 .thenReturn(true);
13925         final NotificationRecord child = generateNotificationRecord(
13926                 mTestNotificationChannel, 3, null, false);
13927         child.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13928         mService.addNotification(child);
13929         String[] keys = {child.getSbn().getKey()};
13930         mService.getBinderService().cancelNotificationsFromListener(null, keys);
13931         waitForIdle();
13932         StatusBarNotification[] notifs =
13933                 mBinderService.getActiveNotifications(child.getSbn().getPackageName());
13934         assertEquals(0, notifs.length);
13935     }
13936 
13937     @Test
13938     public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception {
13939         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
13940                 .thenReturn(true);
13941         final NotificationRecord parent = generateNotificationRecord(
13942                 mTestNotificationChannel, 1, "group", true);
13943         final NotificationRecord child = generateNotificationRecord(
13944                 mTestNotificationChannel, 2, "group", false);
13945         final NotificationRecord child2 = generateNotificationRecord(
13946                 mTestNotificationChannel, 3, "group", false);
13947         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
13948         final NotificationRecord newGroup = generateNotificationRecord(
13949                 mTestNotificationChannel, 4, "group2", false);
13950         mService.addNotification(parent);
13951         mService.addNotification(child);
13952         mService.addNotification(child2);
13953         mService.addNotification(newGroup);
13954         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId());
13955         waitForIdle();
13956         StatusBarNotification[] notifs =
13957                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
13958         assertEquals(0, notifs.length);
13959     }
13960 
13961     @Test
13962     public void testDeleteChannelGroupChecksForUijs() throws Exception {
13963         when(mCompanionMgr.getAssociations(mPkg, UserHandle.getUserId(mUid)))
13964                 .thenReturn(singletonList(mock(AssociationInfo.class)));
13965         CountDownLatch latch = new CountDownLatch(2);
13966         mService.createNotificationChannelGroup(mPkg, mUid,
13967                 new NotificationChannelGroup("group", "group"), true, false);
13968         new Thread(() -> {
13969             NotificationChannel notificationChannel = new NotificationChannel("id", "id",
13970                     NotificationManager.IMPORTANCE_HIGH);
13971             notificationChannel.setGroup("group");
13972             ParceledListSlice<NotificationChannel> pls =
13973                     new ParceledListSlice(ImmutableList.of(notificationChannel));
13974             try {
13975                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
13976             } catch (RemoteException e) {
13977                 throw new RuntimeException(e);
13978             }
13979             latch.countDown();
13980         }).start();
13981         new Thread(() -> {
13982             try {
13983                 synchronized (this) {
13984                     wait(5000);
13985                 }
13986                 mService.createNotificationChannelGroup(mPkg, mUid,
13987                         new NotificationChannelGroup("new", "new group"), true, false);
13988                 NotificationChannel notificationChannel =
13989                         new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
13990                 notificationChannel.setGroup("new");
13991                 ParceledListSlice<NotificationChannel> pls =
13992                         new ParceledListSlice(ImmutableList.of(notificationChannel));
13993                 try {
13994                     mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
13995                     mBinderService.deleteNotificationChannelGroup(mPkg, "group");
13996                 } catch (RemoteException e) {
13997                     throw new RuntimeException(e);
13998                 }
13999             } catch (Exception e) {
14000                 e.printStackTrace();
14001             }
14002             latch.countDown();
14003         }).start();
14004 
14005         latch.await();
14006         verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs(
14007                 anyString(), anyInt(), anyString());
14008     }
14009 
14010     @Test
14011     public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() {
14012         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
14013                 .thenReturn(true);
14014         Notification n = new Notification.Builder(mContext, "").build();
14015         n.flags |= FLAG_USER_INITIATED_JOB;
14016 
14017         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
14018                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14019         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14020 
14021         mService.addEnqueuedNotification(r);
14022 
14023         mInternalService.removeUserInitiatedJobFlagFromNotification(
14024                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
14025 
14026         waitForIdle();
14027 
14028         verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
14029     }
14030 
14031     @Test
14032     public void testRemoveUserInitiatedJobFlagFromNotification_posted() {
14033         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
14034                 .thenReturn(true);
14035         Notification n = new Notification.Builder(mContext, "").build();
14036         n.flags |= FLAG_USER_INITIATED_JOB;
14037 
14038         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
14039                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14040         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14041 
14042         mService.addNotification(r);
14043 
14044         mInternalService.removeUserInitiatedJobFlagFromNotification(
14045                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
14046 
14047         waitForIdle();
14048 
14049         ArgumentCaptor<NotificationRecord> captor =
14050                 ArgumentCaptor.forClass(NotificationRecord.class);
14051         verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
14052 
14053         assertEquals(0, captor.getValue().getNotification().flags);
14054     }
14055 
14056     @Test
14057     public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() {
14058         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
14059             Notification n = new Notification.Builder(mContext, "").build();
14060             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
14061                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
14062             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14063             mService.addEnqueuedNotification(r);
14064         }
14065         Notification n = new Notification.Builder(mContext, "").build();
14066         n.flags |= FLAG_USER_INITIATED_JOB;
14067 
14068         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
14069                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
14070                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14071         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14072 
14073         mService.addEnqueuedNotification(r);
14074 
14075         mInternalService.removeUserInitiatedJobFlagFromNotification(
14076                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
14077 
14078         waitForIdle();
14079 
14080         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
14081                 mService.getNotificationRecordCount());
14082     }
14083 
14084     @Test
14085     public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() {
14086         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
14087                 .thenReturn(true);
14088         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
14089             Notification n = new Notification.Builder(mContext, "").build();
14090             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
14091                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
14092             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14093             mService.addNotification(r);
14094         }
14095         Notification n = new Notification.Builder(mContext, "").build();
14096         n.flags |= FLAG_USER_INITIATED_JOB;
14097 
14098         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
14099                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
14100                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14101         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14102 
14103         mService.addNotification(r);
14104 
14105         mInternalService.removeUserInitiatedJobFlagFromNotification(
14106                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
14107 
14108         waitForIdle();
14109 
14110         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
14111                 mService.getNotificationRecordCount());
14112     }
14113 
14114     @Test
14115     public void testCanPostUijWhenOverLimit() throws RemoteException {
14116         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
14117                 .thenReturn(true);
14118         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
14119             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
14120                     i, null, false).getSbn();
14121             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCanPostUijWhenOverLimit",
14122                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
14123         }
14124 
14125         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
14126         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
14127         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
14128                 "testCanPostUijWhenOverLimit - uij over limit!",
14129                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
14130 
14131         waitForIdle();
14132 
14133         StatusBarNotification[] notifs =
14134                 mBinderService.getActiveNotifications(sbn.getPackageName());
14135         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
14136         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
14137                 mService.getNotificationRecordCount());
14138     }
14139 
14140     @Test
14141     public void testCannotPostNonUijWhenOverLimit() throws RemoteException {
14142         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
14143                 .thenReturn(true);
14144         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
14145             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
14146                     i, null, false).getSbn();
14147             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCannotPostNonUijWhenOverLimit",
14148                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
14149             waitForIdle();
14150         }
14151 
14152         final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
14153                 100, null, false).getSbn();
14154         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
14155         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
14156                 "testCannotPostNonUijWhenOverLimit - uij over limit!",
14157                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
14158 
14159         final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
14160                 101, null, false).getSbn();
14161         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
14162                 "testCannotPostNonUijWhenOverLimit - non uij over limit!",
14163                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
14164 
14165         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
14166                 .thenReturn(false);
14167         final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
14168                 101, null, false).getSbn();
14169         sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB;
14170         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
14171                 "testCannotPostNonUijWhenOverLimit - fake uij over limit!",
14172                 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
14173 
14174         waitForIdle();
14175 
14176         StatusBarNotification[] notifs =
14177                 mBinderService.getActiveNotifications(sbn.getPackageName());
14178         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
14179         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
14180                 mService.getNotificationRecordCount());
14181     }
14182 
14183     @Test
14184     public void fixNotification_withUijFlag_butIsNotUij() throws Exception {
14185         final ApplicationInfo applicationInfo = new ApplicationInfo();
14186         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14187                 .thenReturn(applicationInfo);
14188 
14189         Notification n = new Notification.Builder(mContext, "test")
14190                 .setFlag(FLAG_USER_INITIATED_JOB, true)
14191                 .build();
14192 
14193         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14194         assertFalse(n.isUserInitiatedJob());
14195     }
14196 
14197     @Test
14198     public void enqueue_updatesEnqueueRate() throws Exception {
14199         Notification n = generateNotificationRecord(null).getNotification();
14200 
14201         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
14202         // Don't waitForIdle() here. We want to verify the "intermediate" state.
14203 
14204         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
14205         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
14206         verify(mUsageStats, never()).registerPostedByApp(any());
14207 
14208         waitForIdle();
14209     }
14210 
14211     @Test
14212     public void enqueue_withPost_updatesEnqueueRateAndPost() throws Exception {
14213         Notification n = generateNotificationRecord(null).getNotification();
14214 
14215         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
14216         waitForIdle();
14217 
14218         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
14219         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
14220         verify(mUsageStats).registerPostedByApp(any());
14221     }
14222 
14223     @Test
14224     public void enqueueNew_whenOverEnqueueRate_accepts() throws Exception {
14225         Notification n = generateNotificationRecord(null).getNotification();
14226         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
14227                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f);
14228 
14229         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
14230         waitForIdle();
14231 
14232         assertThat(mService.mNotificationsByKey).hasSize(1);
14233         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
14234         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
14235         verify(mUsageStats).registerPostedByApp(any());
14236     }
14237 
14238     @Test
14239     public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception {
14240         // Post the first version.
14241         Notification original = generateNotificationRecord(null).getNotification();
14242         original.when = System.currentTimeMillis();
14243         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
14244         waitForIdle();
14245         assertThat(mService.mNotificationList).hasSize(1);
14246         assertThat(mService.mNotificationList.get(0).getNotification().when)
14247                 .isEqualTo(original.when);
14248 
14249         reset(mUsageStats);
14250         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
14251                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE - 1f);
14252 
14253         // Post the update.
14254         Notification update = generateNotificationRecord(null).getNotification();
14255         update.when = System.currentTimeMillis() + 111;
14256         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
14257         waitForIdle();
14258 
14259         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
14260         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
14261         verify(mUsageStats, never()).registerPostedByApp(any());
14262         verify(mUsageStats).registerUpdatedByApp(any(), any());
14263         assertThat(mService.mNotificationList).hasSize(1);
14264         assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when);
14265     }
14266 
14267     @Test
14268     public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception {
14269         // Post the first version.
14270         Notification original = generateNotificationRecord(null).getNotification();
14271         original.when = System.currentTimeMillis();
14272         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
14273         waitForIdle();
14274         assertThat(mService.mNotificationList).hasSize(1);
14275         assertThat(mService.mNotificationList.get(0).getNotification().when)
14276                 .isEqualTo(original.when);
14277 
14278         reset(mUsageStats);
14279         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
14280                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f);
14281 
14282         // Post the update.
14283         Notification update = generateNotificationRecord(null).getNotification();
14284         update.when = System.currentTimeMillis() + 111;
14285         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
14286         waitForIdle();
14287 
14288         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
14289         verify(mUsageStats, never()).registerEnqueuedByAppAndAccepted(any());
14290         verify(mUsageStats, never()).registerPostedByApp(any());
14291         verify(mUsageStats, never()).registerUpdatedByApp(any(), any());
14292         assertThat(mService.mNotificationList).hasSize(1);
14293         assertThat(mService.mNotificationList.get(0).getNotification().when)
14294                 .isEqualTo(original.when); // old
14295     }
14296 
14297     @Test
14298     @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN)
14299     public void enqueueNotification_acceptsCorrectToken() throws RemoteException {
14300         Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14301                 .setContentIntent(createPendingIntent("content"))
14302                 .build();
14303         Notification received = parcelAndUnparcel(sent, Notification.CREATOR);
14304         assertThat(received.getAllowlistToken()).isEqualTo(
14305                 NotificationManagerService.ALLOWLIST_TOKEN);
14306 
14307         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
14308                 parcelAndUnparcel(received, Notification.CREATOR), mUserId);
14309         waitForIdle();
14310 
14311         assertThat(mService.mNotificationList).hasSize(1);
14312         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
14313                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
14314     }
14315 
14316     @Test
14317     @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN)
14318     public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException {
14319         Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14320                 .setContentIntent(createPendingIntent("content"))
14321                 .build();
14322         assertThat(receivedWithoutParceling.getAllowlistToken()).isNull();
14323 
14324         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
14325                 parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId);
14326         waitForIdle();
14327 
14328         assertThat(mService.mNotificationList).hasSize(1);
14329         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
14330                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
14331     }
14332 
14333     @Test
14334     @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN)
14335     public void enqueueNotification_rejectsOtherToken() throws RemoteException {
14336         Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14337                 .setContentIntent(createPendingIntent("content"))
14338                 .build();
14339         sent.overrideAllowlistToken(new Binder());
14340         Notification received = parcelAndUnparcel(sent, Notification.CREATOR);
14341         assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken());
14342 
14343         assertThrows(SecurityException.class, () ->
14344                 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
14345                         parcelAndUnparcel(received, Notification.CREATOR), mUserId));
14346         waitForIdle();
14347 
14348         assertThat(mService.mNotificationList).isEmpty();
14349     }
14350 
14351     @Test
14352     @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN)
14353     public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents()
14354             throws RemoteException {
14355         Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14356                 .setContentIntent(createPendingIntent("content"))
14357                 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID)
14358                         .setContentIntent(createPendingIntent("public"))
14359                         .build())
14360                 .build();
14361         sentFromApp.publicVersion.overrideAllowlistToken(new Binder());
14362 
14363         // Instead of using the normal parceling, assume the caller parcels it by hand, including a
14364         // null token in the outer notification (as would be expected, and as is verified by
14365         // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets
14366         // propagated to the PendingIntents.
14367         Parcel parcelSentFromApp = Parcel.obtain();
14368         writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>(
14369                 Lists.newArrayList(sentFromApp.contentIntent,
14370                         sentFromApp.publicVersion.contentIntent)));
14371 
14372         // Use the unparceling as received in enqueueNotificationWithTag()
14373         parcelSentFromApp.setDataPosition(0);
14374         Notification receivedByNms = new Notification(parcelSentFromApp);
14375 
14376         // Verify that all the pendingIntents have the correct token.
14377         assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo(
14378                 NotificationManagerService.ALLOWLIST_TOKEN);
14379         assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo(
14380                 NotificationManagerService.ALLOWLIST_TOKEN);
14381     }
14382 
14383     /**
14384      * Replicates the behavior of {@link Notification#writeToParcel} but excluding the
14385      * "always use the same allowlist token as the root notification" parts.
14386      */
14387     private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif,
14388             ArraySet<PendingIntent> allPendingIntents) {
14389         int flags = 0;
14390         parcel.writeInt(1); // version?
14391 
14392         parcel.writeStrongBinder(notif.getAllowlistToken());
14393         parcel.writeLong(notif.when);
14394         parcel.writeLong(notif.creationTime);
14395         if (notif.getSmallIcon() != null) {
14396             parcel.writeInt(1);
14397             notif.getSmallIcon().writeToParcel(parcel, 0);
14398         } else {
14399             parcel.writeInt(0);
14400         }
14401         parcel.writeInt(notif.number);
14402         if (notif.contentIntent != null) {
14403             parcel.writeInt(1);
14404             notif.contentIntent.writeToParcel(parcel, 0);
14405         } else {
14406             parcel.writeInt(0);
14407         }
14408         if (notif.deleteIntent != null) {
14409             parcel.writeInt(1);
14410             notif.deleteIntent.writeToParcel(parcel, 0);
14411         } else {
14412             parcel.writeInt(0);
14413         }
14414         if (notif.tickerText != null) {
14415             parcel.writeInt(1);
14416             TextUtils.writeToParcel(notif.tickerText, parcel, flags);
14417         } else {
14418             parcel.writeInt(0);
14419         }
14420         if (notif.tickerView != null) {
14421             parcel.writeInt(1);
14422             notif.tickerView.writeToParcel(parcel, 0);
14423         } else {
14424             parcel.writeInt(0);
14425         }
14426         if (notif.contentView != null) {
14427             parcel.writeInt(1);
14428             notif.contentView.writeToParcel(parcel, 0);
14429         } else {
14430             parcel.writeInt(0);
14431         }
14432         if (notif.getLargeIcon() != null) {
14433             parcel.writeInt(1);
14434             notif.getLargeIcon().writeToParcel(parcel, 0);
14435         } else {
14436             parcel.writeInt(0);
14437         }
14438 
14439         parcel.writeInt(notif.defaults);
14440         parcel.writeInt(notif.flags);
14441 
14442         if (notif.sound != null) {
14443             parcel.writeInt(1);
14444             notif.sound.writeToParcel(parcel, 0);
14445         } else {
14446             parcel.writeInt(0);
14447         }
14448         parcel.writeInt(notif.audioStreamType);
14449 
14450         if (notif.audioAttributes != null) {
14451             parcel.writeInt(1);
14452             notif.audioAttributes.writeToParcel(parcel, 0);
14453         } else {
14454             parcel.writeInt(0);
14455         }
14456 
14457         parcel.writeLongArray(notif.vibrate);
14458         parcel.writeInt(notif.ledARGB);
14459         parcel.writeInt(notif.ledOnMS);
14460         parcel.writeInt(notif.ledOffMS);
14461         parcel.writeInt(notif.iconLevel);
14462 
14463         if (notif.fullScreenIntent != null) {
14464             parcel.writeInt(1);
14465             notif.fullScreenIntent.writeToParcel(parcel, 0);
14466         } else {
14467             parcel.writeInt(0);
14468         }
14469 
14470         parcel.writeInt(notif.priority);
14471 
14472         parcel.writeString8(notif.category);
14473 
14474         parcel.writeString8(notif.getGroup());
14475 
14476         parcel.writeString8(notif.getSortKey());
14477 
14478         parcel.writeBundle(notif.extras); // null ok
14479 
14480         parcel.writeTypedArray(notif.actions, 0); // null ok
14481 
14482         if (notif.bigContentView != null) {
14483             parcel.writeInt(1);
14484             notif.bigContentView.writeToParcel(parcel, 0);
14485         } else {
14486             parcel.writeInt(0);
14487         }
14488 
14489         if (notif.headsUpContentView != null) {
14490             parcel.writeInt(1);
14491             notif.headsUpContentView.writeToParcel(parcel, 0);
14492         } else {
14493             parcel.writeInt(0);
14494         }
14495 
14496         parcel.writeInt(notif.visibility);
14497 
14498         if (notif.publicVersion != null) {
14499             parcel.writeInt(1);
14500             writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>());
14501         } else {
14502             parcel.writeInt(0);
14503         }
14504 
14505         parcel.writeInt(notif.color);
14506 
14507         if (notif.getChannelId() != null) {
14508             parcel.writeInt(1);
14509             parcel.writeString8(notif.getChannelId());
14510         } else {
14511             parcel.writeInt(0);
14512         }
14513         parcel.writeLong(notif.getTimeoutAfter());
14514 
14515         if (notif.getShortcutId() != null) {
14516             parcel.writeInt(1);
14517             parcel.writeString8(notif.getShortcutId());
14518         } else {
14519             parcel.writeInt(0);
14520         }
14521 
14522         if (notif.getLocusId() != null) {
14523             parcel.writeInt(1);
14524             notif.getLocusId().writeToParcel(parcel, 0);
14525         } else {
14526             parcel.writeInt(0);
14527         }
14528 
14529         parcel.writeInt(notif.getBadgeIconType());
14530 
14531         if (notif.getSettingsText() != null) {
14532             parcel.writeInt(1);
14533             TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags);
14534         } else {
14535             parcel.writeInt(0);
14536         }
14537 
14538         parcel.writeInt(notif.getGroupAlertBehavior());
14539 
14540         if (notif.getBubbleMetadata() != null) {
14541             parcel.writeInt(1);
14542             notif.getBubbleMetadata().writeToParcel(parcel, 0);
14543         } else {
14544             parcel.writeInt(0);
14545         }
14546 
14547         parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions());
14548 
14549         parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior
14550 
14551         // mUsesStandardHeader is not written because it should be recomputed in listeners
14552 
14553         parcel.writeArraySet(allPendingIntents);
14554     }
14555 
14556     @Test
14557     @SuppressWarnings("unchecked")
14558     @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN)
14559     public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException {
14560         Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14561                 .setContentIntent(createPendingIntent("content"))
14562                 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID)
14563                         .setContentIntent(createPendingIntent("public"))
14564                         .build())
14565                 .extend(new Notification.WearableExtender()
14566                         .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID)
14567                                 .setContentIntent(createPendingIntent("wearPage"))
14568                                 .build()))
14569                 .build();
14570         // Binder transition: app -> NMS
14571         Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR);
14572         assertThat(receivedByNms.getAllowlistToken()).isEqualTo(
14573                 NotificationManagerService.ALLOWLIST_TOKEN);
14574         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
14575                 parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId);
14576         waitForIdle();
14577         assertThat(mService.mNotificationList).hasSize(1);
14578         Notification posted = mService.mNotificationList.get(0).getNotification();
14579         assertThat(posted.getAllowlistToken()).isEqualTo(
14580                 NotificationManagerService.ALLOWLIST_TOKEN);
14581         assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo(
14582                 NotificationManagerService.ALLOWLIST_TOKEN);
14583 
14584         ParceledListSlice<StatusBarNotification> listSentFromNms =
14585                 mBinderService.getAppActiveNotifications(mPkg, mUserId);
14586         // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it
14587         // (having a different one would produce the same effect; the relevant thing is to not let
14588         // out ALLOWLIST_TOKEN).
14589         // Note: for other tests, this is restored by constructing TestableNMS in setup().
14590         Notification.processAllowlistToken = null;
14591         ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel(
14592                 listSentFromNms, ParceledListSlice.CREATOR);
14593         Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification();
14594 
14595         assertThat(gottenBackByApp.getAllowlistToken()).isNull();
14596         assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull();
14597         assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull();
14598         assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull();
14599         assertThat(new Notification.WearableExtender(gottenBackByApp).getPages()
14600                 .get(0).getAllowlistToken()).isNull();
14601         assertThat(new Notification.WearableExtender(gottenBackByApp).getPages()
14602                 .get(0).contentIntent.getWhitelistToken()).isNull();
14603     }
14604 
14605     @Test
14606     public void enqueueNotification_allowlistsPendingIntents() throws RemoteException {
14607         PendingIntent contentIntent = createPendingIntent("content");
14608         PendingIntent actionIntent1 = createPendingIntent("action1");
14609         PendingIntent actionIntent2 = createPendingIntent("action2");
14610         Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14611                 .setContentIntent(contentIntent)
14612                 .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build())
14613                 .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build())
14614                 .build();
14615 
14616         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
14617                 parcelAndUnparcel(n, Notification.CREATOR), mUserId);
14618 
14619         verify(mAmi, times(3)).setPendingIntentAllowlistDuration(
14620                 any(), any(), anyLong(),
14621                 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
14622                 eq(REASON_NOTIFICATION_SERVICE), any());
14623         verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(),
14624                 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
14625         contentIntent.cancel();
14626         actionIntent2.cancel();
14627         actionIntent1.cancel();
14628     }
14629 
14630     @Test
14631     public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion()
14632             throws RemoteException {
14633         PendingIntent contentIntent = createPendingIntent("content");
14634         PendingIntent actionIntent = createPendingIntent("action");
14635         PendingIntent publicContentIntent = createPendingIntent("publicContent");
14636         PendingIntent publicActionIntent = createPendingIntent("publicAction");
14637         Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID)
14638                 .setContentIntent(contentIntent)
14639                 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
14640                 .setPublicVersion(new Notification.Builder(mContext, "channel")
14641                         .setContentIntent(publicContentIntent)
14642                         .addAction(new Notification.Action.Builder(
14643                                 null, "publicAction", publicActionIntent).build())
14644                         .build())
14645                 .build();
14646 
14647         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
14648                 parcelAndUnparcel(source, Notification.CREATOR), mUserId);
14649 
14650         verify(mAmi, times(4)).setPendingIntentAllowlistDuration(
14651                 any(), any(), anyLong(),
14652                 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
14653                 eq(REASON_NOTIFICATION_SERVICE), any());
14654         verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(),
14655                 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
14656         contentIntent.cancel();
14657         publicContentIntent.cancel();
14658         actionIntent.cancel();
14659         publicActionIntent.cancel();
14660     }
14661 
14662     @Test
14663     @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
14664     public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() {
14665         mService.mZenModeHelper = mock(ZenModeHelper.class);
14666         mService.setPreferencesHelper(mPreferencesHelper);
14667 
14668         UserInfo prevUser = new UserInfo();
14669         prevUser.id = 10;
14670         UserInfo newUser = new UserInfo();
14671         newUser.id = 20;
14672 
14673         mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser));
14674 
14675         InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
14676         inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
14677         inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
14678         inOrder.verifyNoMoreInteractions();
14679     }
14680 
14681     @Test
14682     @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
14683     public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() {
14684         Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
14685         intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
14686         mService.mZenModeHelper = mock(ZenModeHelper.class);
14687         mService.setPreferencesHelper(mPreferencesHelper);
14688 
14689         mUserIntentReceiver.onReceive(mContext, intent);
14690 
14691         InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
14692         inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
14693         inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
14694         inOrder.verifyNoMoreInteractions();
14695     }
14696 
14697     @Test
14698     public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception {
14699         final String notReal = "NOT REAL";
14700         final var checker = mService.permissionChecker;
14701 
14702         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
14703                 PackageManager.NameNotFoundException.class);
14704 
14705         assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse();
14706         verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt());
14707         verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean());
14708         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt());
14709         verify(mListeners, never()).isComponentEnabledForPackage(any());
14710         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
14711     }
14712 
14713     @Test
14714     public void isNotificationPolicyAccessGranted_hasPermission() throws Exception {
14715         final String packageName = "target";
14716         final int uid = 123;
14717         final var checker = mService.permissionChecker;
14718 
14719         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
14720         when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true))
14721                 .thenReturn(PackageManager.PERMISSION_GRANTED);
14722 
14723         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
14724         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
14725         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
14726         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt());
14727         verify(mListeners, never()).isComponentEnabledForPackage(any());
14728         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
14729     }
14730 
14731     @Test
14732     public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception {
14733         final String packageName = "target";
14734         final int uid = 123;
14735         final var checker = mService.permissionChecker;
14736 
14737         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
14738         when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt()))
14739                 .thenReturn(true);
14740 
14741         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
14742         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
14743         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
14744         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
14745         verify(mListeners, never()).isComponentEnabledForPackage(any());
14746         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
14747     }
14748 
14749     @Test
14750     public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception {
14751         final String packageName = "target";
14752         final int uid = 123;
14753         final var checker = mService.permissionChecker;
14754 
14755         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
14756         when(mListeners.isComponentEnabledForPackage(packageName)).thenReturn(true);
14757 
14758         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
14759         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
14760         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
14761         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
14762         verify(mListeners).isComponentEnabledForPackage(packageName);
14763         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
14764     }
14765 
14766     @Test
14767     public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception {
14768         final String packageName = "target";
14769         final int uid = 123;
14770         final var checker = mService.permissionChecker;
14771 
14772         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
14773         when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true);
14774 
14775         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
14776         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
14777         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
14778         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
14779         verify(mListeners).isComponentEnabledForPackage(packageName);
14780         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
14781     }
14782 
14783     /**
14784      * b/292163859
14785      */
14786     @Test
14787     public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception {
14788         final String packageName = "target";
14789         final int uid = 123;
14790         final int callingUid = Binder.getCallingUid();
14791         final var checker = mService.permissionChecker;
14792 
14793         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
14794         when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true);
14795 
14796         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
14797         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
14798         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
14799         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
14800         verify(mListeners).isComponentEnabledForPackage(packageName);
14801         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
14802         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid);
14803     }
14804 
14805     @Test
14806     public void isNotificationPolicyAccessGranted_notGranted() throws Exception {
14807         final String packageName = "target";
14808         final int uid = 123;
14809         final var checker = mService.permissionChecker;
14810 
14811         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
14812 
14813         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
14814         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
14815         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
14816         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
14817         verify(mListeners).isComponentEnabledForPackage(packageName);
14818         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
14819     }
14820 
14821     @Test
14822     public void testResetDefaultDnd() {
14823         TestableNotificationManagerService service = spy(mService);
14824         UserInfo user = new UserInfo(0, "owner", 0);
14825         when(mUm.getAliveUsers()).thenReturn(List.of(user));
14826         doReturn(false).when(service).isDNDMigrationDone(anyInt());
14827 
14828         service.resetDefaultDndIfNecessary();
14829 
14830         verify(mConditionProviders, times(1)).removeDefaultFromConfig(user.id);
14831         verify(mConditionProviders, times(1)).resetDefaultFromConfig();
14832         verify(service, times(1)).allowDndPackages(user.id);
14833         verify(service, times(1)).setDNDMigrationDone(user.id);
14834     }
14835 
14836     @Test
14837     public void testProfileUnavailableIntent() throws RemoteException {
14838         mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE,
14839                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
14840         simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE);
14841         verify(mWorkerHandler).post(any(Runnable.class));
14842         verify(mSnoozeHelper).clearData(anyInt());
14843     }
14844 
14845 
14846     @Test
14847     public void testManagedProfileUnavailableIntent() throws RemoteException {
14848         mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE,
14849                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
14850         simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
14851         verify(mWorkerHandler).post(any(Runnable.class));
14852         verify(mSnoozeHelper).clearData(anyInt());
14853     }
14854 
14855     @Test
14856     @EnableFlags(android.app.Flags.FLAG_MODES_API)
14857     public void setDeviceEffectsApplier_succeeds() throws Exception {
14858         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
14859 
14860         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
14861         // No exception!
14862     }
14863 
14864     @Test
14865     @EnableFlags(android.app.Flags.FLAG_MODES_API)
14866     public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
14867         initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
14868 
14869         assertThrows(IllegalStateException.class, () ->
14870                 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
14871     }
14872 
14873     @Test
14874     @EnableFlags(android.app.Flags.FLAG_MODES_API)
14875     public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
14876         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
14877 
14878         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
14879         assertThrows(IllegalStateException.class, () ->
14880                 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
14881     }
14882 
14883     @Test
14884     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14885     public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
14886         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
14887         mService.setCallerIsNormalPackage();
14888         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
14889         mService.mZenModeHelper = zenHelper;
14890         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
14891                 .thenReturn(true);
14892 
14893         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
14894         mBinderService.setNotificationPolicy("package", policy, false);
14895 
14896         verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(eq("package"), anyInt(), eq(policy));
14897     }
14898 
14899     @Test
14900     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14901     public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException {
14902         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
14903         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
14904         mService.mZenModeHelper = zenModeHelper;
14905         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
14906                 .thenReturn(true);
14907         mService.isSystemUid = true;
14908 
14909         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
14910         mBinderService.setNotificationPolicy("package", policy, false);
14911 
14912         verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt());
14913     }
14914 
14915     @Test
14916     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14917     public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy()
14918             throws RemoteException {
14919         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
14920                 AssociationRequest.DEVICE_PROFILE_WATCH, true);
14921     }
14922 
14923     @Test
14924     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14925     public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy()
14926             throws RemoteException {
14927         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
14928                 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
14929     }
14930 
14931     @Test
14932     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14933     public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy()
14934             throws RemoteException {
14935         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
14936                 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
14937     }
14938 
14939     private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
14940             @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
14941             throws RemoteException {
14942         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
14943         mService.setCallerIsNormalPackage();
14944         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
14945         mService.mZenModeHelper = zenModeHelper;
14946         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
14947                 .thenReturn(true);
14948         when(mCompanionMgr.getAssociations(anyString(), anyInt()))
14949                 .thenReturn(ImmutableList.of(
14950                         new AssociationInfo.Builder(1, mUserId, "package")
14951                                 .setDisplayName("My connected device")
14952                                 .setDeviceProfile(deviceProfile)
14953                                 .build()));
14954 
14955         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
14956         mBinderService.setNotificationPolicy("package", policy, false);
14957 
14958         if (canSetGlobalPolicy) {
14959             verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt());
14960         } else {
14961             verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(anyString(), anyInt(),
14962                     eq(policy));
14963         }
14964     }
14965 
14966     @Test
14967     @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14968     public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException {
14969         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
14970         mService.setCallerIsNormalPackage();
14971         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
14972         mService.mZenModeHelper = zenModeHelper;
14973         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
14974                 .thenReturn(true);
14975 
14976         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
14977         mBinderService.setNotificationPolicy("package", policy, false);
14978 
14979         verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt());
14980     }
14981 
14982     @Test
14983     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14984     public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException {
14985         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
14986         mService.setCallerIsNormalPackage();
14987         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
14988         mService.mZenModeHelper = zenHelper;
14989         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
14990                 .thenReturn(true);
14991 
14992         mBinderService.getNotificationPolicy("package");
14993 
14994         verify(zenHelper).getNotificationPolicyFromImplicitZenRule(eq("package"));
14995     }
14996 
14997     @Test
14998     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
14999     public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException {
15000         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
15001         mService.setCallerIsNormalPackage();
15002         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
15003         mService.mZenModeHelper = zenHelper;
15004         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
15005                 .thenReturn(true);
15006 
15007         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
15008 
15009         verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(eq("package"), anyInt(),
15010                 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
15011     }
15012 
15013     @Test
15014     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15015     public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException {
15016         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
15017         mService.setCallerIsNormalPackage();
15018         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
15019         mService.mZenModeHelper = zenModeHelper;
15020         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
15021                 .thenReturn(true);
15022         mService.isSystemUid = true;
15023 
15024         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
15025 
15026         verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
15027                 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), eq("package"),
15028                 anyInt());
15029     }
15030 
15031     @Test
15032     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15033     public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException {
15034         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
15035                 AssociationRequest.DEVICE_PROFILE_WATCH, true);
15036     }
15037 
15038     @Test
15039     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15040     public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException {
15041         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
15042                 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
15043     }
15044 
15045     @Test
15046     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15047     public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen()
15048             throws RemoteException {
15049         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
15050                 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
15051     }
15052 
15053     private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
15054             @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
15055             throws RemoteException {
15056         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
15057         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
15058         mService.mZenModeHelper = zenModeHelper;
15059         mService.setCallerIsNormalPackage();
15060         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
15061                 .thenReturn(true);
15062         when(mCompanionMgr.getAssociations(anyString(), anyInt()))
15063                 .thenReturn(ImmutableList.of(
15064                         new AssociationInfo.Builder(1, mUserId, "package")
15065                                 .setDisplayName("My connected device")
15066                                 .setDeviceProfile(deviceProfile)
15067                                 .build()));
15068 
15069         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
15070 
15071         if (canSetGlobalPolicy) {
15072             verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
15073                     eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyString(), eq("package"), anyInt());
15074         } else {
15075             verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(anyString(), anyInt(),
15076                     eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
15077         }
15078     }
15079 
15080     @Test
15081     @EnableFlags(android.app.Flags.FLAG_MODES_API)
15082     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15083     public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen()
15084             throws Exception {
15085         mService.setCallerIsNormalPackage();
15086         mService.mZenModeHelper = mock(ZenModeHelper.class);
15087         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
15088         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
15089         info.component = new ComponentName("pkg", "cls");
15090 
15091         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
15092                 INTERRUPTION_FILTER_PRIORITY);
15093 
15094         verify(mService.mZenModeHelper).applyGlobalZenModeAsImplicitZenRule(eq("pkg"), eq(mUid),
15095                 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
15096     }
15097 
15098     @Test
15099     @EnableFlags(android.app.Flags.FLAG_MODES_API)
15100     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15101     public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen()
15102             throws Exception {
15103         mService.isSystemUid = true;
15104         mService.mZenModeHelper = mock(ZenModeHelper.class);
15105         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
15106         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
15107         info.component = new ComponentName("pkg", "cls");
15108 
15109         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
15110                 INTERRUPTION_FILTER_PRIORITY);
15111 
15112         verify(mService.mZenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS),
15113                 eq(null), eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(),
15114                 eq("pkg"), eq(mUid));
15115     }
15116 
15117     @Test
15118     @DisableFlags(android.app.Flags.FLAG_MODES_API)
15119     public void requestInterruptionFilterFromListener_flagOff_callsRequestFromListener()
15120             throws Exception {
15121         mService.setCallerIsNormalPackage();
15122         mService.mZenModeHelper = mock(ZenModeHelper.class);
15123         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
15124         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
15125         info.component = new ComponentName("pkg", "cls");
15126 
15127         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
15128                 INTERRUPTION_FILTER_PRIORITY);
15129 
15130         verify(mService.mZenModeHelper).requestFromListener(eq(info.component),
15131                 eq(INTERRUPTION_FILTER_PRIORITY), eq(mUid), /* fromSystemOrSystemUi= */ eq(false));
15132     }
15133 
15134     @Test
15135     @EnableFlags(android.app.Flags.FLAG_MODES_API)
15136     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15137     public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception {
15138         setUpRealZenTest();
15139         mService.setCallerIsNormalPackage();
15140         assertThat(mBinderService.getAutomaticZenRules()).isEmpty();
15141 
15142         // Create an implicit zen rule by calling setNotificationPolicy from an app.
15143         mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false);
15144         assertThat(mBinderService.getAutomaticZenRules()).hasSize(1);
15145         Map.Entry<String, AutomaticZenRule> rule = getOnlyElement(
15146                 mBinderService.getAutomaticZenRules().entrySet());
15147         assertThat(rule.getValue().getOwner()).isNull();
15148         assertThat(rule.getValue().getConfigurationActivity()).isNull();
15149 
15150         // Now try to update said rule (e.g. disable it). Should fail.
15151         // We also validate the exception message because NPE could be thrown by all sorts of test
15152         // issues (e.g. misconfigured mocks).
15153         rule.getValue().setEnabled(false);
15154         NullPointerException e = assertThrows(NullPointerException.class,
15155                 () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false));
15156         assertThat(e.getMessage()).isEqualTo(
15157                 "Rule must have a ConditionProviderService and/or configuration activity");
15158     }
15159 
15160     @Test
15161     @EnableFlags(android.app.Flags.FLAG_MODES_API)
15162     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
15163     public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception {
15164         setUpRealZenTest();
15165         mService.setCallerIsNormalPackage();
15166         assertThat(mBinderService.getAutomaticZenRules()).isEmpty();
15167 
15168         // Create an implicit zen rule by calling setNotificationPolicy from an app.
15169         mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false);
15170         assertThat(mBinderService.getAutomaticZenRules()).hasSize(1);
15171         Map.Entry<String, AutomaticZenRule> rule = getOnlyElement(
15172                 mBinderService.getAutomaticZenRules().entrySet());
15173         assertThat(rule.getValue().getOwner()).isNull();
15174         assertThat(rule.getValue().getConfigurationActivity()).isNull();
15175 
15176         // Now update said rule from Settings (e.g. disable it). Should work!
15177         mService.isSystemUid = true;
15178         rule.getValue().setEnabled(false);
15179         mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false);
15180 
15181         Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement(
15182                 mBinderService.getAutomaticZenRules().entrySet());
15183         assertThat(updatedRule.getValue().isEnabled()).isFalse();
15184     }
15185 
15186     /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */
15187     private void setUpRealZenTest() throws Exception {
15188         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
15189                 .thenReturn(true);
15190 
15191         int iconResId = 79;
15192         String iconResName = "icon_79";
15193         String pkg = mContext.getPackageName();
15194         ApplicationInfo appInfoSpy = spy(new ApplicationInfo());
15195         appInfoSpy.icon = iconResId;
15196         when(appInfoSpy.loadLabel(any())).thenReturn("Test App");
15197         when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy);
15198 
15199         when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName);
15200         when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId);
15201         when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources);
15202     }
15203 
15204     @Test
15205     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
15206     public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception {
15207         Notification n = new Notification.Builder(mContext, "test")
15208                 .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true)
15209                 .build();
15210 
15211         assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
15212 
15213         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15214 
15215         assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
15216     }
15217 
15218     @Test
15219     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne()
15220             throws RemoteException {
15221         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
15222                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
15223 
15224         // Create recent notification.
15225         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
15226                 System.currentTimeMillis());
15227         mService.addNotification(nr1);
15228 
15229         // Create old notification.
15230         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
15231                 System.currentTimeMillis() - 60000);
15232         mService.addNotification(nr2);
15233 
15234         // Cancel specific notifications via listener.
15235         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
15236         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15237         waitForIdle();
15238 
15239         // Notifications should not be active anymore.
15240         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
15241         assertThat(notifications).isEmpty();
15242         assertEquals(0, mService.getNotificationRecordCount());
15243         // Ensure cancel event is logged.
15244         verify(mAppOpsManager).noteOpNoThrow(
15245                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null);
15246     }
15247 
15248     @Test
15249     public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException {
15250         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
15251                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
15252 
15253         // Create old notifications.
15254         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
15255                 System.currentTimeMillis() - 60000);
15256         mService.addNotification(nr1);
15257 
15258         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
15259                 System.currentTimeMillis() - 60000);
15260         mService.addNotification(nr2);
15261 
15262         // Cancel specific notifications via listener.
15263         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
15264         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15265         waitForIdle();
15266 
15267         // Notifications should not be active anymore.
15268         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
15269         assertThat(notifications).isEmpty();
15270         assertEquals(0, mService.getNotificationRecordCount());
15271         // Ensure cancel event is not logged.
15272         verify(mAppOpsManager, never()).noteOpNoThrow(
15273                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
15274                 any(), any());
15275     }
15276 
15277     @Test
15278     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled()
15279             throws RemoteException {
15280         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
15281                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
15282 
15283         // Create recent notification.
15284         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
15285                 System.currentTimeMillis());
15286         mService.addNotification(nr1);
15287 
15288         // Create old notification.
15289         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
15290                 System.currentTimeMillis() - 60000);
15291         mService.addNotification(nr2);
15292 
15293         // Cancel specific notifications via listener.
15294         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
15295         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15296         waitForIdle();
15297 
15298         // Notifications should not be active anymore.
15299         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
15300         assertThat(notifications).isEmpty();
15301         assertEquals(0, mService.getNotificationRecordCount());
15302         // Ensure cancel event is not logged due to flag being disabled.
15303         verify(mAppOpsManager, never()).noteOpNoThrow(
15304                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
15305                 any(), any());
15306     }
15307 
15308     @Test
15309     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll()
15310             throws RemoteException {
15311         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
15312                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
15313 
15314         // Create recent notification.
15315         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
15316                 System.currentTimeMillis());
15317         mService.addNotification(nr1);
15318 
15319         // Create old notification.
15320         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
15321                 System.currentTimeMillis() - 60000);
15322         mService.addNotification(nr2);
15323 
15324         // Cancel all notifications via listener.
15325         mService.getBinderService().cancelNotificationsFromListener(null, null);
15326         waitForIdle();
15327 
15328         // Notifications should not be active anymore.
15329         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
15330         assertThat(notifications).isEmpty();
15331         assertEquals(0, mService.getNotificationRecordCount());
15332         // Ensure cancel event is logged.
15333         verify(mAppOpsManager).noteOpNoThrow(
15334                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null);
15335     }
15336 
15337     @Test
15338     public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException {
15339         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
15340                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
15341 
15342         // Create old notifications.
15343         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
15344                 System.currentTimeMillis() - 60000);
15345         mService.addNotification(nr1);
15346 
15347         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
15348                 System.currentTimeMillis() - 60000);
15349         mService.addNotification(nr2);
15350 
15351         // Cancel all notifications via listener.
15352         mService.getBinderService().cancelNotificationsFromListener(null, null);
15353         waitForIdle();
15354 
15355         // Notifications should not be active anymore.
15356         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
15357         assertThat(notifications).isEmpty();
15358         assertEquals(0, mService.getNotificationRecordCount());
15359         // Ensure cancel event is not logged.
15360         verify(mAppOpsManager, never()).noteOpNoThrow(
15361                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
15362                 any(), any());
15363     }
15364 
15365     @Test
15366     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled()
15367             throws RemoteException {
15368         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
15369                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
15370 
15371         // Create recent notification.
15372         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
15373                 System.currentTimeMillis());
15374         mService.addNotification(nr1);
15375 
15376         // Create old notification.
15377         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
15378                 System.currentTimeMillis() - 60000);
15379         mService.addNotification(nr2);
15380 
15381         // Cancel all notifications via listener.
15382         mService.getBinderService().cancelNotificationsFromListener(null, null);
15383         waitForIdle();
15384 
15385         // Notifications should not be active anymore.
15386         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
15387         assertThat(notifications).isEmpty();
15388         assertEquals(0, mService.getNotificationRecordCount());
15389         // Ensure cancel event is not logged due to flag being disabled.
15390         verify(mAppOpsManager, never()).noteOpNoThrow(
15391                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
15392                 any(), any());
15393     }
15394 
15395     @Test
15396     @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS)
15397     public void testSetPrivateNotificationsAllowed() throws Exception {
15398         when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS))
15399                 .thenReturn(PERMISSION_GRANTED);
15400         mBinderService.setPrivateNotificationsAllowed(false);
15401         Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED)
15402                 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false);
15403         ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class);
15404         verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE));
15405 
15406         assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction());
15407         assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true));
15408         assertFalse(mBinderService.getPrivateNotificationsAllowed());
15409     }
15410 
15411     @Test
15412     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
15413     public void testCallNotificationListener_NotifiedOnPostCallStyle() throws Exception {
15414         ICallNotificationEventCallback listener = mock(
15415                 ICallNotificationEventCallback.class);
15416         when(listener.asBinder()).thenReturn(mock(IBinder.class));
15417         mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.CURRENT, listener);
15418         waitForIdle();
15419 
15420         final UserHandle userHandle = UserHandle.getUserHandleForUid(mUid);
15421         final NotificationRecord r = createAndPostCallStyleNotification(mPkg, userHandle,
15422                 "testCallNotificationListener_NotifiedOnPostCallStyle");
15423 
15424         verify(listener, times(1)).onCallNotificationPosted(mPkg, userHandle);
15425 
15426         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
15427                 r.getSbn().getUserId());
15428         waitForIdle();
15429 
15430         verify(listener, times(1)).onCallNotificationRemoved(mPkg, userHandle);
15431     }
15432 
15433     @Test
15434     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
15435     public void testCallNotificationListener_NotNotifiedOnPostNonCallStyle() throws Exception {
15436         ICallNotificationEventCallback listener = mock(
15437                 ICallNotificationEventCallback.class);
15438         when(listener.asBinder()).thenReturn(mock(IBinder.class));
15439         mBinderService.registerCallNotificationEventListener(mPkg,
15440                 UserHandle.getUserHandleForUid(mUid), listener);
15441         waitForIdle();
15442 
15443         Notification.Builder nb = new Notification.Builder(mContext,
15444                 mTestNotificationChannel.getId()).setSmallIcon(android.R.drawable.sym_def_app_icon);
15445         final NotificationRecord r = createAndPostNotification(nb,
15446                 "testCallNotificationListener_NotNotifiedOnPostNonCallStyle");
15447 
15448         verify(listener, never()).onCallNotificationPosted(anyString(), any());
15449 
15450         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
15451                 r.getSbn().getUserId());
15452         waitForIdle();
15453 
15454         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
15455     }
15456 
15457     @Test
15458     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
15459     public void testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId()
15460             throws Exception {
15461         ICallNotificationEventCallback listener = mock(
15462                 ICallNotificationEventCallback.class);
15463         when(listener.asBinder()).thenReturn(mock(IBinder.class));
15464         mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.ALL, listener);
15465         waitForIdle();
15466 
15467         final UserHandle otherUser = UserHandle.of(2);
15468         final NotificationRecord r = createAndPostCallStyleNotification(mPkg,
15469                 otherUser, "testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId");
15470 
15471         verify(listener, times(1)).onCallNotificationPosted(mPkg, otherUser);
15472 
15473         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
15474                 r.getSbn().getUserId());
15475         waitForIdle();
15476 
15477         verify(listener, times(1)).onCallNotificationRemoved(mPkg, otherUser);
15478     }
15479 
15480     @Test
15481     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
15482     public void testCallNotificationListener_differentPackage_notNotified() throws Exception {
15483         final String packageName = "package";
15484         ICallNotificationEventCallback listener = mock(
15485                 ICallNotificationEventCallback.class);
15486         when(listener.asBinder()).thenReturn(mock(IBinder.class));
15487         mBinderService.registerCallNotificationEventListener(packageName, UserHandle.ALL, listener);
15488         waitForIdle();
15489 
15490         final NotificationRecord r = createAndPostCallStyleNotification(mPkg,
15491                 UserHandle.of(mUserId),
15492                 "testCallNotificationListener_differentPackage_notNotified");
15493 
15494         verify(listener, never()).onCallNotificationPosted(anyString(), any());
15495 
15496         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
15497                 r.getSbn().getUserId());
15498         waitForIdle();
15499 
15500         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
15501     }
15502 
15503     @Test
15504     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
15505     public void rankingTime_newNotification_noisy_matchesSbn() throws Exception {
15506         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId);
15507 
15508         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15509                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
15510         waitForIdle();
15511 
15512         NotificationRecord posted = mService.mNotificationList.get(0);
15513         long originalPostTime = posted.getSbn().getPostTime();
15514         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
15515     }
15516 
15517     @Test
15518     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
15519     public void rankingTime_newNotification_silent_matchesSbn() throws Exception {
15520         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
15521         NotificationRecord nr = generateNotificationRecord(low, mUserId);
15522 
15523         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15524                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
15525         waitForIdle();
15526 
15527         NotificationRecord posted = mService.mNotificationList.get(0);
15528         long originalPostTime = posted.getSbn().getPostTime();
15529         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
15530     }
15531 
15532     @Test
15533     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
15534     public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception {
15535         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
15536         NotificationRecord nr = generateNotificationRecord(low, mUserId);
15537 
15538         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15539                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
15540         waitForIdle();
15541         NotificationRecord posted = mService.mNotificationList.get(0);
15542         long originalPostTime = posted.getSbn().getPostTime();
15543         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
15544 
15545         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15546                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
15547         waitForIdle();
15548         assertThat(mService.mNotificationList.get(0).getRankingTimeMs())
15549                 .isEqualTo(originalPostTime);
15550     }
15551 
15552     @Test
15553     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
15554     public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception {
15555         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
15556         NotificationRecord nr = generateNotificationRecord(low, 0, mUserId);
15557 
15558         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15559                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
15560         waitForIdle();
15561         NotificationRecord posted = mService.mNotificationList.get(0);
15562         long originalPostTime = posted.getSbn().getPostTime();
15563         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
15564 
15565         NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar");
15566         // no attention helper mocked behavior needed because this does not make noise
15567         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15568                 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
15569                 nrUpdate.getSbn().getUserId());
15570         waitForIdle();
15571 
15572         posted = mService.mNotificationList.get(0);
15573         assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
15574         assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
15575     }
15576 
15577     @Test
15578     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
15579     public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception {
15580         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
15581         NotificationRecord nr = generateNotificationRecord(low, mUserId);
15582 
15583         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15584                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
15585         waitForIdle();
15586         NotificationRecord posted = mService.mNotificationList.get(0);
15587         long originalPostTime = posted.getSbn().getPostTime();
15588         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
15589 
15590         NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId);
15591         when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() {
15592             public Object answer(InvocationOnMock invocation) {
15593                 Object[] args = invocation.getArguments();
15594                 ((NotificationRecord) args[0]).resetRankingTime();
15595                 return 2; // beep
15596             }
15597         });
15598         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
15599                 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
15600                 nrUpdate.getSbn().getUserId());
15601         waitForIdle();
15602         posted = mService.mNotificationList.get(0);
15603         assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
15604         assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
15605     }
15606 
15607     @Test
15608     @EnableFlags(android.app.Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA)
15609     public void testRestrictAudioAttributes_listenersGetCorrectAttributes() throws Exception {
15610         NotificationChannel sound = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
15611         sound.setSound(Uri.EMPTY, new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build());
15612         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(
15613                 Arrays.asList(sound)));
15614 
15615         Notification n = new Notification.Builder(mContext, "a")
15616                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15617                 .build();
15618         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
15619                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15620 
15621         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
15622                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15623         waitForIdle();
15624 
15625         ArgumentCaptor<NotificationRecord> captor =
15626                 ArgumentCaptor.forClass(NotificationRecord.class);
15627         verify(mListeners, times(1)).prepareNotifyPostedLocked(
15628                 captor.capture(), any(), anyBoolean());
15629 
15630         assertThat(captor.getValue().getChannel().getAudioAttributes().getUsage())
15631                 .isEqualTo(USAGE_NOTIFICATION);
15632     }
15633 
15634     @Test
15635     @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
15636     public void testFixNotification_missingTtl() throws Exception {
15637         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15638                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15639                 .build();
15640 
15641         mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
15642 
15643         assertThat(n.getTimeoutAfter()).isEqualTo(NOTIFICATION_TTL);
15644     }
15645 
15646     @Test
15647     @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
15648     public void testFixNotification_doesNotOverwriteTtl() throws Exception {
15649         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15650                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15651                 .setTimeoutAfter(20)
15652                 .build();
15653 
15654         mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
15655 
15656         assertThat(n.getTimeoutAfter()).isEqualTo(20);
15657     }
15658 
15659     @Test
15660     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
15661     public void testRejectOldNotification_oldWhen() throws Exception {
15662         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15663                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15664                 .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis())
15665                 .build();
15666         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
15667                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15668         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15669 
15670         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
15671                 .isFalse();
15672     }
15673 
15674     @Test
15675     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
15676     public void testRejectOldNotification_mediumOldWhen() throws Exception {
15677         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15678                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15679                 .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis())
15680                 .build();
15681         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
15682                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15683         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15684 
15685         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
15686                 .isTrue();
15687     }
15688 
15689     @Test
15690     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
15691     public void testRejectOldNotification_zeroWhen() throws Exception {
15692         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15693                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15694                 .setWhen(0)
15695                 .build();
15696         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
15697                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15698         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15699 
15700         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
15701                 .isTrue();
15702     }
15703 
15704     @Test
15705     public void testClearUIJFromUninstallingPackage() throws Exception {
15706         NotificationRecord r =
15707                 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar");
15708         mService.addNotification(r);
15709 
15710         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt()))
15711                 .thenThrow(PackageManager.NameNotFoundException.class);
15712         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
15713 
15714         mInternalService.cancelNotification(mPkg, mPkg, mUid, 0, r.getSbn().getTag(),
15715                 r.getSbn().getId(), mUserId);
15716 
15717         // no exception
15718     }
15719 
15720     @Test
15721     public void testPostFromMissingPackage_throws() throws Exception {
15722         NotificationRecord r =
15723                 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar");
15724 
15725         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt()))
15726                 .thenThrow(PackageManager.NameNotFoundException.class);
15727         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
15728 
15729         try {
15730             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
15731                     r.getSbn().getId(), r.getSbn().getNotification(),
15732                     r.getSbn().getUserId());
15733             fail("Allowed to post a notification for an absent package");
15734         } catch (SecurityException e) {
15735             // yay
15736         }
15737     }
15738 
15739     @Test
15740     public void testGetEffectsSuppressor_noSuppressor() throws Exception {
15741         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
15742         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
15743         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true);
15744         assertThat(mBinderService.getEffectsSuppressor()).isNull();
15745     }
15746 
15747     @Test
15748     public void testGetEffectsSuppressor_suppressorSameApp() throws Exception {
15749         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
15750         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
15751         mService.isSystemUid = false;
15752         mService.isSystemAppId = false;
15753         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
15754                 HINT_HOST_DISABLE_EFFECTS);
15755         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true);
15756         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
15757     }
15758 
15759     @Test
15760     public void testGetEffectsSuppressor_suppressorDiffApp() throws Exception {
15761         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
15762         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
15763         mService.isSystemUid = false;
15764         mService.isSystemAppId = false;
15765         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
15766                 HINT_HOST_DISABLE_EFFECTS);
15767         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
15768         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(null);
15769     }
15770 
15771     @Test
15772     public void testGetEffectsSuppressor_suppressorDiffAppSystemCaller() throws Exception {
15773         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
15774         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
15775         mService.isSystemUid = true;
15776         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
15777                 HINT_HOST_DISABLE_EFFECTS);
15778         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
15779         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
15780     }
15781 }
15782