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_GROUP_SUMMARY;
37 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
38 import static android.app.Notification.FLAG_NO_CLEAR;
39 import static android.app.Notification.FLAG_NO_DISMISS;
40 import static android.app.Notification.FLAG_ONGOING_EVENT;
41 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
42 import static android.app.Notification.FLAG_PROMOTED_ONGOING;
43 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
44 import static android.app.Notification.GROUP_ALERT_CHILDREN;
45 import static android.app.Notification.VISIBILITY_PRIVATE;
46 import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
47 import static android.app.NotificationChannel.NEWS_ID;
48 import static android.app.NotificationChannel.PROMOTIONS_ID;
49 import static android.app.NotificationChannel.RECS_ID;
50 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
51 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
52 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
53 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
54 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED;
55 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
56 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
57 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
58 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
59 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
60 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
61 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
62 import static android.app.NotificationManager.IMPORTANCE_HIGH;
63 import static android.app.NotificationManager.IMPORTANCE_LOW;
64 import static android.app.NotificationManager.IMPORTANCE_MAX;
65 import static android.app.NotificationManager.IMPORTANCE_MIN;
66 import static android.app.NotificationManager.IMPORTANCE_NONE;
67 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
68 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
69 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
70 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
71 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
72 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
73 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
74 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
78 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
79 import static android.app.PendingIntent.FLAG_IMMUTABLE;
80 import static android.app.PendingIntent.FLAG_MUTABLE;
81 import static android.app.PendingIntent.FLAG_ONE_SHOT;
82 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED;
83 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED;
84 import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
85 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
86 import static android.content.pm.PackageManager.FEATURE_TELECOM;
87 import static android.content.pm.PackageManager.FEATURE_WATCH;
88 import static android.content.pm.PackageManager.PERMISSION_DENIED;
89 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
90 import static android.media.AudioAttributes.USAGE_MEDIA;
91 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
92 import static android.os.Build.VERSION_CODES.O_MR1;
93 import static android.os.Build.VERSION_CODES.P;
94 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
95 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
96 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
97 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
98 import static android.os.UserHandle.USER_SYSTEM;
99 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
100 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
101 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
102 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
103 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
104 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
105 import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
106 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
107 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
108 import static android.service.notification.Adjustment.KEY_TYPE;
109 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
110 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
111 import static android.service.notification.Adjustment.TYPE_NEWS;
112 import static android.service.notification.Adjustment.TYPE_PROMOTION;
113 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
114 import static android.service.notification.Condition.SOURCE_CONTEXT;
115 import static android.service.notification.Condition.SOURCE_USER_ACTION;
116 import static android.service.notification.Condition.STATE_TRUE;
117 import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
118 import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT;
119 import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
120 import static android.service.notification.Flags.FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION;
121 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
122 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
123 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
124 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
125 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
126 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
127 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
128 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
129 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
130 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
131 import static android.view.Display.DEFAULT_DISPLAY;
132 import static android.view.Display.INVALID_DISPLAY;
133 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
134 
135 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
136 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
137 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
138 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
139 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL;
140 import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS;
141 import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY;
142 import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
143 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
144 import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL;
145 import static com.android.server.notification.NotificationManagerService.TAG;
146 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
147 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
148 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
149 
150 import static com.google.common.collect.Iterables.getOnlyElement;
151 import static com.google.common.truth.Truth.assertThat;
152 import static com.google.common.truth.Truth.assertWithMessage;
153 
154 import static junit.framework.Assert.assertEquals;
155 import static junit.framework.Assert.assertFalse;
156 import static junit.framework.Assert.assertNotNull;
157 import static junit.framework.Assert.assertNotSame;
158 import static junit.framework.Assert.assertNull;
159 import static junit.framework.Assert.assertSame;
160 import static junit.framework.Assert.assertTrue;
161 import static junit.framework.Assert.fail;
162 
163 import static org.junit.Assert.assertNotEquals;
164 import static org.junit.Assert.assertThrows;
165 import static org.mockito.ArgumentMatchers.isNull;
166 import static org.mockito.Matchers.anyBoolean;
167 import static org.mockito.Matchers.anyLong;
168 import static org.mockito.Matchers.anyString;
169 import static org.mockito.Matchers.eq;
170 import static org.mockito.Mockito.any;
171 import static org.mockito.Mockito.anyInt;
172 import static org.mockito.Mockito.atLeastOnce;
173 import static org.mockito.Mockito.clearInvocations;
174 import static org.mockito.Mockito.doAnswer;
175 import static org.mockito.Mockito.doNothing;
176 import static org.mockito.Mockito.doReturn;
177 import static org.mockito.Mockito.doThrow;
178 import static org.mockito.Mockito.inOrder;
179 import static org.mockito.Mockito.mock;
180 import static org.mockito.Mockito.never;
181 import static org.mockito.Mockito.reset;
182 import static org.mockito.Mockito.spy;
183 import static org.mockito.Mockito.timeout;
184 import static org.mockito.Mockito.times;
185 import static org.mockito.Mockito.verify;
186 import static org.mockito.Mockito.verifyNoMoreInteractions;
187 import static org.mockito.Mockito.when;
188 
189 import static java.util.Collections.emptyList;
190 import static java.util.Collections.singletonList;
191 
192 import android.Manifest;
193 import android.annotation.Nullable;
194 import android.annotation.SuppressLint;
195 import android.annotation.UserIdInt;
196 import android.app.ActivityManager;
197 import android.app.ActivityManagerInternal;
198 import android.app.AlarmManager;
199 import android.app.AppOpsManager;
200 import android.app.AutomaticZenRule;
201 import android.app.IActivityManager;
202 import android.app.ICallNotificationEventCallback;
203 import android.app.INotificationManager;
204 import android.app.ITransientNotification;
205 import android.app.IUriGrantsManager;
206 import android.app.Notification;
207 import android.app.Notification.MessagingStyle.Message;
208 import android.app.NotificationChannel;
209 import android.app.NotificationChannelGroup;
210 import android.app.NotificationManager;
211 import android.app.NotificationManager.Policy;
212 import android.app.PendingIntent;
213 import android.app.Person;
214 import android.app.RemoteInput;
215 import android.app.RemoteInputHistoryItem;
216 import android.app.StatsManager;
217 import android.app.ZenBypassingApp;
218 import android.app.admin.DevicePolicyManagerInternal;
219 import android.app.backup.BackupRestoreEventLogger;
220 import android.app.job.JobScheduler;
221 import android.app.role.RoleManager;
222 import android.app.usage.UsageStatsManagerInternal;
223 import android.companion.AssociationInfo;
224 import android.companion.AssociationRequest;
225 import android.companion.ICompanionDeviceManager;
226 import android.compat.testing.PlatformCompatChangeRule;
227 import android.content.BroadcastReceiver;
228 import android.content.ComponentName;
229 import android.content.ContentUris;
230 import android.content.Context;
231 import android.content.IIntentSender;
232 import android.content.Intent;
233 import android.content.IntentFilter;
234 import android.content.pm.ActivityInfo;
235 import android.content.pm.ApplicationInfo;
236 import android.content.pm.IPackageManager;
237 import android.content.pm.LauncherApps;
238 import android.content.pm.ModuleInfo;
239 import android.content.pm.PackageManager;
240 import android.content.pm.PackageManagerInternal;
241 import android.content.pm.ParceledListSlice;
242 import android.content.pm.ResolveInfo;
243 import android.content.pm.ShortcutInfo;
244 import android.content.pm.ShortcutServiceInternal;
245 import android.content.pm.UserInfo;
246 import android.content.pm.VersionedPackage;
247 import android.content.res.Resources;
248 import android.graphics.Bitmap;
249 import android.graphics.Color;
250 import android.graphics.drawable.Icon;
251 import android.media.AudioAttributes;
252 import android.media.AudioManager;
253 import android.media.session.MediaSession;
254 import android.net.Uri;
255 import android.os.Binder;
256 import android.os.Build;
257 import android.os.Bundle;
258 import android.os.IBinder;
259 import android.os.Looper;
260 import android.os.Parcel;
261 import android.os.Parcelable;
262 import android.os.PowerManager;
263 import android.os.PowerManager.WakeLock;
264 import android.os.Process;
265 import android.os.RemoteException;
266 import android.os.SystemClock;
267 import android.os.UserHandle;
268 import android.os.UserManager;
269 import android.os.WorkSource;
270 import android.permission.PermissionManager;
271 import android.platform.test.annotations.DisableFlags;
272 import android.platform.test.annotations.EnableFlags;
273 import android.platform.test.annotations.RequiresFlagsEnabled;
274 import android.platform.test.flag.junit.FlagsParameterization;
275 import android.platform.test.flag.junit.SetFlagsRule;
276 import android.platform.test.rule.LimitDevicesRule;
277 import android.provider.MediaStore;
278 import android.provider.Settings;
279 import android.service.notification.Adjustment;
280 import android.service.notification.Condition;
281 import android.service.notification.ConversationChannelWrapper;
282 import android.service.notification.DeviceEffectsApplier;
283 import android.service.notification.INotificationListener;
284 import android.service.notification.NotificationListenerFilter;
285 import android.service.notification.NotificationListenerService;
286 import android.service.notification.NotificationRankingUpdate;
287 import android.service.notification.NotificationStats;
288 import android.service.notification.StatusBarNotification;
289 import android.service.notification.ZenModeConfig;
290 import android.service.notification.ZenPolicy;
291 import android.telecom.TelecomManager;
292 import android.testing.TestWithLooperRule;
293 import android.testing.TestableContentResolver;
294 import android.testing.TestableLooper;
295 import android.testing.TestableLooper.RunWithLooper;
296 import android.testing.TestablePermissions;
297 import android.testing.TestableResources;
298 import android.text.Html;
299 import android.text.TextUtils;
300 import android.util.ArrayMap;
301 import android.util.ArraySet;
302 import android.util.AtomicFile;
303 import android.util.Log;
304 import android.util.Pair;
305 import android.util.Xml;
306 import android.view.accessibility.AccessibilityManager;
307 import android.widget.RemoteViews;
308 
309 import androidx.test.InstrumentationRegistry;
310 import androidx.test.filters.SmallTest;
311 
312 import com.android.internal.R;
313 import com.android.internal.config.sysui.TestableFlagResolver;
314 import com.android.internal.logging.InstanceIdSequence;
315 import com.android.internal.logging.InstanceIdSequenceFake;
316 import com.android.internal.messages.nano.SystemMessageProto;
317 import com.android.internal.statusbar.NotificationVisibility;
318 import com.android.internal.widget.LockPatternUtils;
319 import com.android.modules.utils.TypedXmlPullParser;
320 import com.android.modules.utils.TypedXmlSerializer;
321 import com.android.server.DeviceIdleInternal;
322 import com.android.server.LocalServices;
323 import com.android.server.SystemService;
324 import com.android.server.SystemService.TargetUser;
325 import com.android.server.UiServiceTestCase;
326 import com.android.server.job.JobSchedulerInternal;
327 import com.android.server.lights.LightsManager;
328 import com.android.server.lights.LogicalLight;
329 import com.android.server.notification.GroupHelper.NotificationAttributes;
330 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
331 import com.android.server.notification.NotificationManagerService.NotificationListeners;
332 import com.android.server.notification.NotificationManagerService.PostNotificationTracker;
333 import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory;
334 import com.android.server.pm.PackageManagerService;
335 import com.android.server.pm.UserManagerInternal;
336 import com.android.server.policy.PermissionPolicyInternal;
337 import com.android.server.statusbar.StatusBarManagerInternal;
338 import com.android.server.uri.UriGrantsManagerInternal;
339 import com.android.server.utils.quota.MultiRateLimiter;
340 import com.android.server.wm.ActivityTaskManagerInternal;
341 import com.android.server.wm.WindowManagerInternal;
342 
343 import com.google.android.collect.Lists;
344 import com.google.common.collect.ImmutableList;
345 
346 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
347 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
348 
349 import org.junit.After;
350 import org.junit.Assert;
351 import org.junit.Before;
352 import org.junit.ClassRule;
353 import org.junit.Rule;
354 import org.junit.Test;
355 import org.junit.rules.TestRule;
356 import org.junit.runner.RunWith;
357 import org.mockito.ArgumentCaptor;
358 import org.mockito.ArgumentMatcher;
359 import org.mockito.ArgumentMatchers;
360 import org.mockito.InOrder;
361 import org.mockito.Mock;
362 import org.mockito.Mockito;
363 import org.mockito.MockitoAnnotations;
364 import org.mockito.invocation.InvocationOnMock;
365 import org.mockito.stubbing.Answer;
366 
367 import java.io.BufferedInputStream;
368 import java.io.BufferedOutputStream;
369 import java.io.ByteArrayInputStream;
370 import java.io.ByteArrayOutputStream;
371 import java.io.File;
372 import java.io.FileOutputStream;
373 import java.time.Duration;
374 import java.util.ArrayList;
375 import java.util.Arrays;
376 import java.util.HashSet;
377 import java.util.List;
378 import java.util.Map;
379 import java.util.concurrent.CountDownLatch;
380 import java.util.function.Consumer;
381 
382 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
383 import platform.test.runner.parameterized.Parameters;
384 
385 @SmallTest
386 @RunWith(ParameterizedAndroidJunit4.class)
387 @RunWithLooper
388 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
389 public class NotificationManagerServiceTest extends UiServiceTestCase {
390     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
391     private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package";
392     private static final String PKG_NO_CHANNELS = "com.example.no.channels";
393     private static final int TEST_TASK_ID = 1;
394     private static final int UID_HEADLESS = 1_000_000;
395     private static final int TOAST_DURATION = 2_000;
396     private static final int SECONDARY_DISPLAY_ID = 42;
397     private static final int TEST_PROFILE_USERHANDLE = 12;
398     private static final long DELAY_FORCE_REGROUP_TIME = 3000;
399 
400     private static final String ACTION_NOTIFICATION_TIMEOUT =
401             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
402     private static final String EXTRA_KEY = "key";
403     private static final String SCHEME_TIMEOUT = "timeout";
404     private static final String REDACTED_TEXT = "redacted text";
405 
406     private static final AutomaticZenRule SOME_ZEN_RULE =
407             new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
408                     .setOwner(new ComponentName("pkg", "cls"))
409                     .build();
410 
411     @ClassRule
412     public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule();
413 
414     @Rule
415     public TestRule compatChangeRule = new PlatformCompatChangeRule();
416 
417     private TestableNotificationManagerService mService;
418     private INotificationManager mBinderService;
419     private NotificationManagerInternal mInternalService;
420     private ShortcutHelper mShortcutHelper;
421     @Mock
422     private IPackageManager mPackageManager;
423     @Mock
424     private PackageManager mPackageManagerClient;
425     @Mock
426     private PackageManagerInternal mPackageManagerInternal;
427     @Mock
428     private PermissionPolicyInternal mPermissionPolicyInternal;
429     @Mock
430     private WindowManagerInternal mWindowManagerInternal;
431     @Mock
432     private PermissionHelper mPermissionHelper;
433     private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
434     @Rule(order = Integer.MAX_VALUE)
435     public TestWithLooperRule mlooperRule = new TestWithLooperRule();
436     private TestableLooper mTestableLooper;
437     @Mock
438     private RankingHelper mRankingHelper;
439     @Mock private PreferencesHelper mPreferencesHelper;
440     AtomicFile mPolicyFile;
441     File mFile;
442     @Mock
443     private NotificationUsageStats mUsageStats;
444     @Mock
445     private UsageStatsManagerInternal mAppUsageStats;
446     @Mock
447     private AudioManager mAudioManager;
448     @Mock
449     private LauncherApps mLauncherApps;
450     @Mock
451     private ShortcutServiceInternal mShortcutServiceInternal;
452     @Mock
453     private UserManager mUserManager;
454     @Mock
455     ActivityManager mActivityManager;
456     @Mock
457     TelecomManager mTelecomManager;
458     @Mock
459     Resources mResources;
460     @Mock
461     RankingHandler mRankingHandler;
462     @Mock
463     ActivityManagerInternal mAmi;
464     @Mock
465     JobSchedulerInternal mJsi;
466     @Mock
467     private Looper mMainLooper;
468     @Mock
469     private NotificationManager mMockNm;
470     @Mock
471     private PermissionManager mPermissionManager;
472     @Mock
473     private DevicePolicyManagerInternal mDevicePolicyManager;
474     @Mock
475     private PowerManager mPowerManager;
476     @Mock
477     private LightsManager mLightsManager;
478     private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>();
479     private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory =
480             new TestPostNotificationTrackerFactory();
481 
482     private PendingIntent mActivityIntent;
483     private PendingIntent mActivityIntentImmutable;
484 
485     private static final int MAX_POST_DELAY = 1000;
486 
487     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
488             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
489 
490     NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW);
491 
492     NotificationChannel mMinChannel = new NotificationChannel("min", "min", IMPORTANCE_MIN);
493 
494     private final NotificationChannel mParentChannel =
495             new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT);
496     private final NotificationChannel mConversationChannel =
497             new NotificationChannel(
498                     CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT);
499 
500     private static final String PARENT_CHANNEL_ID = "parentChannelId";
501     private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId";
502     private static final String CONVERSATION_ID = "conversationId";
503 
504     private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
505 
506     private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
507     private static final String SEARCH_SELECTOR_PKG = "searchSelector";
508     private static final String ADSERVICES_MODULE_PKG = "com.android.adservices";
509     private static final String ADSERVICES_APK_PKG = "com.android.adservices.api";
510 
511     @Mock
512     private NotificationListeners mListeners;
513     @Mock
514     private NotificationListenerFilter mNlf;
515     @Mock private NotificationAssistants mAssistants;
516     @Mock private ConditionProviders mConditionProviders;
517     private ManagedServices.ManagedServiceInfo mListener;
518     @Mock private ICompanionDeviceManager mCompanionMgr;
519     @Mock SnoozeHelper mSnoozeHelper;
520     @Mock GroupHelper mGroupHelper;
521     @Mock
522     IBinder mPermOwner;
523     @Mock
524     IActivityManager mAm;
525     @Mock
526     ActivityTaskManagerInternal mAtm;
527     @Mock
528     IUriGrantsManager mUgm;
529     @Mock
530     UriGrantsManagerInternal mUgmInternal;
531     @Mock
532     AppOpsManager mAppOpsManager;
533     private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener;
534     @Mock
535     private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
536             mNotificationAssistantAccessGrantedCallback;
537     @Mock
538     UserManager mUm;
539     @Mock
540     UserManagerInternal mUmInternal;
541     @Mock
542     NotificationHistoryManager mHistoryManager;
543     @Mock
544     StatsManager mStatsManager;
545     @Mock
546     AlarmManager mAlarmManager;
547     @Mock JobScheduler mJobScheduler;
548     @Mock
549     MultiRateLimiter mToastRateLimiter;
550     BroadcastReceiver mPackageIntentReceiver;
551     BroadcastReceiver mUserIntentReceiver;
552     BroadcastReceiver mNotificationTimeoutReceiver;
553     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
554     TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
555 
556     TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
557     @Rule
558     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
559     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
560             1 << 30);
561     @Mock
562     StatusBarManagerInternal mStatusBar;
563 
564     @Mock
565     NotificationAttentionHelper mAttentionHelper;
566 
567     private NotificationManagerService.WorkerHandler mWorkerHandler;
568 
569     private class TestableToastCallback extends ITransientNotification.Stub {
570         @Override
show(IBinder windowToken)571         public void show(IBinder windowToken) {
572         }
573 
574         @Override
hide()575         public void hide() {
576         }
577     }
578 
579     private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory {
580 
581         private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>();
582 
583         @Override
newTracker(@ullable WakeLock optionalWakeLock)584         public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) {
585             PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker(
586                     optionalWakeLock);
587             mCreatedTrackers.add(tracker);
588             return tracker;
589         }
590     }
591 
592     @Parameters(name = "{0}")
getParams()593     public static List<FlagsParameterization> getParams() {
594         return FlagsParameterization.allCombinationsOf();
595     }
596 
NotificationManagerServiceTest(FlagsParameterization flags)597     public NotificationManagerServiceTest(FlagsParameterization flags) {
598         mSetFlagsRule.setFlagsParameterization(flags);
599     }
600 
601     @Before
setUp()602     public void setUp() throws Exception {
603         // Shell permisssions will override permissions of our app, so add all necessary permissions
604         // for this test here:
605         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
606                 "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG",
607                 "android.permission.READ_DEVICE_CONFIG",
608                 "android.permission.READ_CONTACTS");
609 
610         MockitoAnnotations.initMocks(this);
611 
612         DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
613         when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
614 
615         LocalServices.removeServiceForTest(UserManagerInternal.class);
616         LocalServices.addService(UserManagerInternal.class, mUmInternal);
617         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
618         LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
619         LocalServices.removeServiceForTest(WindowManagerInternal.class);
620         LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
621         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
622         LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
623         LocalServices.removeServiceForTest(DeviceIdleInternal.class);
624         LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
625         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
626         LocalServices.addService(ActivityManagerInternal.class, mAmi);
627         LocalServices.removeServiceForTest(JobSchedulerInternal.class);
628         LocalServices.addService(JobSchedulerInternal.class, mJsi);
629         LocalServices.removeServiceForTest(PackageManagerInternal.class);
630         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
631         LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
632         LocalServices.addService(PermissionPolicyInternal.class, mPermissionPolicyInternal);
633         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
634         LocalServices.addService(ShortcutServiceInternal.class, mShortcutServiceInternal);
635         mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
636         mContext.addMockSystemService(NotificationManager.class, mMockNm);
637         mContext.addMockSystemService(RoleManager.class, mock(RoleManager.class));
638         mContext.addMockSystemService(Context.LAUNCHER_APPS_SERVICE, mLauncherApps);
639         mContext.addMockSystemService(Context.USER_SERVICE, mUm);
640         mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE,
641                 mock(AccessibilityManager.class));
642 
643         doNothing().when(mContext).sendBroadcast(any(), anyString());
644         doNothing().when(mContext).sendBroadcastAsUser(any(), any());
645         doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
646         TestableContentResolver cr = mock(TestableContentResolver.class);
647         when(mContext.getContentResolver()).thenReturn(cr);
648         doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt());
649 
650         when(mAppOpsManager.checkOpNoThrow(
651                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
652                 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED);
653 
654         // Use this testable looper.
655         mTestableLooper = TestableLooper.get(this);
656         // MockPackageManager - default returns ApplicationInfo with matching calling UID
657         mContext.setMockPackageManager(mPackageManagerClient);
658 
659         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
660                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
661                     Object[] args = invocation.getArguments();
662                     return getApplicationInfo((String) args[0], mUid);
663                 });
664         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
665                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
666                     Object[] args = invocation.getArguments();
667                     return getApplicationInfo((String) args[0], mUid);
668                 });
669         when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
670         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer(
671                 (Answer<Boolean>) invocation -> {
672                     // TODO: b/317957802 - This is overly broad and basically makes ANY
673                     //  isSameApp() check pass,  requiring Mockito.reset() for meaningful
674                     //  tests! Make it more precise.
675                     Object[] args = invocation.getArguments();
676                     return (int) args[1] == mUid;
677                 });
678         when(mLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
679         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
680         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
681         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
682         when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{mPkg});
683         when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{mPkg});
684         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt()))
685                 .thenReturn(INVALID_TASK_ID);
686         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
687         when(mUm.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId});
688         when(mUmInternal.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId});
689         when(mAmi.getCurrentUserId()).thenReturn(mUserId);
690 
691         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true);
692 
693         ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
694         List<ActivityManager.AppTask> taskList = new ArrayList<>();
695         ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo();
696         taskInfo.taskId = TEST_TASK_ID;
697         when(task.getTaskInfo()).thenReturn(taskInfo);
698         taskList.add(task);
699         when(mAtm.getAppTasks(anyString(), anyInt())).thenReturn(taskList);
700 
701         // write to a test file; the system file isn't readable from tests
702         mFile = new File(mContext.getCacheDir(), "test.xml");
703         mFile.createNewFile();
704         final String preupgradeXml = "<notification-policy></notification-policy>";
705         mPolicyFile = new AtomicFile(mFile);
706         FileOutputStream fos = mPolicyFile.startWrite();
707         fos.write(preupgradeXml.getBytes());
708         mPolicyFile.finishWrite(fos);
709 
710         // Setup managed services
711         when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
712         when(mNlf.isPackageAllowed(any())).thenReturn(true);
713         when(mNlf.isPackageAllowed(null)).thenReturn(true);
714         when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
715         mListener = mListeners.new ManagedServiceInfo(
716                 null, new ComponentName(mPkg, "test_class"),
717                 mUserId, true, null, 0, 123);
718         ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
719         ArraySet<ComponentName> components = new ArraySet<>();
720         components.add(defaultComponent);
721         when(mListeners.getDefaultComponents()).thenReturn(components);
722         when(mConditionProviders.getDefaultPackages())
723                 .thenReturn(new ArraySet<>(Arrays.asList("config")));
724         when(mAssistants.getDefaultComponents()).thenReturn(components);
725         when(mAssistants.queryPackageForServices(
726                 anyString(), anyInt(), anyInt())).thenReturn(components);
727         when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
728         ManagedServices.Config listenerConfig = new ManagedServices.Config();
729         listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
730         when(mListeners.getConfig()).thenReturn(listenerConfig);
731         ManagedServices.Config assistantConfig = new ManagedServices.Config();
732         assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS;
733         when(mAssistants.getConfig()).thenReturn(assistantConfig);
734         ManagedServices.Config dndConfig = new ManagedServices.Config();
735         dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS;
736         when(mConditionProviders.getConfig()).thenReturn(dndConfig);
737 
738         when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
739 
740         // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks.
741         // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks,
742         // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't
743         // call release twice, etc) and we want the test to fail if such misuse happens, too.
744         PowerManager realPowerManager = mContext.getSystemService(PowerManager.class);
745         when(mPowerManager.newWakeLock(anyInt(), anyString())).then(
746                 (Answer<WakeLock>) invocation -> {
747                     WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0),
748                             invocation.getArgument(1));
749                     mAcquiredWakeLocks.add(wl);
750                     return wl;
751                 });
752 
753         // TODO (b/291907312): remove feature flag
754         // NOTE: Prefer using the @EnableFlags annotation where possible. Do not add any android.app
755         //  flags here.
756         mSetFlagsRule.disableFlags(
757                 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE);
758 
759         mActivityIntent = spy(PendingIntent.getActivity(mContext, 0,
760                 new Intent().setPackage(mPkg), PendingIntent.FLAG_MUTABLE));
761         mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0,
762                 new Intent().setPackage(mPkg), FLAG_IMMUTABLE));
763 
764         initNMS();
765     }
766 
initNMS()767     private void initNMS() throws Exception {
768         initNMS(SystemService.PHASE_BOOT_COMPLETED);
769     }
770 
initNMS(int upToBootPhase)771     private void initNMS(int upToBootPhase) throws Exception {
772         mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
773                 mNotificationInstanceIdSequence);
774 
775         // apps allowed as convos
776         mService.setStringArrayResourceValue(PKG_O);
777 
778         TestableResources tr = mContext.getOrCreateTestableResources();
779         tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName,
780                 SEARCH_SELECTOR_PKG);
781 
782         doAnswer(invocation -> {
783             mOnPermissionChangeListener = invocation.getArgument(2);
784             return null;
785         }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(),
786                 any());
787         when(mUmInternal.isUserInitialized(anyInt())).thenReturn(true);
788 
789         mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
790         mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
791                 mLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
792                 mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
793                 mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal,
794                 mAppOpsManager, mUm, mHistoryManager, mStatsManager,
795                 mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
796                 mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
797                 mPowerManager, mPostNotificationTrackerFactory);
798 
799         mService.setAttentionHelper(mAttentionHelper);
800         mService.setLockPatternUtils(mock(LockPatternUtils.class));
801 
802         // Return first true for RoleObserver main-thread check
803         when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
804         ModuleInfo moduleInfo = new ModuleInfo();
805         moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG);
806         moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG));
807         when(mPackageManagerClient.getInstalledModules(anyInt()))
808                 .thenReturn(List.of(moduleInfo));
809         if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) {
810             mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
811         }
812 
813         Mockito.reset(mHistoryManager);
814         verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
815 
816         if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
817             mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
818             verify(mHistoryManager).onBootPhaseAppsCanStart();
819         }
820 
821         mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
822         mService.setStrongAuthTracker(mStrongAuthTracker);
823 
824         mShortcutHelper = mService.getShortcutHelper();
825         mShortcutHelper.setLauncherApps(mLauncherApps);
826         mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
827         mShortcutHelper.setUserManager(mUserManager);
828 
829         // Capture PackageIntentReceiver
830         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
831                 ArgumentCaptor.forClass(BroadcastReceiver.class);
832         ArgumentCaptor<IntentFilter> intentFilterCaptor =
833                 ArgumentCaptor.forClass(IntentFilter.class);
834 
835         verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
836                 any(), intentFilterCaptor.capture(), any(), any());
837         verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
838                 intentFilterCaptor.capture(), anyInt());
839         verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
840                 intentFilterCaptor.capture());
841         List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
842         List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues();
843 
844         for (int i = 0; i < intentFilters.size(); i++) {
845             final IntentFilter filter = intentFilters.get(i);
846             if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)
847                     && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED)
848                     && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
849                 mPackageIntentReceiver = broadcastReceivers.get(i);
850             }
851             if (filter.hasAction(Intent.ACTION_USER_SWITCHED)
852                     || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)
853                     || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
854                 // There may be multiple receivers, get the NMS one
855                 if (broadcastReceivers.get(i).toString().contains(
856                         NotificationManagerService.class.getName())) {
857                     mUserIntentReceiver = broadcastReceivers.get(i);
858                 }
859             }
860             if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT)
861                     && filter.hasDataScheme(SCHEME_TIMEOUT)) {
862                 mNotificationTimeoutReceiver = broadcastReceivers.get(i);
863             }
864         }
865         assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
866         assertNotNull("User receiver should exist", mUserIntentReceiver);
867         if (!Flags.allNotifsNeedTtl()) {
868             assertNotNull("Notification timeout receiver should exist",
869                     mNotificationTimeoutReceiver);
870         }
871 
872         // Pretend the shortcut exists
873         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
874         shortcutInfos.add(createMockConvoShortcut());
875         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
876         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
877                 anyString(), anyInt(), any())).thenReturn(true);
878         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
879         mockIsUserVisible(DEFAULT_DISPLAY, true);
880         mockIsVisibleBackgroundUsersSupported(false);
881 
882         // Set the testable bubble extractor
883         RankingHelper rankingHelper = mService.getRankingHelper();
884         BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
885         extractor.setActivityManager(mActivityManager);
886 
887         // Tests call directly into the Binder.
888         mBinderService = mService.getBinderService();
889         mInternalService = mService.getInternalService();
890 
891         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(
892                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
893         mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice(
894                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
895         mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
896                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
897         assertNotNull(mBinderService.getNotificationChannel(
898                 mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID));
899         assertNotNull(mBinderService.getNotificationChannel(
900                 mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId()));
901         assertNotNull(mBinderService.getNotificationChannel(
902                 mPkg, mContext.getUserId(), mPkg, mMinChannel.getId()));
903         clearInvocations(mRankingHandler);
904         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
905 
906         var checker = mock(TestableNotificationManagerService.ComponentPermissionChecker.class);
907         mService.permissionChecker = checker;
908         when(checker.check(anyString(), anyInt(), anyInt(), anyBoolean()))
909                 .thenReturn(PackageManager.PERMISSION_DENIED);
910     }
911 
912     @After
assertNotificationRecordLoggerCallsValid()913     public void assertNotificationRecordLoggerCallsValid() {
914         waitForIdle(); // Finish async work, including all logging calls done by Runnables.
915         for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) {
916             if (call.wasLogged) {
917                 assertNotNull(call.event);
918                 if (call.event == NOTIFICATION_POSTED || call.event == NOTIFICATION_UPDATED) {
919                     assertThat(call.postDurationMillisLogged).isGreaterThan(0);
920                 } else {
921                     assertThat(call.postDurationMillisLogged).isNull();
922                 }
923             }
924         }
925         assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty();
926     }
927 
928     @After
assertAllTrackersFinishedOrCancelled()929     public void assertAllTrackersFinishedOrCancelled() {
930         waitForIdle(); // Finish async work.
931         // Verify that no trackers were left dangling.
932         for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) {
933             assertThat(tracker.isOngoing()).isFalse();
934         }
935         mPostNotificationTrackerFactory.mCreatedTrackers.clear();
936     }
937 
938     @After
assertAllWakeLocksReleased()939     public void assertAllWakeLocksReleased() {
940         waitForIdle(); // Finish async work.
941         for (WakeLock wakeLock : mAcquiredWakeLocks) {
942             assertThat(wakeLock.isHeld()).isFalse();
943         }
944     }
945 
946     @After
tearDown()947     public void tearDown() throws Exception {
948         if (mFile != null) mFile.delete();
949 
950         if (mActivityIntent != null) {
951             mActivityIntent.cancel();
952         }
953 
954         mService.clearNotifications();
955         if (mTestableLooper != null) {
956             mTestableLooper.processAllMessages();
957         }
958 
959         try {
960             mService.onDestroy();
961         } catch (IllegalStateException | IllegalArgumentException e) {
962             Log.e(TAG, "failed to destroy", e);
963             // can throw if a broadcast receiver was never registered
964         }
965 
966         InstrumentationRegistry.getInstrumentation()
967                 .getUiAutomation().dropShellPermissionIdentity();
968         if (mWorkerHandler != null) {
969             // Remove scheduled messages that would be processed when the test is already done, and
970             // could cause issues, for example, messages that remove/cancel shown toasts (this causes
971             // problematic interactions with mocks when they're no longer working as expected).
972             mWorkerHandler.removeCallbacksAndMessages(null);
973         }
974 
975         if (mTestableLooper != null) {
976             // Must remove static reference to this test object to prevent leak (b/261039202)
977             mTestableLooper.remove(this);
978         }
979     }
980 
createMockConvoShortcut()981     private ShortcutInfo createMockConvoShortcut() {
982         ShortcutInfo info = mock(ShortcutInfo.class);
983         when(info.getPackage()).thenReturn(mPkg);
984         when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
985         when(info.getUserId()).thenReturn(USER_SYSTEM);
986         when(info.isLongLived()).thenReturn(true);
987         when(info.isEnabled()).thenReturn(true);
988         return info;
989     }
990 
simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid)991     private void simulatePackageSuspendBroadcast(boolean suspend, String pkg,
992             int uid) {
993         // mimics receive broadcast that package is (un)suspended
994         // but does not actually (un)suspend the package
995         final Bundle extras = new Bundle();
996         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
997                 new String[]{pkg});
998         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid});
999 
1000         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
1001                 : Intent.ACTION_PACKAGES_UNSUSPENDED;
1002         final Intent intent = new Intent(action);
1003         intent.putExtras(extras);
1004 
1005         mPackageIntentReceiver.onReceive(getContext(), intent);
1006     }
1007 
simulatePackageRemovedBroadcast(String pkg, int uid)1008     private void simulatePackageRemovedBroadcast(String pkg, int uid) {
1009         // mimics receive broadcast that package is removed, but doesn't remove the package.
1010         final Bundle extras = new Bundle();
1011         extras.putInt(Intent.EXTRA_UID, uid);
1012 
1013         final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
1014         intent.setData(Uri.parse("package:" + pkg));
1015         intent.putExtras(extras);
1016 
1017         mPackageIntentReceiver.onReceive(getContext(), intent);
1018     }
1019 
simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids)1020     private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) {
1021         // mimics receive broadcast that package is (un)distracting
1022         // but does not actually register that info with packagemanager
1023         final Bundle extras = new Bundle();
1024         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
1025         extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
1026         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids);
1027 
1028         final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
1029         intent.putExtras(extras);
1030 
1031         mPackageIntentReceiver.onReceive(getContext(), intent);
1032     }
1033 
simulateProfileAvailabilityActions(String intentAction)1034     private void simulateProfileAvailabilityActions(String intentAction) {
1035         final Intent intent = new Intent(intentAction);
1036         intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
1037         mUserIntentReceiver.onReceive(mContext, intent);
1038     }
1039 
generateResetComponentValues()1040     private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() {
1041         ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>();
1042         changed.put(true, new ArrayList<>());
1043         changed.put(false, new ArrayList<>());
1044         return changed;
1045     }
getApplicationInfo(String pkg, int uid)1046     private ApplicationInfo getApplicationInfo(String pkg, int uid) {
1047         final ApplicationInfo applicationInfo = new ApplicationInfo();
1048         applicationInfo.packageName = pkg;
1049         applicationInfo.uid = uid;
1050         applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir;
1051         switch (pkg) {
1052             case PKG_N_MR1:
1053                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
1054                 break;
1055             case PKG_O:
1056                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
1057                 break;
1058             case PKG_P:
1059                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
1060                 break;
1061             default:
1062                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
1063                 break;
1064         }
1065         return applicationInfo;
1066     }
1067 
waitForIdle()1068     public void waitForIdle() {
1069         if (mTestableLooper != null) {
1070             mTestableLooper.processAllMessages();
1071         }
1072     }
1073 
setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, int pkgPref, boolean channelEnabled)1074     private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled,
1075             int pkgPref, boolean channelEnabled) {
1076         Settings.Secure.putInt(mContext.getContentResolver(),
1077                 Settings.Secure.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0);
1078         mService.mPreferencesHelper.updateBubblesEnabled();
1079         assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled(
1080                 mock(UserHandle.class)));
1081         try {
1082             mBinderService.setBubblesAllowed(pkg, uid, pkgPref);
1083         } catch (RemoteException e) {
1084             e.printStackTrace();
1085         }
1086         mTestNotificationChannel.setAllowBubbles(channelEnabled);
1087     }
1088 
setUpPrefsForHistory(@serIdInt int userId, boolean globalEnabled)1089     private void setUpPrefsForHistory(@UserIdInt int userId, boolean globalEnabled)
1090             throws Exception {
1091         initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY);
1092 
1093         // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
1094         Settings.Secure.putIntForUser(mContext.getContentResolver(),
1095                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, userId);
1096         // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0
1097         Settings.Secure.putInt(mContext.getContentResolver(),
1098                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0);
1099         setUsers(new int[] {0, userId});
1100 
1101         // Forces an update by calling observe on mSettingsObserver, which picks up the settings
1102         // changes above.
1103         mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
1104 
1105         assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(),
1106                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, userId) != 0);
1107     }
1108 
generateSbn(String pkg, int uid, long postTime, int userId)1109     private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) {
1110         Notification.Builder nb = new Notification.Builder(mContext, "a")
1111                 .setContentTitle("foo")
1112                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1113         StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid,
1114                 "tag" + System.currentTimeMillis(), uid, 0,
1115                 nb.build(), new UserHandle(userId), null, postTime);
1116         return sbn;
1117     }
1118 
generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary)1119     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1120             String groupKey, boolean isSummary) {
1121         return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey,
1122                 isSummary);
1123     }
1124 
generateNotificationRecord(NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary)1125     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1126             String tag, String groupKey, boolean isSummary) {
1127         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1128                 .setContentTitle("foo")
1129                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1130                 .setGroup(groupKey)
1131                 .setGroupSummary(isSummary);
1132         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id,
1133                 tag, mUid, 0,
1134                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1135         return new NotificationRecord(mContext, sbn, channel);
1136     }
1137 
generateNotificationRecord(NotificationChannel channel)1138     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
1139         return generateNotificationRecord(channel, null);
1140     }
1141 
generateNotificationRecord(NotificationChannel channel, Notification.TvExtender extender)1142     private NotificationRecord generateNotificationRecord(NotificationChannel channel,
1143             Notification.TvExtender extender) {
1144         if (channel == null) {
1145             channel = mTestNotificationChannel;
1146         }
1147         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1148                 .setContentTitle("foo")
1149                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1150                 .addAction(new Notification.Action.Builder(null, "test", mActivityIntent).build())
1151                 .addAction(new Notification.Action.Builder(
1152                         null, "test", mActivityIntentImmutable).build());
1153         if (extender != null) {
1154             nb.extend(extender);
1155         }
1156         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
1157                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1158         return new NotificationRecord(mContext, sbn, channel);
1159     }
1160 
generateNotificationRecord(NotificationChannel channel, long postTime)1161     private NotificationRecord generateNotificationRecord(NotificationChannel channel,
1162             long postTime) {
1163         final StatusBarNotification sbn = generateSbn(mPkg, mUid, postTime, mUserId);
1164         return new NotificationRecord(mContext, sbn, channel);
1165     }
1166 
generateNotificationRecord(NotificationChannel channel, int userId)1167     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) {
1168         return generateNotificationRecord(channel, 1, userId);
1169     }
1170 
generateNotificationRecord(NotificationChannel channel, int id, int userId)1171     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1172             int userId) {
1173         return generateNotificationRecord(channel, id, userId, "foo");
1174     }
1175 
generateNotificationRecord(NotificationChannel channel, int id, int userId, String title)1176     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1177             int userId, String title) {
1178         if (channel == null) {
1179             channel = mTestNotificationChannel;
1180         }
1181         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1182                 .setContentTitle(title)
1183                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1184         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0,
1185                 nb.build(), new UserHandle(userId), null, 0);
1186         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
1187         return r;
1188     }
1189 
generateMessageBubbleNotifRecord(NotificationChannel channel, String tag)1190     private NotificationRecord generateMessageBubbleNotifRecord(NotificationChannel channel,
1191             String tag) {
1192         return generateMessageBubbleNotifRecord(true, channel, 1, tag, null, false, true);
1193     }
1194 
generateMessageBubbleNotifRecord(boolean addMetadata, NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, boolean mutable)1195     private NotificationRecord generateMessageBubbleNotifRecord(boolean addMetadata,
1196             NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary,
1197             boolean mutable) {
1198         if (channel == null) {
1199             channel = mTestNotificationChannel;
1200         }
1201         if (tag == null) {
1202             tag = "tag";
1203         }
1204         Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey,
1205                 isSummary, mutable);
1206         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id,
1207                 tag, mUid, 0,
1208                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1209         return new NotificationRecord(mContext, sbn, channel);
1210     }
1211 
generateRedactedSbn(NotificationChannel channel, int id, int userId)1212     private StatusBarNotification generateRedactedSbn(NotificationChannel channel, int id,
1213             int userId) {
1214         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1215                 .setContentTitle("foo")
1216                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1217                 .setContentText(REDACTED_TEXT);
1218         return new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0,
1219                 nb.build(), new UserHandle(userId), null, 0);
1220     }
1221 
getSignalExtractorSideEffects()1222     private Map<String, Answer> getSignalExtractorSideEffects() {
1223         Map<String, Answer> answers = new ArrayMap<>();
1224 
1225         answers.put("override group key", invocationOnMock -> {
1226             ((NotificationRecord) invocationOnMock.getArguments()[0])
1227                     .setOverrideGroupKey("bananas");
1228             return null;
1229         });
1230         answers.put("override people", invocationOnMock -> {
1231             ((NotificationRecord) invocationOnMock.getArguments()[0])
1232                     .setPeopleOverride(new ArrayList<>());
1233             return null;
1234         });
1235         answers.put("snooze criteria", invocationOnMock -> {
1236             ((NotificationRecord) invocationOnMock.getArguments()[0])
1237                     .setSnoozeCriteria(new ArrayList<>());
1238             return null;
1239         });
1240         answers.put("notification channel", invocationOnMock -> {
1241             ((NotificationRecord) invocationOnMock.getArguments()[0])
1242                     .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW));
1243             return null;
1244         });
1245         answers.put("badging", invocationOnMock -> {
1246             NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
1247             r.setShowBadge(!r.canShowBadge());
1248             return null;
1249         });
1250         answers.put("bubbles", invocationOnMock -> {
1251             NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
1252             r.setAllowBubble(!r.canBubble());
1253             return null;
1254         });
1255         answers.put("package visibility", invocationOnMock -> {
1256             ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride(
1257                     Notification.VISIBILITY_SECRET);
1258             return null;
1259         });
1260 
1261         return answers;
1262     }
1263 
getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary, boolean mutable)1264     private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata,
1265             String groupKey, boolean isSummary, boolean mutable) {
1266         // Give it a person
1267         Person person = new Person.Builder()
1268                 .setName("bubblebot")
1269                 .build();
1270         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
1271         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
1272         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
1273                 mutable ? mActivityIntent : mActivityIntentImmutable).addRemoteInput(remoteInput)
1274                 .build();
1275         // Make it messaging style
1276         Notification.Builder nb = new Notification.Builder(mContext,
1277                 mTestNotificationChannel.getId())
1278                 .setContentTitle("foo")
1279                 .setStyle(new Notification.MessagingStyle(person)
1280                         .setConversationTitle("Bubble Chat")
1281                         .addMessage("Hello?",
1282                                 SystemClock.currentThreadTimeMillis() - 300000, person)
1283                         .addMessage("Is it me you're looking for?",
1284                                 SystemClock.currentThreadTimeMillis(), person)
1285                 )
1286                 .setActions(replyAction)
1287                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1288                 .setShortcutId(VALID_CONVO_SHORTCUT_ID)
1289                 .setGroupSummary(isSummary);
1290         if (groupKey != null) {
1291             nb.setGroup(groupKey);
1292         }
1293         if (addBubbleMetadata) {
1294             nb.setBubbleMetadata(getBubbleMetadata());
1295         }
1296         return nb;
1297     }
1298 
getBubbleMetadata()1299     private Notification.BubbleMetadata getBubbleMetadata() {
1300         ActivityInfo info = new ActivityInfo();
1301         info.resizeMode = RESIZE_MODE_RESIZEABLE;
1302         ResolveInfo ri = new ResolveInfo();
1303         ri.activityInfo = info;
1304         when(mPackageManagerClient.resolveActivityAsUser(any(), anyInt(), anyInt())).thenReturn(ri);
1305 
1306         return new Notification.BubbleMetadata.Builder(
1307                 mActivityIntent,
1308                 Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon))
1309                 .build();
1310     }
1311 
addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)1312     private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)
1313             throws RemoteException {
1314 
1315         String groupKey = "BUBBLE_GROUP";
1316 
1317         // Notification that has bubble metadata
1318         NotificationRecord nrBubble = generateMessageBubbleNotifRecord(true /* addMetadata */,
1319                 mTestNotificationChannel, 1 /* id */, "tag", groupKey, false /* isSummary */,
1320                 true);
1321 
1322         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrBubble.getSbn().getTag(),
1323                 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(),
1324                 nrBubble.getSbn().getUserId());
1325         waitForIdle();
1326 
1327         // Make sure we are a bubble
1328         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
1329         assertEquals(1, notifsAfter.length);
1330         assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
1331 
1332         // Notification without bubble metadata
1333         NotificationRecord nrPlain = generateMessageBubbleNotifRecord(false /* addMetadata */,
1334                 mTestNotificationChannel, 2 /* id */, "tag", groupKey, false /* isSummary */,
1335                 true);
1336 
1337         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrPlain.getSbn().getTag(),
1338                 nrPlain.getSbn().getId(), nrPlain.getSbn().getNotification(),
1339                 nrPlain.getSbn().getUserId());
1340         waitForIdle();
1341 
1342         notifsAfter = mBinderService.getActiveNotifications(mPkg);
1343         assertEquals(2, notifsAfter.length);
1344 
1345         // Summary notification for both of those
1346         NotificationRecord nrSummary = generateMessageBubbleNotifRecord(false /* addMetadata */,
1347                 mTestNotificationChannel, 3 /* id */, "tag", groupKey, true /* isSummary */,
1348                 true);
1349 
1350         if (summaryAutoCancel) {
1351             nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL;
1352         }
1353         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrSummary.getSbn().getTag(),
1354                 nrSummary.getSbn().getId(), nrSummary.getSbn().getNotification(),
1355                 nrSummary.getSbn().getUserId());
1356         waitForIdle();
1357 
1358         notifsAfter = mBinderService.getActiveNotifications(mPkg);
1359         assertEquals(3, notifsAfter.length);
1360 
1361         return nrSummary;
1362     }
1363 
createAndPostCallStyleNotification(String packageName, UserHandle userHandle, String testName)1364     private NotificationRecord createAndPostCallStyleNotification(String packageName,
1365             UserHandle userHandle, String testName) throws Exception {
1366         Person person = new Person.Builder().setName("caller").build();
1367         Notification.Builder nb = new Notification.Builder(mContext,
1368                 mTestNotificationChannel.getId())
1369                 .setFlag(FLAG_USER_INITIATED_JOB, true)
1370                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
1371                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1372         StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1,
1373                 testName, mUid, 0, nb.build(), userHandle, null, 0);
1374         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
1375 
1376         mService.addEnqueuedNotification(r);
1377         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1378                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run();
1379         waitForIdle();
1380 
1381         return mService.findNotificationLocked(
1382                 packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId());
1383     }
1384 
createAndPostNotification(Notification.Builder nb, String testName)1385     private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
1386             throws RemoteException {
1387         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0,
1388                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1389         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
1390 
1391         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1392                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1393         waitForIdle();
1394 
1395         return mService.findNotificationLocked(
1396                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
1397     }
1398 
parcelAndUnparcel(T source, Parcelable.Creator<T> creator)1399     private static <T extends Parcelable> T parcelAndUnparcel(T source,
1400             Parcelable.Creator<T> creator) {
1401         Parcel parcel = Parcel.obtain();
1402         source.writeToParcel(parcel, 0);
1403         parcel.setDataPosition(0);
1404         return creator.createFromParcel(parcel);
1405     }
1406 
createPendingIntent(String action)1407     private PendingIntent createPendingIntent(String action) {
1408         return PendingIntent.getActivity(mContext, 0,
1409                 new Intent(action).setPackage(mContext.getPackageName()),
1410                 PendingIntent.FLAG_MUTABLE);
1411     }
1412 
allowTestPackageToToast()1413     private void allowTestPackageToToast() throws Exception {
1414         assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty();
1415         mService.isSystemUid = false;
1416         mService.isSystemAppId = false;
1417         setToastRateIsWithinQuota(true);
1418         setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false);
1419         // package is not suspended
1420         when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId))
1421                 .thenReturn(false);
1422     }
1423 
enqueueToast(String testPackage, ITransientNotification callback)1424     private boolean enqueueToast(String testPackage, ITransientNotification callback)
1425             throws RemoteException {
1426         return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(),
1427                 callback);
1428     }
1429 
enqueueToast(INotificationManager service, String testPackage, IBinder token, ITransientNotification callback)1430     private boolean enqueueToast(INotificationManager service, String testPackage,
1431             IBinder token, ITransientNotification callback) throws RemoteException {
1432         return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */
1433                 true, DEFAULT_DISPLAY);
1434     }
1435 
enqueueTextToast(String testPackage, CharSequence text)1436     private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException {
1437         return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY);
1438     }
1439 
enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, int displayId)1440     private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext,
1441             int displayId) throws RemoteException {
1442         return ((INotificationManager) mService.mService).enqueueTextToast(testPackage,
1443                 new Binder(), text, TOAST_DURATION, isUiContext, displayId,
1444                 /* textCallback= */ null);
1445     }
1446 
mockIsVisibleBackgroundUsersSupported(boolean supported)1447     private void mockIsVisibleBackgroundUsersSupported(boolean supported) {
1448         when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported);
1449     }
1450 
mockIsUserVisible(int displayId, boolean visible)1451     private void mockIsUserVisible(int displayId, boolean visible) {
1452         when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible);
1453     }
1454 
mockDisplayAssignedToUser(int displayId)1455     private void mockDisplayAssignedToUser(int displayId) {
1456         when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId);
1457     }
1458 
verifyToastShownForTestPackage(String text, int displayId)1459     private void verifyToastShownForTestPackage(String text, int displayId) {
1460         verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(),
1461                 eq(TOAST_DURATION), any(), eq(displayId));
1462     }
1463 
1464     @Test
1465     @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
testLimitTimeOutBroadcast()1466     public void testLimitTimeOutBroadcast() {
1467         NotificationChannel channel = new NotificationChannel("id", "name",
1468                 NotificationManager.IMPORTANCE_HIGH);
1469         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1470                 .setContentTitle("foo")
1471                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1472                 .setTimeoutAfter(1);
1473 
1474         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
1475                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1476         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
1477 
1478         mService.scheduleTimeoutLocked(r);
1479         ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
1480         verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture());
1481         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
1482                 captor.getValue().getIntent().getPackage());
1483 
1484         mService.cancelScheduledTimeoutLocked(r);
1485         verify(mAlarmManager).cancel(captor.capture());
1486         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
1487                 captor.getValue().getIntent().getPackage());
1488     }
1489 
1490     @Test
testDefaultAssistant_overrideDefault()1491     public void testDefaultAssistant_overrideDefault() {
1492         final int userId = mContext.getUserId();
1493         final String testComponent = "package/class";
1494         final List<UserInfo> userInfos = new ArrayList<>();
1495         userInfos.add(new UserInfo(userId, "", 0));
1496         final ArraySet<ComponentName> validAssistants = new ArraySet<>();
1497         validAssistants.add(ComponentName.unflattenFromString(testComponent));
1498         when(mActivityManager.isLowRamDevice()).thenReturn(false);
1499         when(mAssistants.queryPackageForServices(isNull(), anyInt(), anyInt()))
1500                 .thenReturn(validAssistants);
1501         when(mAssistants.getDefaultComponents()).thenReturn(validAssistants);
1502         when(mUm.getEnabledProfiles(anyInt())).thenReturn(userInfos);
1503 
1504         mService.setDefaultAssistantForUser(userId);
1505 
1506         verify(mAssistants).setPackageOrComponentEnabled(
1507                 eq(testComponent), eq(userId), eq(true), eq(true), eq(false));
1508     }
1509 
1510     @Test
testCreateNotificationChannels_SingleChannel()1511     public void testCreateNotificationChannels_SingleChannel() throws Exception {
1512         final NotificationChannel channel =
1513                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1514         mBinderService.createNotificationChannels(mPkg,
1515                 new ParceledListSlice(Arrays.asList(channel)));
1516         final NotificationChannel createdChannel =
1517                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1518         assertTrue(createdChannel != null);
1519     }
1520 
1521     @Test
testCreateNotificationChannels_NullChannelThrowsException()1522     public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
1523         try {
1524             mBinderService.createNotificationChannels(mPkg,
1525                     new ParceledListSlice(Arrays.asList((Object[])null)));
1526             fail("Exception should be thrown immediately.");
1527         } catch (NullPointerException e) {
1528             // pass
1529         }
1530     }
1531 
1532     @Test
testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()1533     public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()
1534             throws Exception {
1535         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1536         final NotificationChannel channel =
1537                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1538         mBinderService.createNotificationChannels(PKG_NO_CHANNELS,
1539                 new ParceledListSlice(Arrays.asList(channel)));
1540         verify(mWorkerHandler).post(eq(new NotificationManagerService
1541                 .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS,
1542                 mUserId, TEST_TASK_ID, mPermissionPolicyInternal)));
1543     }
1544 
1545     @Test
testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()1546     public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()
1547             throws Exception {
1548         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1549         assertTrue(mBinderService.getNumNotificationChannelsForPackage(mPkg, mUid, true) > 0);
1550 
1551         final NotificationChannel channel =
1552                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1553         mBinderService.createNotificationChannels(mPkg,
1554                 new ParceledListSlice(Arrays.asList(channel)));
1555         verify(mWorkerHandler, never()).post(any(
1556                 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class));
1557     }
1558 
1559     @Test
testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()1560     public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()
1561             throws Exception {
1562         reset(mPermissionPolicyInternal);
1563         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1564 
1565         final NotificationChannel channel =
1566                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1567         mBinderService.createNotificationChannels(mPkg,
1568                 new ParceledListSlice(Arrays.asList(channel)));
1569 
1570         verify(mWorkerHandler, never()).post(any(
1571                 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class));
1572     }
1573 
1574     @Test
testCreateNotificationChannels_TwoChannels()1575     public void testCreateNotificationChannels_TwoChannels() throws Exception {
1576         final NotificationChannel channel1 =
1577                 new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT);
1578         final NotificationChannel channel2 =
1579                 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
1580         mBinderService.createNotificationChannels(mPkg,
1581                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
1582         assertTrue(mBinderService.getNotificationChannel(
1583                 mPkg, mContext.getUserId(), mPkg, "id1") != null);
1584         assertTrue(mBinderService.getNotificationChannel(
1585                 mPkg, mContext.getUserId(), mPkg, "id2") != null);
1586     }
1587 
1588     @Test
testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()1589     public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
1590             throws Exception {
1591         final NotificationChannel channel =
1592                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1593         mBinderService.createNotificationChannels(mPkg,
1594                 new ParceledListSlice(Arrays.asList(channel)));
1595 
1596         // Recreating the channel doesn't throw, but ignores importance.
1597         final NotificationChannel dupeChannel =
1598                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1599         mBinderService.createNotificationChannels(mPkg,
1600                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1601         final NotificationChannel createdChannel =
1602                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1603         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
1604     }
1605 
1606     @Test
testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()1607     public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()
1608             throws Exception {
1609         final NotificationChannel channel =
1610                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1611         mBinderService.createNotificationChannels(mPkg,
1612                 new ParceledListSlice(Arrays.asList(channel)));
1613 
1614         // Recreating with a lower importance is allowed to modify the channel.
1615         final NotificationChannel dupeChannel =
1616                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
1617         mBinderService.createNotificationChannels(mPkg,
1618                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1619         final NotificationChannel createdChannel =
1620                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1621         assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
1622     }
1623 
1624     @Test
testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()1625     public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()
1626             throws Exception {
1627         final NotificationChannel channel =
1628                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1629         mBinderService.createNotificationChannels(mPkg,
1630                 new ParceledListSlice(Arrays.asList(channel)));
1631 
1632         // The user modifies importance directly, can no longer be changed by the app.
1633         final NotificationChannel updatedChannel =
1634                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1635         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, updatedChannel);
1636 
1637         // Recreating with a lower importance leaves channel unchanged.
1638         final NotificationChannel dupeChannel =
1639                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
1640         mBinderService.createNotificationChannels(mPkg,
1641                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1642         final NotificationChannel createdChannel =
1643                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1644         assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
1645     }
1646 
1647     @Test
testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()1648     public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
1649             throws Exception {
1650         final NotificationChannel channel1 =
1651                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1652         final NotificationChannel channel2 =
1653                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1654         mBinderService.createNotificationChannels(mPkg,
1655                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
1656         final NotificationChannel createdChannel =
1657                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1658         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
1659     }
1660 
1661     @Test
testBlockedNotifications_suspended()1662     public void testBlockedNotifications_suspended() throws Exception {
1663         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
1664 
1665         NotificationChannel channel = new NotificationChannel("id", "name",
1666                 IMPORTANCE_HIGH);
1667         NotificationRecord r = generateNotificationRecord(channel);
1668 
1669         // isBlocked is only used for user blocking, not app suspension
1670         assertFalse(mService.isRecordBlockedLocked(r));
1671     }
1672 
1673     @Test
testBlockedNotifications_blockedChannel()1674     public void testBlockedNotifications_blockedChannel() throws Exception {
1675         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1676 
1677         NotificationChannel channel = new NotificationChannel("id", "name",
1678                 NotificationManager.IMPORTANCE_NONE);
1679         NotificationRecord r = generateNotificationRecord(channel);
1680         assertTrue(mService.isRecordBlockedLocked(r));
1681 
1682         mBinderService.createNotificationChannels(
1683                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1684         final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1685         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1686                 "testBlockedNotifications_blockedChannel",
1687                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1688         waitForIdle();
1689         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1690     }
1691 
1692     @Test
testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()1693     public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()
1694             throws Exception {
1695         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1696         when(mAmi.applyForegroundServiceNotification(
1697                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1698 
1699         NotificationChannel channel = new NotificationChannel("blocked", "name",
1700                 NotificationManager.IMPORTANCE_NONE);
1701         mBinderService.createNotificationChannels(
1702                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1703 
1704         final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1705         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1706         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1707                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1708         waitForIdle();
1709         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1710         assertEquals(IMPORTANCE_LOW,
1711                 mService.getNotificationRecord(sbn.getKey()).getImportance());
1712         assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
1713                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1714     }
1715 
1716     @Test
testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()1717     public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()
1718             throws Exception {
1719         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1720         when(mAmi.applyForegroundServiceNotification(
1721                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1722 
1723         NotificationChannel channel =
1724                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH);
1725         mBinderService.createNotificationChannels(
1726                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1727 
1728         NotificationChannel update =
1729                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
1730         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update);
1731         waitForIdle();
1732         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1733                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1734 
1735         StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1736         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1737         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1738                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1739         waitForIdle();
1740         // The first time a foreground service notification is shown, we allow the channel
1741         // to be updated to allow it to be seen.
1742         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1743         assertEquals(IMPORTANCE_LOW,
1744                 mService.getNotificationRecord(sbn.getKey()).getImportance());
1745         assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
1746                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1747         mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId());
1748         waitForIdle();
1749 
1750         update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
1751         update.setUserVisibleTaskShown(true);
1752         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update);
1753         waitForIdle();
1754         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1755                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1756 
1757         sbn = generateNotificationRecord(channel).getSbn();
1758         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1759         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1760                 "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService",
1761                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1762         waitForIdle();
1763         // The second time it is shown, we keep the user's preference.
1764         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1765         assertNull(mService.getNotificationRecord(sbn.getKey()));
1766         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1767                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1768     }
1769 
1770     @Test
testBlockedNotifications_blockedChannelGroup()1771     public void testBlockedNotifications_blockedChannelGroup() throws Exception {
1772         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1773         mService.setPreferencesHelper(mPreferencesHelper);
1774         when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())).
1775                 thenReturn(true);
1776 
1777         NotificationChannel channel = new NotificationChannel("id", "name",
1778                 NotificationManager.IMPORTANCE_HIGH);
1779         channel.setGroup("something");
1780         NotificationRecord r = generateNotificationRecord(channel);
1781         assertTrue(mService.isRecordBlockedLocked(r));
1782     }
1783 
1784     @Test
testEnqueuedBlockedNotifications_blockedApp()1785     public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
1786         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1787         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1788 
1789         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1790         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1791                 "testEnqueuedBlockedNotifications_blockedApp",
1792                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1793         waitForIdle();
1794         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1795     }
1796 
1797     @Test
testEnqueuedBlockedNotifications_blockedAppForegroundService()1798     public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
1799         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1800         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1801         when(mAmi.applyForegroundServiceNotification(
1802                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1803 
1804         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1805         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1806         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1807                 "testEnqueuedBlockedNotifications_blockedAppForegroundService",
1808                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1809         waitForIdle();
1810         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1811         assertNull(mService.getNotificationRecord(sbn.getKey()));
1812     }
1813 
1814     /**
1815      * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive
1816      * devices can use car categories.
1817      */
1818     @Test
testEnqueuedRestrictedNotifications_hasPermission()1819     public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception {
1820         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1821                 .thenReturn(true);
1822         // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot
1823         // obtain. Mocking out enforce permission call to ensure notifications can be created when
1824         // permitted.
1825         doNothing().when(mContext).enforceCallingPermission(
1826                 eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString());
1827         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1828                 Notification.CATEGORY_CAR_WARNING,
1829                 Notification.CATEGORY_CAR_INFORMATION);
1830         int id = 0;
1831         for (String category: categories) {
1832             final StatusBarNotification sbn =
1833                     generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn();
1834             sbn.getNotification().category = category;
1835             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1836                     "testEnqueuedRestrictedNotifications_asSystem",
1837                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
1838         }
1839         waitForIdle();
1840         assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length);
1841     }
1842 
1843 
1844     /**
1845      * Confirm restricted notification categories only apply to automotive.
1846      */
1847     @Test
testEnqueuedRestrictedNotifications_notAutomotive()1848     public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception {
1849         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1850                 .thenReturn(false);
1851         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1852                 Notification.CATEGORY_CAR_WARNING,
1853                 Notification.CATEGORY_CAR_INFORMATION);
1854         int id = 0;
1855         for (String category: categories) {
1856             final StatusBarNotification sbn =
1857                     generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn();
1858             sbn.getNotification().category = category;
1859             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1860                     "testEnqueuedRestrictedNotifications_notAutomotive",
1861                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
1862         }
1863         waitForIdle();
1864         assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length);
1865     }
1866 
1867     /**
1868      * Confirm if an application tries to use the car categories on a automotive device without the
1869      * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown.
1870      */
1871     @Test
testEnqueuedRestrictedNotifications_noPermission()1872     public void testEnqueuedRestrictedNotifications_noPermission() throws Exception {
1873         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1874                 .thenReturn(true);
1875         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1876                 Notification.CATEGORY_CAR_WARNING,
1877                 Notification.CATEGORY_CAR_INFORMATION);
1878         for (String category: categories) {
1879             final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1880             sbn.getNotification().category = category;
1881             try {
1882                 mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1883                         "testEnqueuedRestrictedNotifications_badUser",
1884                         sbn.getId(), sbn.getNotification(), sbn.getUserId());
1885                 fail("Calls from non system apps should not allow use of restricted categories");
1886             } catch (SecurityException e) {
1887                 // pass
1888             }
1889         }
1890         waitForIdle();
1891         assertEquals(0, mBinderService.getActiveNotifications(mPkg).length);
1892     }
1893 
1894     @Test
testSetNotificationsEnabledForPackage_noChange()1895     public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
1896         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1897         mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
1898 
1899         verify(mPermissionHelper, never()).setNotificationPermission(
1900                 anyString(), anyInt(), anyBoolean(), anyBoolean());
1901     }
1902 
1903     @Test
testSetNotificationsEnabledForPackage()1904     public void testSetNotificationsEnabledForPackage() throws Exception {
1905         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1906         mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
1907 
1908         verify(mPermissionHelper).setNotificationPermission(
1909                 mContext.getPackageName(), mUserId, false, true);
1910 
1911         verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
1912         List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls();
1913         Assert.assertEquals(
1914                 NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
1915                 calls.get(calls.size() -1).event);
1916     }
1917 
1918     @Test
testBlockedNotifications_blockedByAssistant()1919     public void testBlockedNotifications_blockedByAssistant() throws Exception {
1920         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1921         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
1922 
1923         NotificationChannel channel = new NotificationChannel("id", "name",
1924                 NotificationManager.IMPORTANCE_HIGH);
1925         NotificationRecord r = generateNotificationRecord(channel);
1926         mService.addEnqueuedNotification(r);
1927 
1928         Bundle bundle = new Bundle();
1929         bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE);
1930         Adjustment adjustment = new Adjustment(
1931                 r.getSbn().getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier());
1932         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
1933 
1934         NotificationManagerService.PostNotificationRunnable runnable =
1935                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1936                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
1937         runnable.run();
1938         waitForIdle();
1939 
1940         verify(mUsageStats, never()).registerPostedByApp(any());
1941     }
1942 
1943     @Test
testBlockedNotifications_blockedByUser()1944     public void testBlockedNotifications_blockedByUser() throws Exception {
1945         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1946         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
1947 
1948         NotificationChannel channel = new NotificationChannel("id", "name",
1949                 NotificationManager.IMPORTANCE_HIGH);
1950         NotificationRecord r = generateNotificationRecord(channel);
1951         mService.addEnqueuedNotification(r);
1952 
1953         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
1954 
1955         NotificationManagerService.PostNotificationRunnable runnable =
1956                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1957                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
1958         runnable.run();
1959         waitForIdle();
1960 
1961         verify(mUsageStats).registerBlocked(any());
1962         verify(mUsageStats, never()).registerPostedByApp(any());
1963     }
1964 
1965     @Test
testEnqueueNotificationInternal_noChannel()1966     public void testEnqueueNotificationInternal_noChannel() throws Exception {
1967         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1968         NotificationRecord nr = generateNotificationRecord(
1969                 new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
1970 
1971         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
1972                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1973         waitForIdle();
1974 
1975         verify(mPermissionHelper).hasPermission(mUid);
1976         verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
1977 
1978         reset(mPermissionHelper);
1979         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1980 
1981         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
1982                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1983         waitForIdle();
1984 
1985         verify(mPermissionHelper).hasPermission(mUid);
1986         assertThat(mService.mChannelToastsSent).contains(mUid);
1987     }
1988 
1989     @Test
testEnqueueNotification_appBlocked()1990     public void testEnqueueNotification_appBlocked() throws Exception {
1991         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1992 
1993         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1994                 "testEnqueueNotification_appBlocked", 0,
1995                 generateNotificationRecord(null).getNotification(), mUserId);
1996         waitForIdle();
1997         verify(mWorkerHandler, never()).post(
1998                 any(NotificationManagerService.EnqueueNotificationRunnable.class));
1999     }
2000 
2001     @Test
testEnqueueNotificationWithTag_PopulatesGetActiveNotifications()2002     public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
2003         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2004                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2005                 generateNotificationRecord(null).getNotification(), mUserId);
2006         waitForIdle();
2007         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
2008         assertEquals(1, notifs.length);
2009         assertEquals(1, mService.getNotificationRecordCount());
2010     }
2011 
2012     @Test
testEnqueueNotificationWithTag_WritesExpectedLogs()2013     public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception {
2014         final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog";
2015         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2016                 generateNotificationRecord(null).getNotification(), mUserId);
2017         waitForIdle();
2018         assertEquals(1, mNotificationRecordLogger.numCalls());
2019 
2020         NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0);
2021         assertTrue(call.wasLogged);
2022         assertEquals(NOTIFICATION_POSTED, call.event);
2023         assertNotNull(call.r);
2024         assertNull(call.old);
2025         assertEquals(0, call.position);
2026         assertEquals(0, call.buzzBeepBlink);
2027         assertEquals(mPkg, call.r.getSbn().getPackageName());
2028         assertEquals(0, call.r.getSbn().getId());
2029         assertEquals(tag, call.r.getSbn().getTag());
2030         assertEquals(1, call.getInstanceId());  // Fake instance IDs are assigned in order
2031         assertThat(call.postDurationMillisLogged).isGreaterThan(0);
2032     }
2033 
2034     @Test
testEnqueueNotificationWithTag_LogsOnMajorUpdates()2035     public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception {
2036         final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates";
2037         Notification original = new Notification.Builder(mContext,
2038                 mTestNotificationChannel.getId())
2039                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
2040         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, original, mUserId);
2041         Notification update = new Notification.Builder(mContext,
2042                 mTestNotificationChannel.getId())
2043                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2044                 .setCategory(Notification.CATEGORY_ALARM).build();
2045         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, update, mUserId);
2046         waitForIdle();
2047         assertEquals(2, mNotificationRecordLogger.numCalls());
2048 
2049         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2050         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2051         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
2052         assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0);
2053 
2054         assertTrue(mNotificationRecordLogger.get(1).wasLogged);
2055         assertEquals(NOTIFICATION_UPDATED, mNotificationRecordLogger.event(1));
2056         // Instance ID doesn't change on update of an active notification
2057         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
2058         assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isGreaterThan(0);
2059     }
2060 
2061     @Test
testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate()2062     public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception {
2063         final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate";
2064         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2065                 generateNotificationRecord(null).getNotification(), mUserId);
2066         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2067                 generateNotificationRecord(null).getNotification(), mUserId);
2068         waitForIdle();
2069         assertEquals(2, mNotificationRecordLogger.numCalls());
2070         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2071         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2072         assertFalse(mNotificationRecordLogger.get(1).wasLogged);
2073         assertNull(mNotificationRecordLogger.event(1));
2074     }
2075 
2076     @Test
testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate()2077     public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception {
2078         final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate";
2079         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2080                 generateNotificationRecord(null).getNotification(),
2081                 mUserId);
2082         final Notification notif = generateNotificationRecord(null).getNotification();
2083         notif.extras.putString(Notification.EXTRA_TITLE, "Changed title");
2084         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notif, mUserId);
2085         waitForIdle();
2086         assertEquals(2, mNotificationRecordLogger.numCalls());
2087         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2088         assertNull(mNotificationRecordLogger.event(1));
2089     }
2090 
2091     @Test
testEnqueueNotificationWithTag_LogsAgainAfterCancel()2092     public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception {
2093         final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel";
2094         Notification notification = new Notification.Builder(mContext,
2095                 mTestNotificationChannel.getId())
2096                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
2097         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId);
2098         waitForIdle();
2099         mBinderService.cancelNotificationWithTag(mPkg, mPkg, tag, 0, mUserId);
2100         waitForIdle();
2101         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId);
2102         waitForIdle();
2103         assertEquals(3, mNotificationRecordLogger.numCalls());
2104 
2105         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2106         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2107         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
2108         assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0);
2109 
2110         assertEquals(
2111                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
2112                 mNotificationRecordLogger.event(1));
2113         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
2114         // Cancel is not post, so no logged post_duration_millis.
2115         assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isNull();
2116 
2117         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(2));
2118         assertTrue(mNotificationRecordLogger.get(2).wasLogged);
2119         // New instance ID because notification was canceled before re-post
2120         assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId());
2121         assertThat(mNotificationRecordLogger.get(2).postDurationMillisLogged).isGreaterThan(0);
2122     }
2123 
2124     @Test
testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed()2125     public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception {
2126         when(mAmi.applyForegroundServiceNotification(
2127                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
2128         mContext.getTestablePermissions().setPermission(
2129                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
2130 
2131         final String tag = "testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed";
2132 
2133         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2134                 .setContentTitle("foo")
2135                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2136                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
2137                 .build();
2138         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, tag, mUid, 0,
2139                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
2140         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag,
2141                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2142         waitForIdle();
2143 
2144         StatusBarNotification[] notifs =
2145                 mBinderService.getActiveNotifications(mPkg);
2146         assertThat(notifs[0].getNotification().flags).isEqualTo(
2147                 FLAG_FOREGROUND_SERVICE | FLAG_CAN_COLORIZE | FLAG_NO_CLEAR);
2148     }
2149 
2150     @Test
testEnqueueNotificationWithTag_nullAction_fixed()2151     public void testEnqueueNotificationWithTag_nullAction_fixed() throws Exception {
2152         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2153                 .setContentTitle("foo")
2154                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2155                 .addAction(new Notification.Action.Builder(null, "one", null).build())
2156                 .addAction(new Notification.Action.Builder(null, "two", null).build())
2157                 .addAction(new Notification.Action.Builder(null, "three", null).build())
2158                 .build();
2159         n.actions[1] = null;
2160 
2161         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
2162         waitForIdle();
2163 
2164         StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg);
2165         assertThat(posted).hasLength(1);
2166         assertThat(posted[0].getNotification().actions).hasLength(2);
2167         assertThat(posted[0].getNotification().actions[0].title.toString()).isEqualTo("one");
2168         assertThat(posted[0].getNotification().actions[1].title.toString()).isEqualTo("three");
2169     }
2170 
2171     @Test
testEnqueueNotificationWithTag_allNullActions_fixed()2172     public void testEnqueueNotificationWithTag_allNullActions_fixed() throws Exception {
2173         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2174                 .setContentTitle("foo")
2175                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2176                 .addAction(new Notification.Action.Builder(null, "one", null).build())
2177                 .addAction(new Notification.Action.Builder(null, "two", null).build())
2178                 .build();
2179         n.actions[0] = null;
2180         n.actions[1] = null;
2181 
2182         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
2183         waitForIdle();
2184 
2185         StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg);
2186         assertThat(posted).hasLength(1);
2187         assertThat(posted[0].getNotification().actions).isNull();
2188     }
2189 
2190     @Test
enqueueNotificationWithTag_usesAndFinishesTracker()2191     public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception {
2192         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2193                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2194                 generateNotificationRecord(null).getNotification(), mUserId);
2195 
2196         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2197         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue();
2198 
2199         waitForIdle();
2200 
2201         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(1);
2202         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2203         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2204     }
2205 
2206     @Test
enqueueNotificationWithTag_throws_usesAndCancelsTracker()2207     public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception {
2208         // Simulate not enqueued due to rejected inputs.
2209         assertThrows(Exception.class,
2210                 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2211                         "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2212                         /* notification= */ null, mUserId));
2213 
2214         waitForIdle();
2215 
2216         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2217         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2218         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2219     }
2220 
2221     @Test
enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker()2222     public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception {
2223         // Simulate not enqueued due to snoozing inputs.
2224         when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
2225                 .thenReturn("zzzzzzz");
2226 
2227         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2228                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2229                 generateNotificationRecord(null).getNotification(), mUserId);
2230         waitForIdle();
2231 
2232         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2233         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2234         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2235     }
2236 
2237     @Test
enqueueNotificationWithTag_notPosted_usesAndCancelsTracker()2238     public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception {
2239         // Simulate not posted due to blocked app.
2240         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
2241 
2242         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2243                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2244                 generateNotificationRecord(null).getNotification(), mUserId);
2245         waitForIdle();
2246 
2247         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2248         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2249         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2250     }
2251 
2252     @Test
enqueueNotification_acquiresAndReleasesWakeLock()2253     public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception {
2254         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2255                 "enqueueNotification_acquiresAndReleasesWakeLock", 0,
2256                 generateNotificationRecord(null).getNotification(), mUserId);
2257 
2258         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2259         assertThat(mAcquiredWakeLocks).hasSize(1);
2260         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2261 
2262         waitForIdle();
2263 
2264         assertThat(mAcquiredWakeLocks).hasSize(1);
2265         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2266     }
2267 
2268     @Test
enqueueNotification_throws_acquiresAndReleasesWakeLock()2269     public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception {
2270         // Simulate not enqueued due to rejected inputs.
2271         assertThrows(Exception.class,
2272                 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2273                         "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0,
2274                         /* notification= */ null, mUserId));
2275 
2276         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2277         assertThat(mAcquiredWakeLocks).hasSize(1);
2278         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2279     }
2280 
2281     @Test
enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock()2282     public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception {
2283         // Simulate not enqueued due to snoozing inputs.
2284         when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
2285                 .thenReturn("zzzzzzz");
2286 
2287         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2288                 "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0,
2289                 generateNotificationRecord(null).getNotification(), mUserId);
2290 
2291         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2292         assertThat(mAcquiredWakeLocks).hasSize(1);
2293         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2294 
2295         waitForIdle();
2296 
2297         assertThat(mAcquiredWakeLocks).hasSize(1);
2298         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2299     }
2300 
2301     @Test
enqueueNotification_notPosted_acquiresAndReleasesWakeLock()2302     public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception {
2303         // Simulate enqueued but not posted due to missing small icon.
2304         Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2305                 .setContentTitle("foo")
2306                 .build();
2307 
2308         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2309                 "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0,
2310                 notif, mUserId);
2311 
2312         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2313         assertThat(mAcquiredWakeLocks).hasSize(1);
2314         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2315 
2316         waitForIdle();
2317 
2318         // NLSes were not called.
2319         verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean());
2320 
2321         assertThat(mAcquiredWakeLocks).hasSize(1);
2322         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2323     }
2324 
2325     @Test
enqueueNotification_setsWakeLockWorkSource()2326     public void enqueueNotification_setsWakeLockWorkSource() throws Exception {
2327         // Use a "full" mock for the PowerManager (instead of the one that delegates to the real
2328         // service) so we can return a mocked WakeLock that we can verify() on.
2329         reset(mPowerManager);
2330         WakeLock wakeLock = mock(WakeLock.class);
2331         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock);
2332 
2333         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2334                 "enqueueNotification_setsWakeLockWorkSource", 0,
2335                 generateNotificationRecord(null).getNotification(), mUserId);
2336         waitForIdle();
2337 
2338         InOrder inOrder = inOrder(mPowerManager, wakeLock);
2339         inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2340         inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, mPkg)));
2341         inOrder.verify(wakeLock).acquire(anyLong());
2342         inOrder.verify(wakeLock).release();
2343         inOrder.verifyNoMoreInteractions();
2344     }
2345 
2346     @Test
testCancelNonexistentNotification()2347     public void testCancelNonexistentNotification() throws Exception {
2348         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2349                 "testCancelNonexistentNotification", 0, mUserId);
2350         waitForIdle();
2351         // The notification record logger doesn't even get called when a nonexistent notification
2352         // is cancelled, because that happens very frequently and is not interesting.
2353         assertEquals(0, mNotificationRecordLogger.numCalls());
2354     }
2355 
2356     @Test
testCancelNotificationImmediatelyAfterEnqueue()2357     public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
2358         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2359                 "testCancelNotificationImmediatelyAfterEnqueue", 0,
2360                 generateNotificationRecord(null).getNotification(), mUserId);
2361         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2362                 "testCancelNotificationImmediatelyAfterEnqueue", 0, mUserId);
2363         waitForIdle();
2364         StatusBarNotification[] notifs =
2365                 mBinderService.getActiveNotifications(mPkg);
2366         assertEquals(0, notifs.length);
2367         assertEquals(0, mService.getNotificationRecordCount());
2368     }
2369 
2370     @Test
testPostCancelPostNotifiesListeners()2371     public void testPostCancelPostNotifiesListeners() throws Exception {
2372         // WHEN a notification is posted
2373         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2374         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(),
2375                 sbn.getNotification(), sbn.getUserId());
2376         mTestableLooper.moveTimeForward(1);
2377         // THEN it is canceled
2378         mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId());
2379         mTestableLooper.moveTimeForward(1);
2380         // THEN it is posted again (before the cancel has a chance to finish)
2381         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(),
2382                 sbn.getNotification(), sbn.getUserId());
2383         // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected
2384         waitForIdle();
2385 
2386         // The final enqueue made it to the listener instead of being canceled
2387         StatusBarNotification[] notifs =
2388                 mBinderService.getActiveNotifications(mPkg);
2389         assertEquals(1, notifs.length);
2390         assertEquals(1, mService.getNotificationRecordCount());
2391     }
2392 
2393     @Test
testCancelNotificationWhilePostedAndEnqueued()2394     public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
2395         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2396                 "testCancelNotificationWhilePostedAndEnqueued", 0,
2397                 generateNotificationRecord(null).getNotification(), mUserId);
2398         waitForIdle();
2399         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2400                 "testCancelNotificationWhilePostedAndEnqueued", 0,
2401                 generateNotificationRecord(null).getNotification(), mUserId);
2402         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2403                 "testCancelNotificationWhilePostedAndEnqueued", 0, mUserId);
2404         waitForIdle();
2405         StatusBarNotification[] notifs =
2406                 mBinderService.getActiveNotifications(mPkg);
2407         assertEquals(0, notifs.length);
2408         assertEquals(0, mService.getNotificationRecordCount());
2409         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
2410         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
2411         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
2412     }
2413 
2414     @Test
testCancelNotificationsFromListenerImmediatelyAfterEnqueue()2415     public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
2416         NotificationRecord r = generateNotificationRecord(null);
2417         final StatusBarNotification sbn = r.getSbn();
2418         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2419                 "testCancelNotificationsFromListenerImmediatelyAfterEnqueue",
2420                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2421         mBinderService.cancelNotificationsFromListener(null, null);
2422         waitForIdle();
2423         StatusBarNotification[] notifs =
2424                 mBinderService.getActiveNotifications(sbn.getPackageName());
2425         assertEquals(0, notifs.length);
2426         assertEquals(0, mService.getNotificationRecordCount());
2427     }
2428 
2429     @Test
testCancelAllNotificationsImmediatelyAfterEnqueue()2430     public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
2431         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2432         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2433                 "testCancelAllNotificationsImmediatelyAfterEnqueue",
2434                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2435         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2436         waitForIdle();
2437         StatusBarNotification[] notifs =
2438                 mBinderService.getActiveNotifications(sbn.getPackageName());
2439         assertEquals(0, notifs.length);
2440         assertEquals(0, mService.getNotificationRecordCount());
2441     }
2442 
2443     @Test
testUserInitiatedClearAll_noLeak()2444     public void testUserInitiatedClearAll_noLeak() throws Exception {
2445         final NotificationRecord n = generateNotificationRecord(
2446                 mTestNotificationChannel, 1, "group", true);
2447 
2448         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2449                 "testUserInitiatedClearAll_noLeak",
2450                 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId());
2451         waitForIdle();
2452 
2453         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
2454                 n.getUserId());
2455         waitForIdle();
2456         StatusBarNotification[] notifs =
2457                 mBinderService.getActiveNotifications(n.getSbn().getPackageName());
2458         assertEquals(0, notifs.length);
2459         assertEquals(0, mService.getNotificationRecordCount());
2460         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
2461         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
2462         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
2463     }
2464 
2465     @Test
testCancelAllNotificationsCancelsChildren()2466     public void testCancelAllNotificationsCancelsChildren() throws Exception {
2467         final NotificationRecord parent = generateNotificationRecord(
2468                 mTestNotificationChannel, 1, "group1", true);
2469         final NotificationRecord child = generateNotificationRecord(
2470                 mTestNotificationChannel, 2, "group1", false);
2471 
2472         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2473                 "testCancelAllNotificationsCancelsChildren",
2474                 parent.getSbn().getId(), parent.getSbn().getNotification(),
2475                 parent.getSbn().getUserId());
2476         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2477                 "testCancelAllNotificationsCancelsChildren",
2478                 child.getSbn().getId(), child.getSbn().getNotification(),
2479                 child.getSbn().getUserId());
2480         waitForIdle();
2481 
2482         mBinderService.cancelAllNotifications(mPkg, parent.getSbn().getUserId());
2483         waitForIdle();
2484         assertEquals(0, mService.getNotificationRecordCount());
2485     }
2486 
2487     @Test
testCancelAllNotificationsMultipleEnqueuedDoesNotCrash()2488     public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
2489         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2490         for (int i = 0; i < 10; i++) {
2491             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2492                     "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash",
2493                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
2494         }
2495         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2496         waitForIdle();
2497 
2498         assertEquals(0, mService.getNotificationRecordCount());
2499     }
2500 
2501     @Test
testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash()2502     public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception {
2503         final NotificationRecord parent = generateNotificationRecord(
2504                 mTestNotificationChannel, 1, "group1", true);
2505         final NotificationRecord parentAsChild = generateNotificationRecord(
2506                 mTestNotificationChannel, 1, "group1", false);
2507         final NotificationRecord child = generateNotificationRecord(
2508                 mTestNotificationChannel, 2, "group1", false);
2509 
2510         // fully post parent notification
2511         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2512                 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2513                 parent.getSbn().getId(), parent.getSbn().getNotification(),
2514                 parent.getSbn().getUserId());
2515         waitForIdle();
2516 
2517         // enqueue the child several times
2518         for (int i = 0; i < 10; i++) {
2519             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2520                     "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2521                     child.getSbn().getId(), child.getSbn().getNotification(),
2522                     child.getSbn().getUserId());
2523         }
2524         // make the parent a child, which will cancel the child notification
2525         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2526                 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2527                 parentAsChild.getSbn().getId(), parentAsChild.getSbn().getNotification(),
2528                 parentAsChild.getSbn().getUserId());
2529         waitForIdle();
2530 
2531         assertEquals(0, mService.getNotificationRecordCount());
2532     }
2533 
2534     @Test
2535     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationAdded()2536     public void testAutobundledSummary_notificationAdded() {
2537         NotificationRecord summary =
2538                 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2539         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2540         mService.addNotification(summary);
2541         mService.mSummaryByGroupKey.put("pkg", summary);
2542         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2543         mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
2544 
2545         mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY,
2546                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2547                     mock(Icon.class), 0,
2548                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2549         waitForIdle();
2550 
2551         assertTrue(summary.getSbn().isOngoing());
2552     }
2553 
2554     @Test
2555     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationAdded_forcedGrouping()2556     public void testAutobundledSummary_notificationAdded_forcedGrouping() {
2557         NotificationRecord summary =
2558                 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2559         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2560         mService.addNotification(summary);
2561         mService.mSummaryByGroupKey.put("pkg", summary);
2562         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2563         mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey());
2564 
2565         mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(),
2566                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2567                     mock(Icon.class), 0,
2568                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2569         waitForIdle();
2570 
2571         assertTrue(summary.getSbn().isOngoing());
2572     }
2573 
2574     @Test
2575     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationRemoved()2576     public void testAutobundledSummary_notificationRemoved() {
2577         NotificationRecord summary =
2578                 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2579         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2580         summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
2581         mService.addNotification(summary);
2582         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2583         mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
2584         mService.mSummaryByGroupKey.put(summary.getGroupKey(), summary);
2585 
2586         mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY,
2587                 new NotificationAttributes(GroupHelper.BASE_FLAGS,
2588                     mock(Icon.class), 0,
2589                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2590         waitForIdle();
2591 
2592         assertFalse(summary.getSbn().isOngoing());
2593     }
2594 
2595     @Test
2596     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationRemoved_forceGrouping()2597     public void testAutobundledSummary_notificationRemoved_forceGrouping() {
2598         NotificationRecord summary =
2599             generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2600         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2601         summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
2602         mService.addNotification(summary);
2603         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2604         mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey());
2605 
2606         mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(),
2607                 new NotificationAttributes(GroupHelper.BASE_FLAGS,
2608                     mock(Icon.class), 0,
2609                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2610         waitForIdle();
2611 
2612         assertFalse(summary.getSbn().isOngoing());
2613     }
2614 
2615     @Test
2616     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAggregatedSummary_updateSummaryAttributes()2617     public void testAggregatedSummary_updateSummaryAttributes() {
2618         final String aggregateGroupName = "Aggregate_Test";
2619         final String newChannelId = "newChannelId";
2620         final NotificationChannel newChannel = new NotificationChannel(
2621                 newChannelId, newChannelId, IMPORTANCE_DEFAULT);
2622         mService.setPreferencesHelper(mPreferencesHelper);
2623         final NotificationRecord summary =
2624                 generateNotificationRecord(mTestNotificationChannel, 0, aggregateGroupName, true);
2625         final String groupKey = summary.getGroupKey();
2626         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2627         mService.addNotification(summary);
2628         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2629         mService.mAutobundledSummaries.get(0).put(groupKey, summary.getKey());
2630         when(mPreferencesHelper.getNotificationChannel(eq("pkg"), anyInt(),
2631                 eq(newChannelId), anyBoolean())).thenReturn(newChannel);
2632 
2633         mService.updateAutobundledSummaryLocked(0, "pkg", groupKey,
2634                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2635                     mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, newChannelId),
2636                     false);
2637         waitForIdle();
2638 
2639         assertTrue(summary.getSbn().isOngoing());
2640         assertThat(summary.getNotification().getGroupAlertBehavior()).isEqualTo(
2641                 GROUP_ALERT_CHILDREN);
2642 
2643         assertThat(summary.getChannel().getId()).isEqualTo(newChannelId);
2644     }
2645 
2646     @Test
2647     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAddAggregateNotification_notifyPostedLocked()2648     public void testAddAggregateNotification_notifyPostedLocked() throws Exception {
2649         final String originalGroupName = "originalGroup";
2650         final NotificationRecord r =
2651                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
2652         mService.addNotification(r);
2653         mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true);
2654 
2655         assertThat(r.getSbn().getOverrideGroupKey()).isEqualTo("grpKey");
2656         verify(mRankingHandler, times(1)).requestSort();
2657         verify(mListeners, times(1)).notifyPostedLocked(eq(r), eq(r));
2658     }
2659 
2660     @Test
2661     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAddAggregateSummaryNotification_convertSummary()2662     public void testAddAggregateSummaryNotification_convertSummary() throws Exception {
2663         final String originalGroupName = "originalGroup";
2664         final NotificationRecord r =
2665                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
2666         final String groupKey = r.getGroupKey();
2667         mService.addNotification(r);
2668         assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isTrue();
2669         boolean isConverted = mService.convertSummaryToNotificationLocked(r.getKey());
2670 
2671         assertThat(isConverted).isTrue();
2672         assertThat(r.getSbn().isGroup()).isTrue();
2673         assertThat(r.getNotification().isGroupSummary()).isFalse();
2674         assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isFalse();
2675     }
2676 
2677     @Test
2678     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2679             Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
testAggregateGroups_RemoveAppSummary()2680     public void testAggregateGroups_RemoveAppSummary() throws Exception {
2681         final String originalGroupName = "originalGroup";
2682         final NotificationRecord r =
2683                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
2684         mService.addNotification(r);
2685         mService.removeAppSummaryLocked(r.getKey());
2686 
2687         assertThat(r.isCanceled).isTrue();
2688         waitForIdle();
2689         verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(0));
2690     }
2691 
2692     @Test
2693     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION})
testAggregateGroups_RemoveAppSummary_onClassification()2694     public void testAggregateGroups_RemoveAppSummary_onClassification() throws Exception {
2695         final String originalGroupName = "originalGroup";
2696         final int summaryId = 0;
2697         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
2698                 summaryId + 1, originalGroupName, false);
2699         mService.addNotification(r1);
2700         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
2701                 summaryId + 2, originalGroupName, false);
2702         mService.addNotification(r2);
2703         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
2704                 summaryId, originalGroupName, true);
2705         mService.addNotification(summary);
2706         final String originalGroupKey = summary.getGroupKey();
2707         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
2708 
2709         // Regroup first child notification
2710         r1.setOverrideGroupKey("newGroup");
2711         // Check that removeAppProvidedSummaryOnClassificationLocked is null
2712         //  => there is still one child left in the original group
2713         assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r1.getKey(),
2714                 originalGroupKey)).isNull();
2715 
2716         // Regroup last child notification
2717         r2.setOverrideGroupKey("newGroup");
2718         // Check that removeAppProvidedSummaryOnClassificationLocked returns the original summary
2719         //  and that the original app-provided summary is canceled
2720         assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r2.getKey(),
2721                 originalGroupKey)).isEqualTo(summary);
2722         waitForIdle();
2723         verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(summaryId));
2724         assertThat(mService.mSummaryByGroupKey).doesNotContainKey(originalGroupKey);
2725     }
2726 
2727     @Test
2728     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testUngroupingAggregateSummary()2729     public void testUngroupingAggregateSummary() throws Exception {
2730         final String originalGroupName = "originalGroup";
2731         final String aggregateGroupName = "Aggregate_Test";
2732         final int summaryId = Integer.MAX_VALUE;
2733         // Add 2 group notifications without a summary
2734         NotificationRecord nr0 =
2735                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
2736         NotificationRecord nr1 =
2737                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
2738         mService.addNotification(nr0);
2739         mService.addNotification(nr1);
2740         mService.mSummaryByGroupKey.remove(nr0.getGroupKey());
2741 
2742         // GroupHelper is a mock, so make the calls it would make
2743         // Add aggregate group summary
2744         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
2745                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
2746                 nr0.getChannel().getId());
2747         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
2748                 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
2749         mService.addNotification(aggregateSummary);
2750         nr0.setOverrideGroupKey(aggregateGroupName);
2751         nr1.setOverrideGroupKey(aggregateGroupName);
2752         final String fullAggregateGroupKey = nr0.getGroupKey();
2753 
2754         // Check that the aggregate group summary was created
2755         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
2756         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
2757                 nr0.getChannel().getId());
2758         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
2759 
2760         // Cancel both children
2761         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
2762                 nr0.getSbn().getId(), nr0.getSbn().getUserId());
2763         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
2764                 nr1.getSbn().getId(), nr1.getSbn().getUserId());
2765         waitForIdle();
2766 
2767         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any());
2768         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any());
2769 
2770         // GroupHelper would send 'remove summary' event
2771         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(),
2772                 fullAggregateGroupKey);
2773         waitForIdle();
2774 
2775         // Make sure the summary was removed and not re-posted
2776         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
2777     }
2778 
2779     @Test
2780     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2781             Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
testCancelGroupChildrenForCanceledSummary_singletonGroup()2782     public void testCancelGroupChildrenForCanceledSummary_singletonGroup() throws Exception {
2783         final String originalGroupName = "originalGroup";
2784         final String aggregateGroupName = "Aggregate_Test";
2785         final int summaryId = Integer.MAX_VALUE;
2786         // Add a "singleton group"
2787         NotificationRecord nr0 =
2788                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
2789         NotificationRecord nr1 =
2790                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
2791         final NotificationRecord summary =
2792                 generateNotificationRecord(mTestNotificationChannel, 2, originalGroupName, true);
2793         final String originalGroupKey = summary.getGroupKey();
2794         mService.addNotification(nr0);
2795         mService.addNotification(nr1);
2796         mService.addNotification(summary);
2797 
2798         // GroupHelper is a mock, so make the calls it would make
2799         // Remove the app's summary notification
2800         mService.removeAppSummaryLocked(summary.getKey());
2801         waitForIdle();
2802 
2803         // Add aggregate group summary
2804         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
2805                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
2806                 nr0.getChannel().getId());
2807         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
2808             nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
2809         mService.addNotification(aggregateSummary);
2810 
2811         nr0.setOverrideGroupKey(aggregateGroupName);
2812         nr1.setOverrideGroupKey(aggregateGroupName);
2813         final String fullAggregateGroupKey = nr0.getGroupKey();
2814 
2815         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
2816         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
2817                 nr0.getChannel().getId());
2818         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
2819         assertThat(mService.mSummaryByGroupKey.containsKey(originalGroupKey)).isFalse();
2820 
2821         // Cancel the original app summary (is already removed)
2822         mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(),
2823                 summary.getSbn().getPackageName(), summary.getSbn().getTag(),
2824                 summary.getSbn().getId(), summary.getSbn().getUserId());
2825         waitForIdle();
2826 
2827         // Check if NMS.CancelNotificationRunnable calls maybeCancelGroupChildrenForCanceledSummary
2828         verify(mGroupHelper, times(1)).maybeCancelGroupChildrenForCanceledSummary(
2829                 eq(summary.getSbn().getPackageName()), eq(summary.getSbn().getTag()),
2830                 eq(summary.getSbn().getId()), eq(summary.getSbn().getUserId()),
2831                 eq(REASON_APP_CANCEL));
2832     }
2833 
2834     @Test
2835     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testUpdateChannel_notifyGroupHelper()2836     public void testUpdateChannel_notifyGroupHelper() throws Exception {
2837         mService.setPreferencesHelper(mPreferencesHelper);
2838         mTestNotificationChannel.setLightColor(Color.CYAN);
2839         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
2840                 eq(mTestNotificationChannel.getId()), anyBoolean()))
2841                 .thenReturn(mTestNotificationChannel);
2842 
2843         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel);
2844         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2845         waitForIdle();
2846 
2847         verify(mGroupHelper, times(1)).onChannelUpdated(eq(Process.myUserHandle().getIdentifier()),
2848                 eq(mPkg), eq(mTestNotificationChannel), any());
2849     }
2850 
2851     @Test
2852     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed()2853     public void testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed() throws Exception {
2854         final String aggregateGroupName = "Aggregate_Test";
2855 
2856         // build autogroup summary notification
2857         Notification.Builder nb = new Notification.Builder(mContext,
2858                 mTestNotificationChannel.getId())
2859                 .setContentTitle("foo")
2860                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2861                 .setGroup(aggregateGroupName)
2862                 .setGroupSummary(true)
2863                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true);
2864         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
2865                 "tag" + System.currentTimeMillis(), mUid, 0, nb.build(),
2866                 UserHandle.getUserHandleForUid(mUid), null, 0);
2867         final NotificationRecord summary = new NotificationRecord(mContext, sbn,
2868                 mTestNotificationChannel);
2869 
2870         final NotificationRecord child = generateNotificationRecord(
2871                 mTestNotificationChannel, 2, aggregateGroupName, false);
2872         mService.addNotification(summary);
2873         mService.addNotification(child);
2874         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
2875 
2876         // snooze child only
2877         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
2878                 mService.new SnoozeNotificationRunnable(
2879                     child.getKey(), 100, null);
2880         snoozeNotificationRunnable.run();
2881 
2882         // only child should be snoozed
2883         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
2884 
2885         // both group summary and child should be cancelled
2886         assertNull(mService.getNotificationRecord(summary.getKey()));
2887         assertNull(mService.getNotificationRecord(child.getKey()));
2888 
2889         assertEquals(4, mNotificationRecordLogger.numCalls());
2890         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
2891                 mNotificationRecordLogger.event(0));
2892         assertEquals(
2893                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
2894                 mNotificationRecordLogger.event(1));
2895     }
2896 
2897     @Test
2898     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2899             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testOnlyForceGroupIfNeeded_newNotification_notAutogrouped()2900     public void testOnlyForceGroupIfNeeded_newNotification_notAutogrouped() {
2901         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
2902         when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false);
2903         mService.addEnqueuedNotification(r);
2904         NotificationManagerService.PostNotificationRunnable runnable =
2905                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
2906                     r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
2907         runnable.run();
2908         waitForIdle();
2909 
2910         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2911         waitForIdle();
2912 
2913         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
2914         verify(mGroupHelper, times(1)).onNotificationPostedWithDelay(eq(r), any(), any());
2915     }
2916 
2917     @Test
2918     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2919             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped()2920     public void testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped() {
2921         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
2922         when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(true);
2923         mService.addEnqueuedNotification(r);
2924         NotificationManagerService.PostNotificationRunnable runnable =
2925             mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
2926                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
2927         runnable.run();
2928         waitForIdle();
2929 
2930         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2931         waitForIdle();
2932 
2933         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
2934         verify(mGroupHelper, never()).onNotificationPostedWithDelay(eq(r), any(), any());
2935     }
2936 
2937     @Test
2938     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2939             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testRemoveScheduledForceGroup_onNotificationCanceled()2940     public void testRemoveScheduledForceGroup_onNotificationCanceled() throws Exception {
2941         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "tag", null,
2942                 false);
2943         when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false);
2944         mService.addEnqueuedNotification(r);
2945         NotificationManagerService.PostNotificationRunnable runnable =
2946                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
2947                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
2948         runnable.run();
2949         waitForIdle();
2950 
2951         // Post an update to the notification
2952         NotificationRecord r_update =
2953                 generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, false);
2954         mService.addEnqueuedNotification(r_update);
2955         runnable = mService.new PostNotificationRunnable(r_update.getKey(),
2956                 r_update.getSbn().getPackageName(), r_update.getUid(),
2957                 mPostNotificationTrackerFactory.newTracker(null));
2958         runnable.run();
2959         waitForIdle();
2960 
2961         // Cancel the notification
2962         mBinderService.cancelNotificationWithTag(r.getSbn().getPackageName(),
2963                 r.getSbn().getPackageName(), r.getSbn().getTag(),
2964                 r.getSbn().getId(), r.getSbn().getUserId());
2965         waitForIdle();
2966 
2967         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2968         waitForIdle();
2969 
2970         // Check that onNotificationPostedWithDelay was canceled
2971         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
2972         verify(mGroupHelper, never()).onNotificationPostedWithDelay(any(), any(), any());
2973     }
2974 
2975     @Test
2976     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testEnqueueNotification_forceGrouped_clearsSummaryFlag()2977     public void testEnqueueNotification_forceGrouped_clearsSummaryFlag() throws Exception {
2978         final String originalGroupName = "originalGroup";
2979         final String aggregateGroupName = "Aggregate_Test";
2980 
2981         // Old record was a summary and it was auto-grouped
2982         final NotificationRecord r =
2983                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
2984         mService.addNotification(r);
2985         mService.convertSummaryToNotificationLocked(r.getKey());
2986         mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true);
2987 
2988         assertThat(mService.mNotificationList).hasSize(1);
2989 
2990         // Update record is a summary
2991         final Notification updatedNotification = generateNotificationRecord(
2992                 mTestNotificationChannel, 0, originalGroupName, true).getNotification();
2993         assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY);
2994 
2995         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
2996                 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId());
2997         waitForIdle();
2998 
2999         // Check that FLAG_GROUP_SUMMARY was removed
3000         assertThat(mService.mNotificationList).hasSize(1);
3001         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0);
3002     }
3003 
3004     @Test
3005     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag()3006     public void testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag()
3007             throws Exception {
3008         final String originalGroupName = "originalGroup";
3009         final String aggregateGroupName = "Aggregate_Test";
3010 
3011         // Old record was not summary and it was auto-grouped
3012         final NotificationRecord r =
3013                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
3014         mService.addNotification(r);
3015         mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true);
3016         assertThat(mService.mNotificationList).hasSize(1);
3017 
3018         // Update record is a summary
3019         final Notification updatedNotification = generateNotificationRecord(
3020                 mTestNotificationChannel, 0, originalGroupName, true).getNotification();
3021         assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY);
3022 
3023         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
3024                 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId());
3025         waitForIdle();
3026 
3027         // Check that FLAG_GROUP_SUMMARY was removed
3028         assertThat(mService.mNotificationList).hasSize(1);
3029         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0);
3030     }
3031 
3032     @Test
3033     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testEnqueueNotification_notForceGrouped_dontClearSummaryFlag()3034     public void testEnqueueNotification_notForceGrouped_dontClearSummaryFlag()
3035             throws Exception {
3036         final String originalGroupName = "originalGroup";
3037 
3038         // Old record was a summary and it was not auto-grouped
3039         final NotificationRecord r =
3040                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
3041         mService.addNotification(r);
3042         assertThat(mService.mNotificationList).hasSize(1);
3043 
3044         // Update record is a summary
3045         final Notification updatedNotification = generateNotificationRecord(
3046                 mTestNotificationChannel, 0, originalGroupName, true).getNotification();
3047         assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY);
3048 
3049         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
3050                 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId());
3051         waitForIdle();
3052 
3053         // Check that FLAG_GROUP_SUMMARY was not removed
3054         assertThat(mService.mNotificationList).hasSize(1);
3055         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(
3056                 FLAG_GROUP_SUMMARY);
3057     }
3058 
3059     @Test
3060     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag()3061     public void testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag() {
3062         final String originalGroupName = "originalGroup";
3063         final String aggregateGroupName = "Aggregate_Test";
3064 
3065         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null,
3066                 originalGroupName, true);
3067         r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY;
3068         r.setOverrideGroupKey(aggregateGroupName);
3069         mService.addEnqueuedNotification(r);
3070 
3071         mInternalService.removeForegroundServiceFlagFromNotification(
3072                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
3073         waitForIdle();
3074 
3075         assertThat(mService.mEnqueuedNotifications).hasSize(1);
3076         assertThat(mService.mEnqueuedNotifications.get(0).getFlags() & FLAG_GROUP_SUMMARY)
3077                 .isEqualTo(0);
3078     }
3079 
3080     @Test
3081     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag()3082     public void testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag() {
3083         final String originalGroupName = "originalGroup";
3084         final String aggregateGroupName = "Aggregate_Test";
3085 
3086         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null,
3087                 originalGroupName, true);
3088         r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY;
3089         r.setOverrideGroupKey(aggregateGroupName);
3090         mService.addNotification(r);
3091 
3092         mInternalService.removeForegroundServiceFlagFromNotification(
3093                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
3094         waitForIdle();
3095 
3096         assertThat(mService.mNotificationList).hasSize(1);
3097         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0);
3098     }
3099 
3100     @Test
3101     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
3102             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testScheduleGroupHelperWithDelay_onChildNotificationCanceled()3103     public void testScheduleGroupHelperWithDelay_onChildNotificationCanceled() throws Exception {
3104         // Post summary + 2 child notification
3105         final String originalGroupName = "originalGroup";
3106         final int summaryId = 0;
3107         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
3108                 summaryId + 1, originalGroupName, false);
3109         mService.addNotification(r1);
3110         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
3111                 summaryId + 2, originalGroupName, false);
3112         mService.addNotification(r2);
3113         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
3114                 summaryId, originalGroupName, true);
3115         mService.addNotification(summary);
3116         final String originalGroupKey = summary.getGroupKey();
3117         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
3118 
3119         // Cancel the child notifications
3120         mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
3121                 r1.getSbn().getPackageName(), r1.getSbn().getTag(),
3122                 r1.getSbn().getId(), r1.getSbn().getUserId());
3123         waitForIdle();
3124 
3125         mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
3126                 r2.getSbn().getPackageName(), r2.getSbn().getTag(),
3127                 r2.getSbn().getId(), r2.getSbn().getUserId());
3128         waitForIdle();
3129 
3130         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
3131         waitForIdle();
3132 
3133         // Check that onGroupedNotificationRemovedWithDelay was called only once
3134         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any());
3135         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any());
3136         verify(mGroupHelper, times(1)).onGroupedNotificationRemovedWithDelay(eq(summary), any(),
3137                 any());
3138     }
3139 
3140     @Test
3141     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
3142             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()3143     public void testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()
3144             throws Exception {
3145         // Post summary + 2 child notification
3146         final String originalGroupName = "originalGroup";
3147         final int summaryId = 0;
3148         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
3149                 summaryId + 1, originalGroupName, false);
3150         mService.addNotification(r1);
3151         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
3152                 summaryId + 2, originalGroupName, false);
3153         mService.addNotification(r2);
3154         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
3155                 summaryId, originalGroupName, true);
3156         mService.addNotification(summary);
3157         final String originalGroupKey = summary.getGroupKey();
3158         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
3159 
3160         // Cancel all notifications: children + summary
3161         mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
3162                 r1.getSbn().getPackageName(), r1.getSbn().getTag(),
3163                 r1.getSbn().getId(), r1.getSbn().getUserId());
3164         waitForIdle();
3165 
3166         mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
3167                 r2.getSbn().getPackageName(), r2.getSbn().getTag(),
3168                 r2.getSbn().getId(), r2.getSbn().getUserId());
3169         waitForIdle();
3170 
3171         mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(),
3172                 summary.getSbn().getPackageName(), summary.getSbn().getTag(),
3173                 summary.getSbn().getId(), summary.getSbn().getUserId());
3174         waitForIdle();
3175 
3176         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
3177         waitForIdle();
3178 
3179         // Check that onGroupedNotificationRemovedWithDelay was never called: summary was canceled
3180         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any());
3181         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any());
3182         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(summary), any());
3183         verify(mGroupHelper, never()).onGroupedNotificationRemovedWithDelay(any(), any(), any());
3184     }
3185 
3186     @Test
testCancelAllNotifications_IgnoreForegroundService()3187     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
3188         when(mAmi.applyForegroundServiceNotification(
3189                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
3190         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3191         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3192         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3193                 "testCancelAllNotifications_IgnoreForegroundService",
3194                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3195         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3196         waitForIdle();
3197         StatusBarNotification[] notifs =
3198                 mBinderService.getActiveNotifications(sbn.getPackageName());
3199         assertEquals(1, notifs.length);
3200         assertEquals(1, mService.getNotificationRecordCount());
3201     }
3202 
3203     @Test
testCancelAllNotifications_FgsFlag_NoFgs_Allowed()3204     public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception {
3205         when(mAmi.applyForegroundServiceNotification(
3206                 any(), anyString(), anyInt(), anyString(), anyInt()))
3207                 .thenReturn(NOT_FOREGROUND_SERVICE);
3208         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3209         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3210         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3211                 "testCancelAllNotifications_IgnoreForegroundService",
3212                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3213         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3214         waitForIdle();
3215         StatusBarNotification[] notifs =
3216                 mBinderService.getActiveNotifications(sbn.getPackageName());
3217         assertEquals(0, notifs.length);
3218     }
3219 
3220     @Test
testCancelAllNotifications_IgnoreOtherPackages()3221     public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
3222         when(mAmi.applyForegroundServiceNotification(
3223                 any(), anyString(), anyInt(), anyString(), anyInt()))
3224                 .thenReturn(SHOW_IMMEDIATELY);
3225         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3226         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3227         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3228                 "testCancelAllNotifications_IgnoreOtherPackages",
3229                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3230         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
3231         waitForIdle();
3232         StatusBarNotification[] notifs =
3233                 mBinderService.getActiveNotifications(sbn.getPackageName());
3234         assertEquals(1, notifs.length);
3235         assertEquals(1, mService.getNotificationRecordCount());
3236     }
3237 
3238     @Test
testCancelAllNotifications_NullPkgRemovesAll()3239     public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
3240         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3241         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3242                 "testCancelAllNotifications_NullPkgRemovesAll",
3243                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3244         mBinderService.cancelAllNotifications(null, sbn.getUserId());
3245         waitForIdle();
3246         StatusBarNotification[] notifs =
3247                 mBinderService.getActiveNotifications(sbn.getPackageName());
3248         assertEquals(0, notifs.length);
3249         assertEquals(0, mService.getNotificationRecordCount());
3250     }
3251 
3252     @Test
testCancelAllNotifications_NullPkgIgnoresUserAllNotifications()3253     public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
3254         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3255         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3256                 "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications",
3257                 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
3258         // Null pkg is how we signal a user switch.
3259         mBinderService.cancelAllNotifications(null, sbn.getUserId());
3260         waitForIdle();
3261         StatusBarNotification[] notifs =
3262                 mBinderService.getActiveNotifications(sbn.getPackageName());
3263         assertEquals(1, notifs.length);
3264         assertEquals(1, mService.getNotificationRecordCount());
3265     }
3266 
3267     @Test
testAppInitiatedCancelAllNotifications_CancelsNoClearFlag()3268     public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception {
3269         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3270         sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3271         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3272                 "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag",
3273                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3274         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3275         waitForIdle();
3276         StatusBarNotification[] notifs =
3277                 mBinderService.getActiveNotifications(sbn.getPackageName());
3278         assertEquals(0, notifs.length);
3279     }
3280 
3281     @Test
testCancelAllNotifications_CancelsNoClearFlag()3282     public void testCancelAllNotifications_CancelsNoClearFlag() throws Exception {
3283         final NotificationRecord notif = generateNotificationRecord(
3284                 mTestNotificationChannel, 1, "group", true);
3285         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3286         mService.addNotification(notif);
3287         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
3288                 notif.getUserId(), REASON_CANCEL);
3289         waitForIdle();
3290         StatusBarNotification[] notifs =
3291                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3292         assertEquals(0, notifs.length);
3293     }
3294 
3295     @Test
testUserInitiatedCancelAllOnClearAll_NoClearFlag()3296     public void testUserInitiatedCancelAllOnClearAll_NoClearFlag() throws Exception {
3297         final NotificationRecord notif = generateNotificationRecord(
3298                 mTestNotificationChannel, 1, "group", true);
3299         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3300         mService.addNotification(notif);
3301 
3302         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3303                 notif.getUserId());
3304         waitForIdle();
3305         StatusBarNotification[] notifs =
3306                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3307         assertEquals(1, notifs.length);
3308     }
3309 
3310     @Test
testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue()3311     public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
3312         when(mAmi.applyForegroundServiceNotification(
3313                 any(), anyString(), anyInt(), anyString(), anyInt()))
3314                 .thenReturn(SHOW_IMMEDIATELY);
3315         Notification n =
3316                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
3317                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
3318                         .build();
3319         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
3320                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
3321         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3322         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null,
3323                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3324         mInternalService.removeForegroundServiceFlagFromNotification(mPkg, sbn.getId(),
3325                 sbn.getUserId());
3326         waitForIdle();
3327         StatusBarNotification[] notifs =
3328                 mBinderService.getActiveNotifications(sbn.getPackageName());
3329         assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE);
3330     }
3331 
3332     @Test
testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag()3333     public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
3334         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3335         sbn.getNotification().flags =
3336                 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
3337         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
3338                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3339         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
3340         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
3341                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3342         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3343                 sbn.getUserId());
3344         waitForIdle();
3345         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
3346         assertEquals(0, mService.getNotificationRecordCount());
3347     }
3348 
3349     @Test
3350     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelWithTagDoesNotCancelLifetimeExtended()3351     public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception {
3352         final NotificationRecord notif = generateNotificationRecord(null);
3353         notif.getSbn().getNotification().flags =
3354                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3355         mService.addNotification(notif);
3356         final StatusBarNotification sbn = notif.getSbn();
3357 
3358         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3359         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3360 
3361         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3362                 sbn.getUserId());
3363         waitForIdle();
3364 
3365         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3366         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3367 
3368         // Checks that a post update is sent.
3369         verify(mWorkerHandler, times(1))
3370                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3371         ArgumentCaptor<NotificationRecord> captor =
3372                 ArgumentCaptor.forClass(NotificationRecord.class);
3373         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3374                 anyBoolean());
3375         assertThat(captor.getValue().getNotification().flags
3376                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3377                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3378     }
3379 
3380     @Test
3381     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testMultipleCancelOfLifetimeExtendedSendsOneUpdate()3382     public void testMultipleCancelOfLifetimeExtendedSendsOneUpdate() throws Exception {
3383         final NotificationRecord notif = generateNotificationRecord(null);
3384         notif.getSbn().getNotification().flags =
3385                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3386         mService.addNotification(notif);
3387         final StatusBarNotification sbn = notif.getSbn();
3388 
3389         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3390         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3391 
3392         // Send two cancelations.
3393         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3394                 sbn.getUserId());
3395         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3396                 sbn.getUserId());
3397         waitForIdle();
3398 
3399         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3400         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3401 
3402         // Checks that only one post update is sent.
3403         verify(mWorkerHandler, times(1))
3404                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3405         ArgumentCaptor<NotificationRecord> captor =
3406                 ArgumentCaptor.forClass(NotificationRecord.class);
3407         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3408                 anyBoolean());
3409         assertThat(captor.getValue().getNotification().flags
3410                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3411                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3412     }
3413 
3414     @Test
3415     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelAllClearsLifetimeExtended()3416     public void testCancelAllClearsLifetimeExtended() throws Exception {
3417         final NotificationRecord notif = generateNotificationRecord(
3418                 mTestNotificationChannel, 1, "group", true);
3419         notif.getNotification().flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3420         mService.addNotification(notif);
3421         StatusBarNotification[] notifs =
3422                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3423         assertThat(notifs.length).isEqualTo(1);
3424 
3425         // Simulate a "cancel all" received.
3426         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3427                 notif.getUserId());
3428         waitForIdle();
3429         notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3430         assertThat(notifs.length).isEqualTo(0);
3431 
3432         // Test that no update post is sent to System UI.
3433         verify(mWorkerHandler, never())
3434                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
3435     }
3436 
3437     @Test
3438     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testAppCancelAllDoesNotCancelLifetimeExtended()3439     public void testAppCancelAllDoesNotCancelLifetimeExtended() throws Exception {
3440         // Adds a lifetime extended notification.
3441         final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1,
3442                 null, false);
3443         notif.getSbn().getNotification().flags =
3444                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3445         mService.addNotification(notif);
3446         // Adds a second, non-lifetime extended notification.
3447         final NotificationRecord notifCancelable = generateNotificationRecord(
3448                 mTestNotificationChannel, 2, null, false);
3449         mService.addNotification(notifCancelable);
3450         // Verify that both notifications have been posted and are active.
3451         assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(2);
3452 
3453         mBinderService.cancelAllNotifications(mPkg, notif.getSbn().getUserId());
3454         waitForIdle();
3455 
3456         // The non-lifetime extended notification, with id = 2, has been cancelled.
3457         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
3458         assertThat(notifs.length).isEqualTo(1);
3459         assertThat(notifs[0].getId()).isEqualTo(1);
3460 
3461         // Checks that a post update is sent.
3462         verify(mWorkerHandler, times(1))
3463                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3464         ArgumentCaptor<NotificationRecord> captor =
3465                 ArgumentCaptor.forClass(NotificationRecord.class);
3466         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3467                 anyBoolean());
3468         assertThat(captor.getValue().getNotification().flags
3469                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3470                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3471     }
3472 
3473     @Test
3474     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testLifetimeExtendedCancelledOnClick()3475     public void testLifetimeExtendedCancelledOnClick() throws Exception {
3476         // Adds a lifetime extended notification.
3477         final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1,
3478                 null, false);
3479         notif.getSbn().getNotification().flags =
3480                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3481         mService.addNotification(notif);
3482         // Verify that the notification is posted and active.
3483         assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(1);
3484 
3485         // Click the notification.
3486         final NotificationVisibility nv = NotificationVisibility.obtain(notif.getKey(), 1, 2, true);
3487         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
3488                 notif.getKey(), nv);
3489         waitForIdle();
3490 
3491         // The notification has been cancelled.
3492         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
3493         assertThat(notifs.length).isEqualTo(0);
3494     }
3495 
3496     @Test
testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()3497     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()
3498             throws Exception {
3499         when(mAmi.applyForegroundServiceNotification(
3500                 any(), anyString(), anyInt(), anyString(), anyInt()))
3501                 .thenReturn(SHOW_IMMEDIATELY);
3502         mService.isSystemUid = false;
3503         mService.isSystemAppId = false;
3504         final NotificationRecord parent = generateNotificationRecord(
3505                 mTestNotificationChannel, 1, "group", true);
3506         final NotificationRecord child = generateNotificationRecord(
3507                 mTestNotificationChannel, 2, "group", false);
3508         final NotificationRecord child2 = generateNotificationRecord(
3509                 mTestNotificationChannel, 3, "group", false);
3510         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3511         mService.addNotification(parent);
3512         mService.addNotification(child);
3513         mService.addNotification(child2);
3514         mService.getBinderService().cancelNotificationWithTag(
3515                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3516                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3517         waitForIdle();
3518         StatusBarNotification[] notifs =
3519                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3520         assertEquals(1, notifs.length);
3521     }
3522 
3523     @Test
testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()3524     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()
3525             throws Exception {
3526         when(mAmi.applyForegroundServiceNotification(
3527                 any(), anyString(), anyInt(), anyString(), anyInt()))
3528                 .thenReturn(SHOW_IMMEDIATELY);
3529         mService.isSystemUid = false;
3530         mService.isSystemAppId = false;
3531         final NotificationRecord parent = generateNotificationRecord(
3532                 mTestNotificationChannel, 1, "group", true);
3533         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3534         final NotificationRecord child = generateNotificationRecord(
3535                 mTestNotificationChannel, 2, "group", false);
3536         final NotificationRecord child2 = generateNotificationRecord(
3537                 mTestNotificationChannel, 3, "group", false);
3538         mService.addNotification(parent);
3539         mService.addNotification(child);
3540         mService.addNotification(child2);
3541         mService.getBinderService().cancelNotificationWithTag(
3542                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3543                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3544         waitForIdle();
3545         StatusBarNotification[] notifs =
3546                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3547         assertEquals(3, notifs.length);
3548     }
3549 
3550     @Test
testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()3551     public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()
3552             throws Exception {
3553         mService.isSystemUid = false;
3554         mService.isSystemAppId = false;
3555         final NotificationRecord parent = generateNotificationRecord(
3556                 mTestNotificationChannel, 1, "group", true);
3557         final NotificationRecord child = generateNotificationRecord(
3558                 mTestNotificationChannel, 2, "group", false);
3559         final NotificationRecord child2 = generateNotificationRecord(
3560                 mTestNotificationChannel, 3, "group", false);
3561         child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3562         mService.addNotification(parent);
3563         mService.addNotification(child);
3564         mService.addNotification(child2);
3565         mService.getBinderService().cancelNotificationWithTag(
3566                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3567                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3568         waitForIdle();
3569         StatusBarNotification[] notifs =
3570                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3571         assertEquals(0, notifs.length);
3572     }
3573 
3574     @Test
testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()3575     public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()
3576             throws Exception {
3577         mService.isSystemUid = false;
3578         mService.isSystemAppId = false;
3579         final NotificationRecord parent = generateNotificationRecord(
3580                 mTestNotificationChannel, 1, "group", true);
3581         parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3582         final NotificationRecord child = generateNotificationRecord(
3583                 mTestNotificationChannel, 2, "group", false);
3584         final NotificationRecord child2 = generateNotificationRecord(
3585                 mTestNotificationChannel, 3, "group", false);
3586         mService.addNotification(parent);
3587         mService.addNotification(child);
3588         mService.addNotification(child2);
3589         mService.getBinderService().cancelNotificationWithTag(
3590                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3591                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3592         waitForIdle();
3593         StatusBarNotification[] notifs =
3594                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3595         assertEquals(0, notifs.length);
3596     }
3597 
3598     @Test
testCancelAllNotificationsFromApp_cannotCancelFgsChild()3599     public void testCancelAllNotificationsFromApp_cannotCancelFgsChild()
3600             throws Exception {
3601         when(mAmi.applyForegroundServiceNotification(
3602                 any(), anyString(), anyInt(), anyString(), anyInt()))
3603                 .thenReturn(SHOW_IMMEDIATELY);
3604         mService.isSystemUid = false;
3605         mService.isSystemAppId = false;
3606         final NotificationRecord parent = generateNotificationRecord(
3607                 mTestNotificationChannel, 1, "group", true);
3608         final NotificationRecord child = generateNotificationRecord(
3609                 mTestNotificationChannel, 2, "group", false);
3610         final NotificationRecord child2 = generateNotificationRecord(
3611                 mTestNotificationChannel, 3, "group", false);
3612         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3613         final NotificationRecord newGroup = generateNotificationRecord(
3614                 mTestNotificationChannel, 4, "group2", false);
3615         mService.addNotification(parent);
3616         mService.addNotification(child);
3617         mService.addNotification(child2);
3618         mService.addNotification(newGroup);
3619         mService.getBinderService().cancelAllNotifications(
3620                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3621         waitForIdle();
3622         StatusBarNotification[] notifs =
3623                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3624         assertEquals(1, notifs.length);
3625     }
3626 
3627     @Test
testCancelAllNotifications_fromApp_cannotCancelFgsParent()3628     public void testCancelAllNotifications_fromApp_cannotCancelFgsParent()
3629             throws Exception {
3630         when(mAmi.applyForegroundServiceNotification(
3631                 any(), anyString(), anyInt(), anyString(), anyInt()))
3632                 .thenReturn(SHOW_IMMEDIATELY);
3633         mService.isSystemUid = false;
3634         mService.isSystemAppId = false;
3635         final NotificationRecord parent = generateNotificationRecord(
3636                 mTestNotificationChannel, 1, "group", true);
3637         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3638         final NotificationRecord child = generateNotificationRecord(
3639                 mTestNotificationChannel, 2, "group", false);
3640         final NotificationRecord child2 = generateNotificationRecord(
3641                 mTestNotificationChannel, 3, "group", false);
3642         final NotificationRecord newGroup = generateNotificationRecord(
3643                 mTestNotificationChannel, 4, "group2", false);
3644         mService.addNotification(parent);
3645         mService.addNotification(child);
3646         mService.addNotification(child2);
3647         mService.addNotification(newGroup);
3648         mService.getBinderService().cancelAllNotifications(
3649                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3650         waitForIdle();
3651         StatusBarNotification[] notifs =
3652                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3653         assertEquals(1, notifs.length);
3654     }
3655 
3656     @Test
testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()3657     public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()
3658             throws Exception {
3659         mService.isSystemUid = false;
3660         mService.isSystemAppId = false;
3661         final NotificationRecord parent = generateNotificationRecord(
3662                 mTestNotificationChannel, 1, "group", true);
3663         final NotificationRecord child = generateNotificationRecord(
3664                 mTestNotificationChannel, 2, "group", false);
3665         final NotificationRecord child2 = generateNotificationRecord(
3666                 mTestNotificationChannel, 3, "group", false);
3667         child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3668         final NotificationRecord newGroup = generateNotificationRecord(
3669                 mTestNotificationChannel, 4, "group2", false);
3670         mService.addNotification(parent);
3671         mService.addNotification(child);
3672         mService.addNotification(child2);
3673         mService.addNotification(newGroup);
3674         mService.getBinderService().cancelAllNotifications(
3675                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3676         waitForIdle();
3677         StatusBarNotification[] notifs =
3678                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3679         assertEquals(0, notifs.length);
3680     }
3681 
3682     @Test
testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()3683     public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()
3684             throws Exception {
3685         mService.isSystemUid = false;
3686         mService.isSystemAppId = false;
3687         final NotificationRecord parent = generateNotificationRecord(
3688                 mTestNotificationChannel, 1, "group", true);
3689         parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3690         final NotificationRecord child = generateNotificationRecord(
3691                 mTestNotificationChannel, 2, "group", false);
3692         final NotificationRecord child2 = generateNotificationRecord(
3693                 mTestNotificationChannel, 3, "group", false);
3694         final NotificationRecord newGroup = generateNotificationRecord(
3695                 mTestNotificationChannel, 4, "group2", false);
3696         mService.addNotification(parent);
3697         mService.addNotification(child);
3698         mService.addNotification(child2);
3699         mService.addNotification(newGroup);
3700         mService.getBinderService().cancelAllNotifications(
3701                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3702         waitForIdle();
3703         StatusBarNotification[] notifs =
3704                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3705         assertEquals(0, notifs.length);
3706     }
3707 
3708     @Test
testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()3709     public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()
3710             throws Exception {
3711         final NotificationRecord parent = generateNotificationRecord(
3712                 mTestNotificationChannel, 1, "group", true);
3713         parent.getNotification().flags |= FLAG_ONGOING_EVENT;
3714         final NotificationRecord child = generateNotificationRecord(
3715                 mTestNotificationChannel, 2, "group", false);
3716         final NotificationRecord child2 = generateNotificationRecord(
3717                 mTestNotificationChannel, 3, "group", false);
3718         final NotificationRecord newGroup = generateNotificationRecord(
3719                 mTestNotificationChannel, 4, "group2", false);
3720         mService.addNotification(parent);
3721         mService.addNotification(child);
3722         mService.addNotification(child2);
3723         mService.addNotification(newGroup);
3724         mService.getBinderService().cancelNotificationsFromListener(null, null);
3725         waitForIdle();
3726         StatusBarNotification[] notifs =
3727                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3728         assertEquals(1, notifs.length);
3729     }
3730 
3731     @Test
testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()3732     public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()
3733             throws Exception {
3734         final NotificationRecord parent = generateNotificationRecord(
3735                 mTestNotificationChannel, 1, "group", true);
3736         final NotificationRecord child = generateNotificationRecord(
3737                 mTestNotificationChannel, 2, "group", false);
3738         final NotificationRecord child2 = generateNotificationRecord(
3739                 mTestNotificationChannel, 3, "group", false);
3740         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3741         final NotificationRecord newGroup = generateNotificationRecord(
3742                 mTestNotificationChannel, 4, "group2", false);
3743         mService.addNotification(parent);
3744         mService.addNotification(child);
3745         mService.addNotification(child2);
3746         mService.addNotification(newGroup);
3747         mService.getBinderService().cancelNotificationsFromListener(null, null);
3748         waitForIdle();
3749         StatusBarNotification[] notifs =
3750                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3751         assertEquals(1, notifs.length);
3752     }
3753 
3754     @Test
testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()3755     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()
3756             throws Exception {
3757         when(mAmi.applyForegroundServiceNotification(
3758                 any(), anyString(), anyInt(), anyString(), anyInt()))
3759                 .thenReturn(SHOW_IMMEDIATELY);
3760         final NotificationRecord parent = generateNotificationRecord(
3761                 mTestNotificationChannel, 1, "group", true);
3762         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3763         final NotificationRecord child = generateNotificationRecord(
3764                 mTestNotificationChannel, 2, "group", false);
3765         final NotificationRecord child2 = generateNotificationRecord(
3766                 mTestNotificationChannel, 3, "group", false);
3767         final NotificationRecord newGroup = generateNotificationRecord(
3768                 mTestNotificationChannel, 4, "group2", false);
3769         mService.addNotification(parent);
3770         mService.addNotification(child);
3771         mService.addNotification(child2);
3772         mService.addNotification(newGroup);
3773         mService.getBinderService().cancelNotificationsFromListener(null, null);
3774         waitForIdle();
3775         StatusBarNotification[] notifs =
3776                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3777         assertEquals(0, notifs.length);
3778     }
3779 
3780     @Test
testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()3781     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()
3782             throws Exception {
3783         when(mAmi.applyForegroundServiceNotification(
3784                 any(), anyString(), anyInt(), anyString(), anyInt()))
3785                 .thenReturn(SHOW_IMMEDIATELY);
3786         final NotificationRecord parent = generateNotificationRecord(
3787                 mTestNotificationChannel, 1, "group", true);
3788         final NotificationRecord child = generateNotificationRecord(
3789                 mTestNotificationChannel, 2, "group", false);
3790         final NotificationRecord child2 = generateNotificationRecord(
3791                 mTestNotificationChannel, 3, "group", false);
3792         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3793         final NotificationRecord newGroup = generateNotificationRecord(
3794                 mTestNotificationChannel, 4, "group2", false);
3795         mService.addNotification(parent);
3796         mService.addNotification(child);
3797         mService.addNotification(child2);
3798         mService.addNotification(newGroup);
3799         mService.getBinderService().cancelNotificationsFromListener(null, null);
3800         waitForIdle();
3801         StatusBarNotification[] notifs =
3802                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3803         assertEquals(0, notifs.length);
3804     }
3805 
3806     @Test
testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()3807     public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()
3808             throws Exception {
3809         final NotificationRecord parent = generateNotificationRecord(
3810                 mTestNotificationChannel, 1, "group", true);
3811         parent.getNotification().flags |= FLAG_NO_CLEAR;
3812         final NotificationRecord child = generateNotificationRecord(
3813                 mTestNotificationChannel, 2, "group", false);
3814         final NotificationRecord child2 = generateNotificationRecord(
3815                 mTestNotificationChannel, 3, "group", false);
3816         final NotificationRecord newGroup = generateNotificationRecord(
3817                 mTestNotificationChannel, 4, "group2", false);
3818         mService.addNotification(parent);
3819         mService.addNotification(child);
3820         mService.addNotification(child2);
3821         mService.addNotification(newGroup);
3822         mService.getBinderService().cancelNotificationsFromListener(null, null);
3823         waitForIdle();
3824         StatusBarNotification[] notifs =
3825                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3826         assertEquals(1, notifs.length);
3827     }
3828 
3829     @Test
testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()3830     public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()
3831             throws Exception {
3832         final NotificationRecord parent = generateNotificationRecord(
3833                 mTestNotificationChannel, 1, "group", true);
3834         final NotificationRecord child = generateNotificationRecord(
3835                 mTestNotificationChannel, 2, "group", false);
3836         final NotificationRecord child2 = generateNotificationRecord(
3837                 mTestNotificationChannel, 3, "group", false);
3838         child2.getNotification().flags |= FLAG_NO_CLEAR;
3839         final NotificationRecord newGroup = generateNotificationRecord(
3840                 mTestNotificationChannel, 4, "group2", false);
3841         mService.addNotification(parent);
3842         mService.addNotification(child);
3843         mService.addNotification(child2);
3844         mService.addNotification(newGroup);
3845         mService.getBinderService().cancelNotificationsFromListener(null, null);
3846         waitForIdle();
3847         StatusBarNotification[] notifs =
3848                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3849         assertEquals(1, notifs.length);
3850     }
3851 
3852     @Test
testCancelNotificationsFromListener_clearAll_Ongoing()3853     public void testCancelNotificationsFromListener_clearAll_Ongoing()
3854             throws Exception {
3855         final NotificationRecord child2 = generateNotificationRecord(
3856                 mTestNotificationChannel, 3, null, false);
3857         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3858         mService.addNotification(child2);
3859         String[] keys = {child2.getSbn().getKey()};
3860         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3861         waitForIdle();
3862         StatusBarNotification[] notifs =
3863                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3864         assertEquals(1, notifs.length);
3865     }
3866 
3867     @Test
testCancelNotificationsFromListener_clearAll_NoClear()3868     public void testCancelNotificationsFromListener_clearAll_NoClear()
3869             throws Exception {
3870         final NotificationRecord child2 = generateNotificationRecord(
3871                 mTestNotificationChannel, 3, null, false);
3872         child2.getNotification().flags |= FLAG_NO_CLEAR;
3873         mService.addNotification(child2);
3874         mService.getBinderService().cancelNotificationsFromListener(null, null);
3875         waitForIdle();
3876         StatusBarNotification[] notifs =
3877                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3878         assertEquals(1, notifs.length);
3879     }
3880 
3881     @Test
testCancelNotificationsFromListener_clearAll_Fgs()3882     public void testCancelNotificationsFromListener_clearAll_Fgs()
3883             throws Exception {
3884         when(mAmi.applyForegroundServiceNotification(
3885                 any(), anyString(), anyInt(), anyString(), anyInt()))
3886                 .thenReturn(SHOW_IMMEDIATELY);
3887         final NotificationRecord child2 = generateNotificationRecord(
3888                 mTestNotificationChannel, 3, null, false);
3889         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3890         mService.addNotification(child2);
3891         mService.getBinderService().cancelNotificationsFromListener(null, null);
3892         waitForIdle();
3893         StatusBarNotification[] notifs =
3894                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3895         assertEquals(0, notifs.length);
3896     }
3897 
3898     @Test
3899     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()3900     public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()
3901             throws Exception {
3902         final NotificationRecord notif = generateNotificationRecord(
3903                 mTestNotificationChannel, 1, null, false);
3904         notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3905         mService.addNotification(notif);
3906         verify(mWorkerHandler, times(0))
3907                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3908         mService.getBinderService().cancelNotificationsFromListener(null, null);
3909         waitForIdle();
3910         // Notification not cancelled.
3911         StatusBarNotification[] notifs =
3912                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3913         assertThat(notifs.length).isEqualTo(1);
3914 
3915         // Checks that a post update is sent.
3916         verify(mWorkerHandler, times(1))
3917                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3918         ArgumentCaptor<NotificationRecord> captor =
3919                 ArgumentCaptor.forClass(NotificationRecord.class);
3920         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3921                 anyBoolean());
3922         assertThat(captor.getValue().getNotification().flags
3923                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3924                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3925     }
3926 
3927     @Test
testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()3928     public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()
3929             throws Exception {
3930         final NotificationRecord parent = generateNotificationRecord(
3931                 mTestNotificationChannel, 1, "group", true);
3932         parent.getNotification().flags |= FLAG_ONGOING_EVENT;
3933         final NotificationRecord child = generateNotificationRecord(
3934                 mTestNotificationChannel, 2, "group", false);
3935         final NotificationRecord child2 = generateNotificationRecord(
3936                 mTestNotificationChannel, 3, "group", false);
3937         final NotificationRecord newGroup = generateNotificationRecord(
3938                 mTestNotificationChannel, 4, "group2", false);
3939         mService.addNotification(parent);
3940         mService.addNotification(child);
3941         mService.addNotification(child2);
3942         mService.addNotification(newGroup);
3943         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3944                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3945         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3946         waitForIdle();
3947         StatusBarNotification[] notifs =
3948                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3949         assertEquals(1, notifs.length);
3950     }
3951 
3952     @Test
testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()3953     public void testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()
3954             throws Exception {
3955         final NotificationRecord parent = generateNotificationRecord(
3956                 mTestNotificationChannel, 1, "group", true);
3957         final NotificationRecord child = generateNotificationRecord(
3958                 mTestNotificationChannel, 2, "group", false);
3959         final NotificationRecord child2 = generateNotificationRecord(
3960                 mTestNotificationChannel, 3, "group", false);
3961         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3962         final NotificationRecord newGroup = generateNotificationRecord(
3963                 mTestNotificationChannel, 4, "group2", false);
3964         mService.addNotification(parent);
3965         mService.addNotification(child);
3966         mService.addNotification(child2);
3967         mService.addNotification(newGroup);
3968         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3969                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3970         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3971         waitForIdle();
3972         StatusBarNotification[] notifs =
3973                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3974         assertEquals(1, notifs.length);
3975     }
3976 
3977     @Test
testCancelNotificationsFromListener_byKey_GroupWithFgsParent()3978     public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent()
3979             throws Exception {
3980         when(mAmi.applyForegroundServiceNotification(
3981                 any(), anyString(), anyInt(), anyString(), anyInt()))
3982                 .thenReturn(SHOW_IMMEDIATELY);
3983         final NotificationRecord parent = generateNotificationRecord(
3984                 mTestNotificationChannel, 1, "group", true);
3985         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3986         final NotificationRecord child = generateNotificationRecord(
3987                 mTestNotificationChannel, 2, "group", false);
3988         final NotificationRecord child2 = generateNotificationRecord(
3989                 mTestNotificationChannel, 3, "group", false);
3990         final NotificationRecord newGroup = generateNotificationRecord(
3991                 mTestNotificationChannel, 4, "group2", false);
3992         mService.addNotification(parent);
3993         mService.addNotification(child);
3994         mService.addNotification(child2);
3995         mService.addNotification(newGroup);
3996         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3997                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3998         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3999         waitForIdle();
4000         StatusBarNotification[] notifs =
4001                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4002         assertEquals(0, notifs.length);
4003     }
4004 
4005     @Test
testCancelNotificationsFromListener_byKey_GroupWithFgsChild()4006     public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild()
4007             throws Exception {
4008         when(mAmi.applyForegroundServiceNotification(
4009                 any(), anyString(), anyInt(), anyString(), anyInt()))
4010                 .thenReturn(SHOW_IMMEDIATELY);
4011         final NotificationRecord parent = generateNotificationRecord(
4012                 mTestNotificationChannel, 1, "group", true);
4013         final NotificationRecord child = generateNotificationRecord(
4014                 mTestNotificationChannel, 2, "group", false);
4015         final NotificationRecord child2 = generateNotificationRecord(
4016                 mTestNotificationChannel, 3, "group", false);
4017         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4018         final NotificationRecord newGroup = generateNotificationRecord(
4019                 mTestNotificationChannel, 4, "group2", false);
4020         mService.addNotification(parent);
4021         mService.addNotification(child);
4022         mService.addNotification(child2);
4023         mService.addNotification(newGroup);
4024         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4025                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4026         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4027         waitForIdle();
4028         StatusBarNotification[] notifs =
4029                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4030         assertEquals(0, notifs.length);
4031     }
4032 
4033     @Test
testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()4034     public void testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()
4035             throws Exception {
4036         final NotificationRecord parent = generateNotificationRecord(
4037                 mTestNotificationChannel, 1, "group", true);
4038         parent.getNotification().flags |= FLAG_NO_CLEAR;
4039         final NotificationRecord child = generateNotificationRecord(
4040                 mTestNotificationChannel, 2, "group", false);
4041         final NotificationRecord child2 = generateNotificationRecord(
4042                 mTestNotificationChannel, 3, "group", false);
4043         final NotificationRecord newGroup = generateNotificationRecord(
4044                 mTestNotificationChannel, 4, "group2", false);
4045         mService.addNotification(parent);
4046         mService.addNotification(child);
4047         mService.addNotification(child2);
4048         mService.addNotification(newGroup);
4049         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4050                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4051         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4052         waitForIdle();
4053         StatusBarNotification[] notifs =
4054                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4055         assertEquals(0, notifs.length);
4056     }
4057 
4058     @Test
testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()4059     public void testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()
4060             throws Exception {
4061         final NotificationRecord parent = generateNotificationRecord(
4062                 mTestNotificationChannel, 1, "group", true);
4063         final NotificationRecord child = generateNotificationRecord(
4064                 mTestNotificationChannel, 2, "group", false);
4065         final NotificationRecord child2 = generateNotificationRecord(
4066                 mTestNotificationChannel, 3, "group", false);
4067         child2.getNotification().flags |= FLAG_NO_CLEAR;
4068         final NotificationRecord newGroup = generateNotificationRecord(
4069                 mTestNotificationChannel, 4, "group2", false);
4070         mService.addNotification(parent);
4071         mService.addNotification(child);
4072         mService.addNotification(child2);
4073         mService.addNotification(newGroup);
4074         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4075                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4076         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4077         waitForIdle();
4078         StatusBarNotification[] notifs =
4079                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4080         assertEquals(0, notifs.length);
4081     }
4082 
4083     @Test
testCancelNotificationsFromListener_byKey_Ongoing()4084     public void testCancelNotificationsFromListener_byKey_Ongoing()
4085             throws Exception {
4086         final NotificationRecord child2 = generateNotificationRecord(
4087                 mTestNotificationChannel, 3, null, false);
4088         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
4089         mService.addNotification(child2);
4090         String[] keys = {child2.getSbn().getKey()};
4091         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4092         waitForIdle();
4093         StatusBarNotification[] notifs =
4094                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
4095         assertEquals(1, notifs.length);
4096     }
4097 
4098     @Test
testCancelNotificationsFromListener_byKey_NoClear()4099     public void testCancelNotificationsFromListener_byKey_NoClear()
4100             throws Exception {
4101         final NotificationRecord child2 = generateNotificationRecord(
4102                 mTestNotificationChannel, 3, null, false);
4103         child2.getNotification().flags |= FLAG_NO_CLEAR;
4104         mService.addNotification(child2);
4105         String[] keys = {child2.getSbn().getKey()};
4106         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4107         waitForIdle();
4108         StatusBarNotification[] notifs =
4109                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
4110         assertEquals(0, notifs.length);
4111     }
4112 
4113     @Test
testCancelNotificationsFromListener_byKey_Fgs()4114     public void testCancelNotificationsFromListener_byKey_Fgs()
4115             throws Exception {
4116         when(mAmi.applyForegroundServiceNotification(
4117                 any(), anyString(), anyInt(), anyString(), anyInt()))
4118                 .thenReturn(SHOW_IMMEDIATELY);
4119         final NotificationRecord child2 = generateNotificationRecord(
4120                 mTestNotificationChannel, 3, null, false);
4121         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4122         mService.addNotification(child2);
4123         String[] keys = {child2.getSbn().getKey()};
4124         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4125         waitForIdle();
4126         StatusBarNotification[] notifs =
4127                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
4128         assertEquals(0, notifs.length);
4129     }
4130 
4131     @Test
4132     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()4133     public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()
4134             throws Exception {
4135         final NotificationRecord notif = generateNotificationRecord(
4136                 mTestNotificationChannel, 3, null, false);
4137         notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
4138         mService.addNotification(notif);
4139         String[] keys = {notif.getSbn().getKey()};
4140         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4141         waitForIdle();
4142         StatusBarNotification[] notifs =
4143                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
4144         assertEquals(1, notifs.length);
4145 
4146         // Checks that a post update is sent.
4147         verify(mWorkerHandler, times(1))
4148                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
4149         ArgumentCaptor<NotificationRecord> captor =
4150                 ArgumentCaptor.forClass(NotificationRecord.class);
4151         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
4152                 anyBoolean());
4153         assertThat(captor.getValue().getNotification().flags
4154                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
4155                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
4156     }
4157 
4158     @Test
testGroupInstanceIds()4159     public void testGroupInstanceIds() throws Exception {
4160         final NotificationRecord group1 = generateNotificationRecord(
4161                 mTestNotificationChannel, 1, "group1", true);
4162         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds",
4163                 group1.getSbn().getId(), group1.getSbn().getNotification(),
4164                 group1.getSbn().getUserId());
4165         waitForIdle();
4166 
4167         // same group, child, should be returned
4168         final NotificationRecord group1Child = generateNotificationRecord(
4169                 mTestNotificationChannel, 2, "group1", false);
4170         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds",
4171                 group1Child.getSbn().getId(),
4172                 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
4173         waitForIdle();
4174 
4175         assertEquals(2, mNotificationRecordLogger.numCalls());
4176         assertEquals(mNotificationRecordLogger.get(0).getInstanceId(),
4177                 mNotificationRecordLogger.get(1).groupInstanceId.getId());
4178     }
4179 
4180     @Test
testFindGroupNotificationsLocked()4181     public void testFindGroupNotificationsLocked() throws Exception {
4182         // make sure the same notification can be found in both lists and returned
4183         final NotificationRecord group1 = generateNotificationRecord(
4184                 mTestNotificationChannel, 1, "group1", true);
4185         mService.addEnqueuedNotification(group1);
4186         mService.addNotification(group1);
4187 
4188         // should not be returned
4189         final NotificationRecord group2 = generateNotificationRecord(
4190                 mTestNotificationChannel, 2, "group2", true);
4191         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
4192                 group2.getSbn().getId(), group2.getSbn().getNotification(),
4193                 group2.getSbn().getUserId());
4194         waitForIdle();
4195 
4196         // should not be returned
4197         final NotificationRecord nonGroup = generateNotificationRecord(
4198                 mTestNotificationChannel, 3, null, false);
4199         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
4200                 nonGroup.getSbn().getId(), nonGroup.getSbn().getNotification(),
4201                 nonGroup.getSbn().getUserId());
4202         waitForIdle();
4203 
4204         // same group, child, should be returned
4205         final NotificationRecord group1Child = generateNotificationRecord(
4206                 mTestNotificationChannel, 4, "group1", false);
4207         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
4208                 group1Child.getSbn().getId(),
4209                 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
4210         waitForIdle();
4211 
4212         List<NotificationRecord> inGroup1 =
4213                 mService.findGroupNotificationsLocked(mPkg, group1.getGroupKey(),
4214                         group1.getSbn().getUserId());
4215         assertEquals(3, inGroup1.size());
4216         for (NotificationRecord record : inGroup1) {
4217             assertTrue(record.getGroupKey().equals(group1.getGroupKey()));
4218             assertTrue(record.getSbn().getId() == 1 || record.getSbn().getId() == 4);
4219         }
4220     }
4221 
4222     @Test
testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing()4223     public void testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing() throws Exception {
4224         final NotificationRecord notif = generateNotificationRecord(
4225                 mTestNotificationChannel, 1, "group", true);
4226         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
4227         mService.addNotification(notif);
4228         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0,
4229                 Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL);
4230         waitForIdle();
4231         StatusBarNotification[] notifs =
4232                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
4233         assertEquals(0, notifs.length);
4234     }
4235 
4236     @Test
testAppInitiatedCancelAllNotifications_CancelsOngoingFlag()4237     public void testAppInitiatedCancelAllNotifications_CancelsOngoingFlag() throws Exception {
4238         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
4239         sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
4240         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
4241                 "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag",
4242                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
4243         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
4244         waitForIdle();
4245         StatusBarNotification[] notifs =
4246                 mBinderService.getActiveNotifications(sbn.getPackageName());
4247         assertEquals(0, notifs.length);
4248     }
4249 
4250     @Test
testCancelAllNotificationsInt_CancelsOngoingFlag()4251     public void testCancelAllNotificationsInt_CancelsOngoingFlag() throws Exception {
4252         final NotificationRecord notif = generateNotificationRecord(
4253                 mTestNotificationChannel, 1, "group", true);
4254         notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
4255         mService.addNotification(notif);
4256         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
4257                 notif.getUserId(), REASON_CANCEL);
4258         waitForIdle();
4259         StatusBarNotification[] notifs =
4260                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
4261         assertEquals(0, notifs.length);
4262     }
4263 
4264     @Test
testUserInitiatedCancelAllWithGroup_OngoingFlag()4265     public void testUserInitiatedCancelAllWithGroup_OngoingFlag() throws Exception {
4266         final NotificationRecord parent = generateNotificationRecord(
4267                 mTestNotificationChannel, 1, "group", true);
4268         final NotificationRecord child = generateNotificationRecord(
4269                 mTestNotificationChannel, 2, "group", false);
4270         final NotificationRecord child2 = generateNotificationRecord(
4271                 mTestNotificationChannel, 3, "group", false);
4272         child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
4273         final NotificationRecord newGroup = generateNotificationRecord(
4274                 mTestNotificationChannel, 4, "group2", false);
4275         mService.addNotification(parent);
4276         mService.addNotification(child);
4277         mService.addNotification(child2);
4278         mService.addNotification(newGroup);
4279         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
4280                 parent.getUserId());
4281         waitForIdle();
4282         StatusBarNotification[] notifs =
4283                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4284         assertEquals(1, notifs.length);
4285     }
4286 
4287     @Test
testUserInitiatedCancelAllWithGroup_NoClearFlag()4288     public void testUserInitiatedCancelAllWithGroup_NoClearFlag() throws Exception {
4289         final NotificationRecord parent = generateNotificationRecord(
4290                 mTestNotificationChannel, 1, "group", true);
4291         final NotificationRecord child = generateNotificationRecord(
4292                 mTestNotificationChannel, 2, "group", false);
4293         final NotificationRecord child2 = generateNotificationRecord(
4294                 mTestNotificationChannel, 3, "group", false);
4295         child2.getNotification().flags |= Notification.FLAG_NO_CLEAR;
4296         final NotificationRecord newGroup = generateNotificationRecord(
4297                 mTestNotificationChannel, 4, "group2", false);
4298         mService.addNotification(parent);
4299         mService.addNotification(child);
4300         mService.addNotification(child2);
4301         mService.addNotification(newGroup);
4302         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
4303                 parent.getUserId());
4304         waitForIdle();
4305         StatusBarNotification[] notifs =
4306                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4307         assertEquals(1, notifs.length);
4308     }
4309 
4310     @Test
testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag()4311     public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception {
4312         when(mAmi.applyForegroundServiceNotification(
4313                 any(), anyString(), anyInt(), anyString(), anyInt()))
4314                 .thenReturn(SHOW_IMMEDIATELY);
4315         final NotificationRecord parent = generateNotificationRecord(
4316                 mTestNotificationChannel, 1, "group", true);
4317         final NotificationRecord child = generateNotificationRecord(
4318                 mTestNotificationChannel, 2, "group", false);
4319         final NotificationRecord child2 = generateNotificationRecord(
4320                 mTestNotificationChannel, 3, "group", false);
4321         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4322         final NotificationRecord newGroup = generateNotificationRecord(
4323                 mTestNotificationChannel, 4, "group2", false);
4324         mService.addNotification(parent);
4325         mService.addNotification(child);
4326         mService.addNotification(child2);
4327         mService.addNotification(newGroup);
4328         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
4329                 parent.getUserId());
4330         waitForIdle();
4331         StatusBarNotification[] notifs =
4332                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4333         assertEquals(0, notifs.length);
4334     }
4335 
4336     @Test
testDefaultChannelUpdatesApp_postMigrationToPermissions()4337     public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception {
4338         final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
4339                 PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
4340                 NotificationChannel.DEFAULT_CHANNEL_ID);
4341         defaultChannel.setImportance(IMPORTANCE_NONE);
4342 
4343         mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
4344 
4345         verify(mPermissionHelper).setNotificationPermission(
4346                 PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
4347     }
4348 
4349     @Test
testPostNotification_appPermissionFixed()4350     public void testPostNotification_appPermissionFixed() throws Exception {
4351         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
4352         when(mPermissionHelper.isPermissionFixed(mPkg, mUserId)).thenReturn(true);
4353 
4354         NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
4355         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
4356                 "testPostNotification_appPermissionFixed", 0,
4357                 temp.getNotification(), mUserId);
4358         waitForIdle();
4359         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
4360         StatusBarNotification[] notifs =
4361                 mBinderService.getActiveNotifications(mPkg);
4362         assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
4363     }
4364 
4365     @Test
testSummaryNotification_appPermissionFixed()4366     public void testSummaryNotification_appPermissionFixed() {
4367         NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
4368         mService.addNotification(temp);
4369 
4370         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
4371         when(mPermissionHelper.isPermissionFixed(mPkg, temp.getUserId())).thenReturn(true);
4372 
4373         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
4374             mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
4375 
4376         NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(),
4377             temp.getSbn().getPackageName(), temp.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr);
4378 
4379         assertThat(r.isImportanceFixed()).isTrue();
4380     }
4381 
4382     @Test
testTvExtenderChannelOverride_onTv()4383     public void testTvExtenderChannelOverride_onTv() throws Exception {
4384         mService.setIsTelevision(true);
4385         mService.setPreferencesHelper(mPreferencesHelper);
4386         when(mPreferencesHelper.getNotificationChannel(
4387                 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
4388                     new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
4389 
4390         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
4391         mBinderService.enqueueNotificationWithTag(
4392                 mPkg,
4393                 mPkg,
4394                 "testTvExtenderChannelOverride_onTv",
4395                 0,
4396                 generateNotificationRecord(null, tv).getNotification(),
4397                 mUserId);
4398         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
4399                 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean());
4400     }
4401 
4402     @Test
testTvExtenderChannelOverride_notOnTv()4403     public void testTvExtenderChannelOverride_notOnTv() throws Exception {
4404         mService.setIsTelevision(false);
4405         mService.setPreferencesHelper(mPreferencesHelper);
4406         when(mPreferencesHelper.getNotificationChannel(
4407                 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
4408                 mTestNotificationChannel);
4409 
4410         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
4411         mBinderService.enqueueNotificationWithTag(
4412                 mPkg,
4413                 mPkg,
4414                 "testTvExtenderChannelOverride_notOnTv",
4415                 0,
4416                 generateNotificationRecord(null, tv).getNotification(),
4417                 mUserId);
4418         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
4419                 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null),
4420                 anyBoolean(), anyBoolean());
4421     }
4422 
4423     @Test
onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()4424     public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()
4425             throws RemoteException {
4426         // Have preexisting posted notifications from revoked package and other packages.
4427         mService.addNotification(new NotificationRecord(mContext,
4428                 generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel));
4429         mService.addNotification(new NotificationRecord(mContext,
4430                 generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
4431         // Have preexisting enqueued notifications from revoked package and other packages.
4432         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4433                 generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel));
4434         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4435                 generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
4436         assertThat(mService.mNotificationList).hasSize(2);
4437         assertThat(mService.mEnqueuedNotifications).hasSize(2);
4438 
4439         when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001);
4440         when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
4441 
4442         mOnPermissionChangeListener.onOpChanged(
4443                 AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0);
4444         waitForIdle();
4445 
4446         assertThat(mService.mNotificationList).hasSize(1);
4447         assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other");
4448         assertThat(mService.mEnqueuedNotifications).hasSize(1);
4449         assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo(
4450                 "other");
4451     }
4452 
4453     @Test
onOpChanged_permissionStillGranted_notificationsAreNotAffected()4454     public void onOpChanged_permissionStillGranted_notificationsAreNotAffected()
4455             throws RemoteException {
4456         // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission
4457         // being now granted, AND having previously posted notifications from said package) should
4458         // never happen (if we trust the broadcasts are correct). So this test is for a what-if
4459         // scenario, to verify we still handle it reasonably.
4460 
4461         // Have preexisting posted notifications from specific package and other packages.
4462         mService.addNotification(new NotificationRecord(mContext,
4463                 generateSbn("granted", 1001, 1, 0), mTestNotificationChannel));
4464         mService.addNotification(new NotificationRecord(mContext,
4465                 generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
4466         // Have preexisting enqueued notifications from specific package and other packages.
4467         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4468                 generateSbn("granted", 1001, 3, 0), mTestNotificationChannel));
4469         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4470                 generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
4471         assertThat(mService.mNotificationList).hasSize(2);
4472         assertThat(mService.mEnqueuedNotifications).hasSize(2);
4473 
4474         when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001);
4475         when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
4476 
4477         mOnPermissionChangeListener.onOpChanged(
4478                 AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0);
4479         waitForIdle();
4480 
4481         assertThat(mService.mNotificationList).hasSize(2);
4482         assertThat(mService.mEnqueuedNotifications).hasSize(2);
4483     }
4484 
4485     @Test
onOpChanged_notInitializedUser_ignored()4486     public void onOpChanged_notInitializedUser_ignored() throws RemoteException {
4487         when(mUmInternal.isUserInitialized(eq(0))).thenReturn(false);
4488 
4489         mOnPermissionChangeListener.onOpChanged(
4490                 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
4491         waitForIdle();
4492 
4493         // We early-exited and didn't even query PM for package details.
4494         verify(mPackageManagerInternal, never()).getPackageUid(any(), anyLong(), anyInt());
4495     }
4496 
4497     @Test
setNotificationsEnabledForPackage_disabling_clearsNotifications()4498     public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception {
4499         mService.addNotification(new NotificationRecord(mContext,
4500                 generateSbn("package", 1001, 1, 0), mTestNotificationChannel));
4501         assertThat(mService.mNotificationList).hasSize(1);
4502         when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001);
4503         when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn(
4504                 true);
4505 
4506         // Start with granted permission and simulate effect of revoking it.
4507         when(mPermissionHelper.hasPermission(1001)).thenReturn(true);
4508         doAnswer(invocation -> {
4509             when(mPermissionHelper.hasPermission(1001)).thenReturn(false);
4510             mOnPermissionChangeListener.onOpChanged(
4511                     AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
4512             return null;
4513         }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true);
4514 
4515         mBinderService.setNotificationsEnabledForPackage("package", 1001, false);
4516         waitForIdle();
4517 
4518         assertThat(mService.mNotificationList).hasSize(0);
4519 
4520         mTestableLooper.moveTimeForward(500);
4521         waitForIdle();
4522         verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null));
4523     }
4524 
4525     @Test
testUpdateAppNotifyCreatorBlock()4526     public void testUpdateAppNotifyCreatorBlock() throws Exception {
4527         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
4528 
4529         mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, false);
4530         Thread.sleep(500);
4531         waitForIdle();
4532 
4533         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4534         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4535 
4536         assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
4537                 captor.getValue().getAction());
4538         assertEquals(mPkg, captor.getValue().getPackage());
4539         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
4540     }
4541 
4542     @Test
testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting()4543     public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
4544         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
4545 
4546         mBinderService.setNotificationsEnabledForPackage(mPkg, 0, false);
4547         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
4548     }
4549 
4550     @Test
testUpdateAppNotifyCreatorUnblock()4551     public void testUpdateAppNotifyCreatorUnblock() throws Exception {
4552         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
4553 
4554         mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, true);
4555         Thread.sleep(500);
4556         waitForIdle();
4557 
4558         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4559         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4560 
4561         assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
4562                 captor.getValue().getAction());
4563         assertEquals(mPkg, captor.getValue().getPackage());
4564         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
4565     }
4566 
4567     @Test
testUpdateChannelNotifyCreatorBlock()4568     public void testUpdateChannelNotifyCreatorBlock() throws Exception {
4569         mService.setPreferencesHelper(mPreferencesHelper);
4570         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4571                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4572                 .thenReturn(mTestNotificationChannel);
4573 
4574         NotificationChannel updatedChannel =
4575                 new NotificationChannel(mTestNotificationChannel.getId(),
4576                         mTestNotificationChannel.getName(), IMPORTANCE_NONE);
4577 
4578         mBinderService.updateNotificationChannelForPackage(mPkg, 0, updatedChannel);
4579         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4580         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4581 
4582         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
4583                 captor.getValue().getAction());
4584         assertEquals(mPkg, captor.getValue().getPackage());
4585         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
4586                         NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
4587         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4588     }
4589 
4590     @Test
testUpdateChannelNotifyCreatorUnblock()4591     public void testUpdateChannelNotifyCreatorUnblock() throws Exception {
4592         NotificationChannel existingChannel =
4593                 new NotificationChannel(mTestNotificationChannel.getId(),
4594                         mTestNotificationChannel.getName(), IMPORTANCE_NONE);
4595         mService.setPreferencesHelper(mPreferencesHelper);
4596         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4597                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4598                 .thenReturn(existingChannel);
4599 
4600         mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel);
4601         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4602         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4603 
4604         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
4605                 captor.getValue().getAction());
4606         assertEquals(mPkg, captor.getValue().getPackage());
4607         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
4608                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
4609         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4610     }
4611 
4612     @Test
testUpdateChannelNoNotifyCreatorOtherChanges()4613     public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception {
4614         NotificationChannel existingChannel =
4615                 new NotificationChannel(mTestNotificationChannel.getId(),
4616                         mTestNotificationChannel.getName(), IMPORTANCE_MAX);
4617         mService.setPreferencesHelper(mPreferencesHelper);
4618         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4619                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4620                 .thenReturn(existingChannel);
4621 
4622         mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel);
4623         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
4624     }
4625 
4626     @Test
testUpdateGroupNotifyCreatorBlock()4627     public void testUpdateGroupNotifyCreatorBlock() throws Exception {
4628         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
4629         mService.setPreferencesHelper(mPreferencesHelper);
4630         when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()),
4631                 eq(mPkg), anyInt()))
4632                 .thenReturn(existing);
4633 
4634         NotificationChannelGroup updated = new NotificationChannelGroup("id", "name");
4635         updated.setBlocked(true);
4636 
4637         mBinderService.updateNotificationChannelGroupForPackage(mPkg, 0, updated);
4638         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4639         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4640 
4641         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
4642                 captor.getValue().getAction());
4643         assertEquals(mPkg, captor.getValue().getPackage());
4644         assertEquals(existing.getId(), captor.getValue().getStringExtra(
4645                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
4646         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4647     }
4648 
4649     @Test
testUpdateGroupNotifyCreatorUnblock()4650     public void testUpdateGroupNotifyCreatorUnblock() throws Exception {
4651         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
4652         existing.setBlocked(true);
4653         mService.setPreferencesHelper(mPreferencesHelper);
4654         when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()),
4655                 eq(mPkg), anyInt()))
4656                 .thenReturn(existing);
4657 
4658         mBinderService.updateNotificationChannelGroupForPackage(
4659                 mPkg, 0, new NotificationChannelGroup("id", "name"));
4660         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4661         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4662 
4663         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
4664                 captor.getValue().getAction());
4665         assertEquals(mPkg, captor.getValue().getPackage());
4666         assertEquals(existing.getId(), captor.getValue().getStringExtra(
4667                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
4668         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4669     }
4670 
4671     @Test
testUpdateGroupNoNotifyCreatorOtherChanges()4672     public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception {
4673         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
4674         mService.setPreferencesHelper(mPreferencesHelper);
4675         when(mPreferencesHelper.getNotificationChannelGroup(
4676                 eq(existing.getId()), eq(mPkg), anyInt()))
4677                 .thenReturn(existing);
4678 
4679         mBinderService.updateNotificationChannelGroupForPackage(
4680                 mPkg, 0, new NotificationChannelGroup("id", "new name"));
4681         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
4682     }
4683 
4684     @Test
testCreateChannelNotifyListener()4685     public void testCreateChannelNotifyListener() throws Exception {
4686         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4687                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4688         mService.setPreferencesHelper(mPreferencesHelper);
4689         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4690                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4691                 .thenReturn(mTestNotificationChannel);
4692         NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW);
4693         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4694                 eq(channel2.getId()), anyBoolean()))
4695                 .thenReturn(channel2);
4696         when(mPreferencesHelper.createNotificationChannel(eq(mPkg), anyInt(),
4697                 eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()))
4698                 .thenReturn(true);
4699 
4700         reset(mListeners);
4701         mBinderService.createNotificationChannels(mPkg,
4702                 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2)));
4703         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4704                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4705                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4706         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4707                 eq(Process.myUserHandle()), eq(channel2),
4708                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4709     }
4710 
4711     @Test
testCreateChannelGroupNotifyListener()4712     public void testCreateChannelGroupNotifyListener() throws Exception {
4713         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4714                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4715         mService.setPreferencesHelper(mPreferencesHelper);
4716         NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
4717         NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
4718 
4719         reset(mListeners);
4720         mBinderService.createNotificationChannelGroups(mPkg,
4721                 new ParceledListSlice(Arrays.asList(group1, group2)));
4722         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4723                 eq(Process.myUserHandle()), eq(group1),
4724                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4725         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4726                 eq(Process.myUserHandle()), eq(group2),
4727                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4728     }
4729 
4730     @Test
testUpdateChannelNotifyListener()4731     public void testUpdateChannelNotifyListener() throws Exception {
4732         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4733                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4734         mService.setPreferencesHelper(mPreferencesHelper);
4735         mTestNotificationChannel.setLightColor(Color.CYAN);
4736         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4737                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4738                 .thenReturn(mTestNotificationChannel);
4739 
4740         reset(mListeners);
4741         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel);
4742         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4743                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4744                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4745     }
4746 
4747     @Test
testDeleteChannelNotifyListener()4748     public void testDeleteChannelNotifyListener() throws Exception {
4749         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4750                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4751         mService.setPreferencesHelper(mPreferencesHelper);
4752         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4753                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4754                 .thenReturn(mTestNotificationChannel);
4755         when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
4756                 eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true);
4757         reset(mListeners);
4758         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
4759         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4760                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4761                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4762     }
4763 
4764     @Test
4765     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testAppsCannotDeleteBundleChannel()4766     public void testAppsCannotDeleteBundleChannel() throws Exception {
4767         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4768                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4769         mService.setPreferencesHelper(mPreferencesHelper);
4770         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4771                 eq(NEWS_ID), anyBoolean()))
4772                 .thenReturn(mTestNotificationChannel);
4773         when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
4774                 eq(NEWS_ID), anyInt(), anyBoolean())).thenReturn(true);
4775         reset(mListeners);
4776         mBinderService.deleteNotificationChannel(mPkg, NEWS_ID);
4777         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4778                 eq(Process.myUserHandle()), any(),
4779                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4780     }
4781 
4782     @Test
testDeleteChannelOnlyDoExtraWorkIfExisted()4783     public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
4784         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4785                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4786         mService.setPreferencesHelper(mPreferencesHelper);
4787         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4788                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4789                 .thenReturn(null);
4790         reset(mListeners);
4791         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
4792         verifyNoMoreInteractions(mListeners);
4793         verifyNoMoreInteractions(mHistoryManager);
4794     }
4795 
4796     @Test
testDeleteChannelGroupNotifyListener()4797     public void testDeleteChannelGroupNotifyListener() throws Exception {
4798         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4799                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4800         NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
4801         mService.setPreferencesHelper(mPreferencesHelper);
4802         when(mPreferencesHelper.getNotificationChannelGroupWithChannels(
4803                 eq(mPkg), anyInt(), eq(ncg.getId()), anyBoolean()))
4804                 .thenReturn(ncg);
4805         reset(mListeners);
4806         mBinderService.deleteNotificationChannelGroup(mPkg, ncg.getId());
4807         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4808                 eq(Process.myUserHandle()), eq(ncg),
4809                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4810     }
4811 
4812     @Test
testDeleteChannelGroupChecksForFgses()4813     public void testDeleteChannelGroupChecksForFgses() throws Exception {
4814         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4815                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4816         CountDownLatch latch = new CountDownLatch(2);
4817         mService.createNotificationChannelGroup(
4818                 mPkg, mUid, new NotificationChannelGroup("group", "group"), true, false);
4819         new Thread(() -> {
4820             NotificationChannel notificationChannel = new NotificationChannel("id", "id",
4821                     NotificationManager.IMPORTANCE_HIGH);
4822             notificationChannel.setGroup("group");
4823             ParceledListSlice<NotificationChannel> pls =
4824                     new ParceledListSlice(ImmutableList.of(notificationChannel));
4825             try {
4826                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
4827             } catch (RemoteException e) {
4828                 throw new RuntimeException(e);
4829             }
4830             latch.countDown();
4831         }).start();
4832         new Thread(() -> {
4833             try {
4834                 synchronized (this) {
4835                     wait(5000);
4836                 }
4837                 mService.createNotificationChannelGroup(mPkg, mUid,
4838                         new NotificationChannelGroup("new", "new group"), true, false);
4839                 NotificationChannel notificationChannel =
4840                         new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
4841                 notificationChannel.setGroup("new");
4842                 ParceledListSlice<NotificationChannel> pls =
4843                         new ParceledListSlice(ImmutableList.of(notificationChannel));
4844                 try {
4845                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
4846                 mBinderService.deleteNotificationChannelGroup(mPkg, "group");
4847                 } catch (RemoteException e) {
4848                     throw new RuntimeException(e);
4849                 }
4850             } catch (Exception e) {
4851                 e.printStackTrace();
4852             }
4853             latch.countDown();
4854         }).start();
4855 
4856         latch.await();
4857         verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString());
4858     }
4859 
setUpChannelsForConversationChannelTest()4860     private void setUpChannelsForConversationChannelTest() throws RemoteException {
4861         when(mPreferencesHelper.getNotificationChannel(
4862                 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(false)))
4863                 .thenReturn(mParentChannel);
4864         when(mPreferencesHelper.getConversationNotificationChannel(
4865                 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(CONVERSATION_ID), eq(false), eq(false)))
4866                 .thenReturn(mConversationChannel);
4867         when(mPackageManager.getPackageUid(mPkg, 0, mUserId)).thenReturn(mUid);
4868     }
4869 
4870     @Test
4871     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_cdm_success()4872     public void createConversationChannelForPkgFromPrivilegedListener_cdm_success() throws Exception {
4873         // Set up cdm
4874         mService.setPreferencesHelper(mPreferencesHelper);
4875         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4876                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4877 
4878         // Set up parent channel
4879         setUpChannelsForConversationChannelTest();
4880         final NotificationChannel parentChannelCopy = mParentChannel.copy();
4881 
4882         NotificationChannel createdChannel =
4883                 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4884                     null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID);
4885 
4886         // Verify that a channel is created and a copied channel is returned.
4887         verify(mPreferencesHelper, times(1)).createNotificationChannel(
4888                 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(),
4889                 eq(mUid), anyBoolean());
4890         assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel);
4891         assertThat(createdChannel).isEqualTo(mConversationChannel);
4892 
4893         // Verify that the channel creation is not directly use the parent channel.
4894         verify(mPreferencesHelper, never()).createNotificationChannel(
4895                 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(),
4896                 anyInt(), anyBoolean());
4897 
4898         // Verify that the content of parent channel is not changed.
4899         assertThat(parentChannelCopy).isEqualTo(mParentChannel);
4900     }
4901 
4902     @Test
4903     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess()4904     public void createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess() throws Exception {
4905         // Set up cdm without access
4906         mService.setPreferencesHelper(mPreferencesHelper);
4907         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4908                 .thenReturn(emptyList());
4909 
4910         // Set up parent channel
4911         setUpChannelsForConversationChannelTest();
4912 
4913         try {
4914             mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4915                 null, mPkg, mUser, "parentId", "conversationId");
4916             fail("listeners that don't have a companion device shouldn't be able to call this");
4917         } catch (SecurityException e) {
4918             // pass
4919         }
4920 
4921         verify(mPreferencesHelper, never()).createNotificationChannel(
4922                 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(),
4923                 anyInt(), anyBoolean());
4924     }
4925 
4926     @Test
4927     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_assistant_success()4928     public void createConversationChannelForPkgFromPrivilegedListener_assistant_success() throws Exception {
4929         // Set up assistant
4930         mService.setPreferencesHelper(mPreferencesHelper);
4931         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4932                 .thenReturn(emptyList());
4933         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
4934 
4935         // Set up parent channel
4936         setUpChannelsForConversationChannelTest();
4937         final NotificationChannel parentChannelCopy = mParentChannel.copy();
4938 
4939         NotificationChannel createdChannel =
4940                 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4941                     null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID);
4942 
4943         // Verify that a channel is created and a copied channel is returned.
4944         verify(mPreferencesHelper, times(1)).createNotificationChannel(
4945                 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(),
4946                 eq(mUid), anyBoolean());
4947         assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel);
4948         assertThat(createdChannel).isEqualTo(mConversationChannel);
4949 
4950         // Verify that the channel creation is not directly use the parent channel.
4951         verify(mPreferencesHelper, never()).createNotificationChannel(
4952                 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(),
4953                 anyInt(), anyBoolean());
4954 
4955         // Verify that the content of parent channel is not changed.
4956         assertThat(parentChannelCopy).isEqualTo(mParentChannel);
4957     }
4958 
4959     @Test
4960     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess()4961     public void createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess() throws Exception {
4962         // Set up assistant without access
4963         mService.setPreferencesHelper(mPreferencesHelper);
4964         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4965                 .thenReturn(emptyList());
4966         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
4967 
4968         // Set up parent channel
4969         setUpChannelsForConversationChannelTest();
4970 
4971         try {
4972             mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4973                 null, mPkg, mUser, "parentId", "conversationId");
4974             fail("listeners that don't have a companion device shouldn't be able to call this");
4975         } catch (SecurityException e) {
4976             // pass
4977         }
4978 
4979         verify(mPreferencesHelper, never()).createNotificationChannel(
4980                 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(),
4981                 anyInt(), anyBoolean());
4982     }
4983 
4984     @Test
4985     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_badUser()4986     public void createConversationChannelForPkgFromPrivilegedListener_badUser() throws Exception {
4987         // Set up bad user
4988         mService.setPreferencesHelper(mPreferencesHelper);
4989         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4990                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4991         mListener = mock(ManagedServices.ManagedServiceInfo.class);
4992         mListener.component = new ComponentName(mPkg, mPkg);
4993         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
4994         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
4995 
4996         // Set up parent channel
4997         setUpChannelsForConversationChannelTest();
4998 
4999         try {
5000             mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
5001                 null, mPkg, mUser, "parentId", "conversationId");
5002             fail("listener getting channels from a user they cannot see");
5003         } catch (SecurityException e) {
5004             // pass
5005         }
5006 
5007         verify(mPreferencesHelper, never()).createNotificationChannel(
5008                 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(),
5009                 anyInt(), anyBoolean());
5010     }
5011 
5012     @Test
updateNotificationChannelFromPrivilegedListener_cdm_success()5013     public void updateNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
5014 
5015         mService.setPreferencesHelper(mPreferencesHelper);
5016         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5017                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5018         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5019                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5020                 .thenReturn(mTestNotificationChannel);
5021 
5022         mBinderService.updateNotificationChannelFromPrivilegedListener(
5023                 null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5024 
5025         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5026                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5027 
5028         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5029                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5030                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5031     }
5032 
5033     @Test
updateNotificationChannelFromPrivilegedListener_cdm_noAccess()5034     public void updateNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
5035         mService.setPreferencesHelper(mPreferencesHelper);
5036         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5037                 .thenReturn(emptyList());
5038 
5039         try {
5040             mBinderService.updateNotificationChannelFromPrivilegedListener(
5041                     null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5042             fail("listeners that don't have a companion device shouldn't be able to call this");
5043         } catch (SecurityException e) {
5044             // pass
5045         }
5046 
5047         verify(mPreferencesHelper, never()).updateNotificationChannel(
5048                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5049 
5050         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5051                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5052                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5053     }
5054 
5055     @Test
updateNotificationChannelFromPrivilegedListener_assistant_success()5056     public void updateNotificationChannelFromPrivilegedListener_assistant_success() throws Exception {
5057         mService.setPreferencesHelper(mPreferencesHelper);
5058         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5059                 .thenReturn(emptyList());
5060         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
5061         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5062                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5063                 .thenReturn(mTestNotificationChannel);
5064 
5065         mBinderService.updateNotificationChannelFromPrivilegedListener(
5066                 null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5067 
5068         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5069                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5070 
5071         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5072                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5073                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5074     }
5075 
5076     @Test
updateNotificationChannelFromPrivilegedListener_assistant_noAccess()5077     public void updateNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception {
5078         mService.setPreferencesHelper(mPreferencesHelper);
5079         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5080                 .thenReturn(emptyList());
5081         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
5082 
5083         try {
5084             mBinderService.updateNotificationChannelFromPrivilegedListener(
5085                     null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5086             fail("listeners that don't have a companion device shouldn't be able to call this");
5087         } catch (SecurityException e) {
5088             // pass
5089         }
5090 
5091         verify(mPreferencesHelper, never()).updateNotificationChannel(
5092                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5093 
5094         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5095                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5096                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5097     }
5098 
5099     @Test
updateNotificationChannelFromPrivilegedListener_badUser()5100     public void updateNotificationChannelFromPrivilegedListener_badUser() throws Exception {
5101         mService.setPreferencesHelper(mPreferencesHelper);
5102         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5103                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5104         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5105         mListener.component = new ComponentName(mPkg, mPkg);
5106         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5107         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5108 
5109         try {
5110             mBinderService.updateNotificationChannelFromPrivilegedListener(
5111                     null, mPkg, UserHandle.ALL, mTestNotificationChannel);
5112             fail("incorrectly allowed a change to a user listener cannot see");
5113         } catch (SecurityException e) {
5114             // pass
5115         }
5116 
5117         verify(mPreferencesHelper, never()).updateNotificationChannel(
5118                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5119 
5120         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5121                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5122                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5123     }
5124 
5125     @Test
updateNotificationChannelFromPrivilegedListener_noSoundUriPermission()5126     public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
5127             throws Exception {
5128         mService.setPreferencesHelper(mPreferencesHelper);
5129         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5130                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5131         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5132                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5133                 .thenReturn(mTestNotificationChannel);
5134 
5135         final Uri soundUri = Uri.parse("content://media/test/sound/uri");
5136         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
5137                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
5138         updatedNotificationChannel.setSound(soundUri,
5139                 updatedNotificationChannel.getAudioAttributes());
5140 
5141         doThrow(new SecurityException("no access")).when(mUgmInternal)
5142                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
5143                 anyInt(), eq(Process.myUserHandle().getIdentifier()));
5144 
5145         assertThrows(SecurityException.class,
5146                 () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, mPkg,
5147                 Process.myUserHandle(), updatedNotificationChannel));
5148 
5149         verify(mPreferencesHelper, never()).updateNotificationChannel(
5150                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5151 
5152         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5153                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5154                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5155     }
5156 
5157     @Test
updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()5158     public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
5159             throws Exception {
5160         mService.setPreferencesHelper(mPreferencesHelper);
5161         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5162                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5163         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5164                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5165                 .thenReturn(mTestNotificationChannel);
5166 
5167         final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
5168         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
5169                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
5170         updatedNotificationChannel.setSound(soundUri,
5171                 updatedNotificationChannel.getAudioAttributes());
5172 
5173         doThrow(new SecurityException("no access")).when(mUgmInternal)
5174                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
5175                 anyInt(), eq(Process.myUserHandle().getIdentifier()));
5176 
5177         mBinderService.updateNotificationChannelFromPrivilegedListener(
5178                 null, mPkg, Process.myUserHandle(), updatedNotificationChannel);
5179 
5180         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5181                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5182 
5183         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5184                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5185                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5186     }
5187 
5188     @Test
5189     public void
updateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm()5190         updateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm()
5191             throws Exception {
5192         mService.setPreferencesHelper(mPreferencesHelper);
5193         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5194                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5195         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5196                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5197                 .thenReturn(mTestNotificationChannel);
5198 
5199         // Missing Uri permissions for the old channel sound
5200         final Uri oldSoundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
5201         doThrow(new SecurityException("no access")).when(mUgmInternal)
5202                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(oldSoundUri),
5203                 anyInt(), eq(Process.myUserHandle().getIdentifier()));
5204 
5205         // Has Uri permissions for the old channel sound
5206         final Uri newSoundUri = Uri.parse("content://media/test/sound/uri");
5207         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
5208                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
5209         updatedNotificationChannel.setSound(newSoundUri,
5210                 updatedNotificationChannel.getAudioAttributes());
5211 
5212         mBinderService.updateNotificationChannelFromPrivilegedListener(
5213                 null, mPkg, Process.myUserHandle(), updatedNotificationChannel);
5214 
5215         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5216                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5217 
5218         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5219                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5220                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5221     }
5222 
5223     @Test
testGetNotificationChannelFromPrivilegedListener_cdm_success()5224     public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
5225         mService.setPreferencesHelper(mPreferencesHelper);
5226         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5227                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5228 
5229         mBinderService.getNotificationChannelsFromPrivilegedListener(
5230                 null, mPkg, Process.myUserHandle());
5231 
5232         verify(mPreferencesHelper, times(1)).getNotificationChannels(
5233                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5234     }
5235 
5236     @Test
testGetNotificationChannelFromPrivilegedListener_cdm_noAccess()5237     public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
5238         mService.setPreferencesHelper(mPreferencesHelper);
5239         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5240                 .thenReturn(emptyList());
5241 
5242         try {
5243             mBinderService.getNotificationChannelsFromPrivilegedListener(
5244                     null, mPkg, Process.myUserHandle());
5245             fail("listeners that don't have a companion device shouldn't be able to call this");
5246         } catch (SecurityException e) {
5247             // pass
5248         }
5249 
5250         verify(mPreferencesHelper, never()).getNotificationChannels(
5251                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5252     }
5253 
5254     @Test
testGetNotificationChannelFromPrivilegedListener_assistant_success()5255     public void testGetNotificationChannelFromPrivilegedListener_assistant_success()
5256             throws Exception {
5257         mService.setPreferencesHelper(mPreferencesHelper);
5258         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5259                 .thenReturn(emptyList());
5260         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
5261 
5262         mBinderService.getNotificationChannelsFromPrivilegedListener(
5263                 null, mPkg, Process.myUserHandle());
5264 
5265         verify(mPreferencesHelper, times(1)).getNotificationChannels(
5266                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5267     }
5268 
5269     @Test
testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()5270     public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()
5271             throws Exception {
5272         mService.setPreferencesHelper(mPreferencesHelper);
5273         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5274                 .thenReturn(emptyList());
5275         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
5276 
5277         try {
5278             mBinderService.getNotificationChannelsFromPrivilegedListener(
5279                     null, mPkg, Process.myUserHandle());
5280             fail("listeners that don't have a companion device shouldn't be able to call this");
5281         } catch (SecurityException e) {
5282             // pass
5283         }
5284 
5285         verify(mPreferencesHelper, never()).getNotificationChannels(
5286                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5287     }
5288 
5289     @Test
testGetNotificationChannelFromPrivilegedListener_badUser()5290     public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception {
5291         mService.setPreferencesHelper(mPreferencesHelper);
5292         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5293                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5294         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5295         mListener.component = new ComponentName(mPkg, mPkg);
5296         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5297         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5298 
5299         try {
5300             mBinderService.getNotificationChannelsFromPrivilegedListener(
5301                     null, mPkg, Process.myUserHandle());
5302             fail("listener getting channels from a user they cannot see");
5303         } catch (SecurityException e) {
5304             // pass
5305         }
5306 
5307         verify(mPreferencesHelper, never()).getNotificationChannels(
5308                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5309     }
5310 
5311     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_success()5312     public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
5313         mService.setPreferencesHelper(mPreferencesHelper);
5314         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5315                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5316 
5317         mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
5318                 null, mPkg, Process.myUserHandle());
5319 
5320         verify(mPreferencesHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt());
5321     }
5322 
5323     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_noAccess()5324     public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
5325         mService.setPreferencesHelper(mPreferencesHelper);
5326         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5327                 .thenReturn(emptyList());
5328 
5329         try {
5330             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
5331                     null, mPkg, Process.myUserHandle());
5332             fail("listeners that don't have a companion device shouldn't be able to call this");
5333         } catch (SecurityException e) {
5334             // pass
5335         }
5336 
5337         verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
5338     }
5339 
5340     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_badUser()5341     public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
5342         mService.setPreferencesHelper(mPreferencesHelper);
5343         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5344                 .thenReturn(emptyList());
5345         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5346         mListener.component = new ComponentName(mPkg, mPkg);
5347         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5348         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5349         try {
5350             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
5351                     null, mPkg, Process.myUserHandle());
5352             fail("listeners that don't have a companion device shouldn't be able to call this");
5353         } catch (SecurityException e) {
5354             // pass
5355         }
5356 
5357         verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
5358     }
5359 
5360     @Test
testHasCompanionDevice_failure()5361     public void testHasCompanionDevice_failure() throws Exception {
5362         when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
5363                 new IllegalArgumentException());
5364         mService.hasCompanionDevice(mListener);
5365     }
5366 
5367     @Test
testHasCompanionDevice_noService()5368     public void testHasCompanionDevice_noService() {
5369         NotificationManagerService noManService =
5370                 new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
5371                 mNotificationInstanceIdSequence);
5372 
5373         assertFalse(noManService.hasCompanionDevice(mListener));
5374     }
5375 
5376     @Test
testCrossUserSnooze()5377     public void testCrossUserSnooze() {
5378         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
5379         mService.addNotification(r);
5380         NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
5381         mService.addNotification(r2);
5382 
5383         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5384         mListener.component = new ComponentName(mPkg, mPkg);
5385         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5386         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5387 
5388         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5389                 r.getKey(), 1000, null);
5390 
5391         verify(mWorkerHandler, never()).post(
5392                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5393     }
5394 
5395     @Test
testSameUserSnooze()5396     public void testSameUserSnooze() {
5397         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
5398         mService.addNotification(r);
5399         NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
5400         mService.addNotification(r2);
5401 
5402         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5403         mListener.component = new ComponentName(mPkg, mPkg);
5404         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5405         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5406 
5407         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5408                 r2.getKey(), 1000, null);
5409 
5410         verify(mWorkerHandler).post(
5411                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5412     }
5413 
5414     @Test
snoozeNotificationInt_rapidSnooze_new()5415     public void snoozeNotificationInt_rapidSnooze_new() {
5416         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
5417                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5418 
5419         // Create recent notification.
5420         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5421                 System.currentTimeMillis());
5422         mService.addNotification(nr1);
5423 
5424         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5425         mListener.component = new ComponentName(mPkg, mPkg);
5426         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5427         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5428 
5429         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5430                 nr1.getKey(), 1000, null);
5431 
5432         verify(mWorkerHandler).post(
5433                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5434         // Ensure cancel event is logged.
5435         verify(mAppOpsManager).noteOpNoThrow(
5436                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null,
5437                 null);
5438     }
5439 
5440     @Test
snoozeNotificationInt_rapidSnooze_old()5441     public void snoozeNotificationInt_rapidSnooze_old() {
5442         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
5443                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5444 
5445         // Create old notification.
5446         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5447                 System.currentTimeMillis() - 60000);
5448         mService.addNotification(nr1);
5449 
5450         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5451         mListener.component = new ComponentName(mPkg, mPkg);
5452         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5453         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5454 
5455         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5456                 nr1.getKey(), 1000, null);
5457 
5458         verify(mWorkerHandler).post(
5459                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5460         // Ensure cancel event is not logged.
5461         verify(mAppOpsManager, never()).noteOpNoThrow(
5462                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
5463                 any(), any());
5464     }
5465 
5466     @Test
snoozeNotificationInt_rapidSnooze_new_flagDisabled()5467     public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() {
5468         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
5469                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5470 
5471         // Create recent notification.
5472         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5473                 System.currentTimeMillis());
5474         mService.addNotification(nr1);
5475 
5476         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5477         mListener.component = new ComponentName(mPkg, mPkg);
5478         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5479         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5480 
5481         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5482                 nr1.getKey(), 1000, null);
5483 
5484         verify(mWorkerHandler).post(
5485                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5486         // Ensure cancel event is not logged.
5487         verify(mAppOpsManager, never()).noteOpNoThrow(
5488                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
5489                 any(), any());
5490     }
5491 
5492     @Test
snoozeNotificationInt_rapidSnooze_old_flagDisabled()5493     public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() {
5494         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
5495                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5496 
5497         // Create old notification.
5498         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5499                 System.currentTimeMillis() - 60000);
5500         mService.addNotification(nr1);
5501 
5502         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5503         mListener.component = new ComponentName(mPkg, mPkg);
5504         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5505         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5506 
5507         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5508                 nr1.getKey(), 1000, null);
5509 
5510         verify(mWorkerHandler).post(
5511                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5512         // Ensure cancel event is not logged.
5513         verify(mAppOpsManager, never()).noteOpNoThrow(
5514                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
5515                 any(), any());
5516     }
5517 
5518     @Test
testSnoozeRunnable_tooManySnoozed_singleNotification()5519     public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
5520         final NotificationRecord notification = generateNotificationRecord(
5521                 mTestNotificationChannel, 1, null, true);
5522         mService.addNotification(notification);
5523 
5524         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5525         when(mSnoozeHelper.canSnooze(1)).thenReturn(false);
5526 
5527         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5528                 mService.new SnoozeNotificationRunnable(
5529                         notification.getKey(), 100, null);
5530         snoozeNotificationRunnable.run();
5531 
5532         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
5533         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
5534     }
5535 
5536     @Test
testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification()5537     public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() {
5538         final NotificationRecord notification = generateNotificationRecord(
5539                 mTestNotificationChannel, 1, "group", true);
5540         final NotificationRecord notificationChild = generateNotificationRecord(
5541                 mTestNotificationChannel, 1, "group", false);
5542         mService.addNotification(notification);
5543         mService.addNotification(notificationChild);
5544 
5545         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5546         when(mSnoozeHelper.canSnooze(2)).thenReturn(false);
5547 
5548         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5549                 mService.new SnoozeNotificationRunnable(
5550                         notificationChild.getKey(), 100, null);
5551         snoozeNotificationRunnable.run();
5552 
5553         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
5554         assertThat(mService.getNotificationRecordCount()).isEqualTo(2);
5555     }
5556 
5557     @Test
testSnoozeRunnable_tooManySnoozed_summaryNotification()5558     public void testSnoozeRunnable_tooManySnoozed_summaryNotification() {
5559         final NotificationRecord notification = generateNotificationRecord(
5560                 mTestNotificationChannel, 1, "group", true);
5561         final NotificationRecord notificationChild = generateNotificationRecord(
5562                 mTestNotificationChannel, 12, "group", false);
5563         final NotificationRecord notificationChild2 = generateNotificationRecord(
5564                 mTestNotificationChannel, 13, "group", false);
5565         mService.addNotification(notification);
5566         mService.addNotification(notificationChild);
5567         mService.addNotification(notificationChild2);
5568 
5569         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5570         when(mSnoozeHelper.canSnooze(3)).thenReturn(false);
5571 
5572         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5573                 mService.new SnoozeNotificationRunnable(
5574                         notification.getKey(), 100, null);
5575         snoozeNotificationRunnable.run();
5576 
5577         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
5578         assertThat(mService.getNotificationRecordCount()).isEqualTo(3);
5579     }
5580 
5581     @Test
testSnoozeRunnable_reSnoozeASingleSnoozedNotification()5582     public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() {
5583         final NotificationRecord notification = generateNotificationRecord(
5584                 mTestNotificationChannel, 1, null, true);
5585         mService.addNotification(notification);
5586         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
5587         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5588 
5589         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5590                 mService.new SnoozeNotificationRunnable(
5591                 notification.getKey(), 100, null);
5592         snoozeNotificationRunnable.run();
5593         snoozeNotificationRunnable.run();
5594 
5595         // snooze twice
5596         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
5597     }
5598 
5599     @Test
testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey()5600     public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() {
5601         final NotificationRecord notification = generateNotificationRecord(
5602                 mTestNotificationChannel, 1, "group", true);
5603         mService.addNotification(notification);
5604         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
5605         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5606 
5607         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5608                 mService.new SnoozeNotificationRunnable(
5609                 notification.getKey(), 100, null);
5610         snoozeNotificationRunnable.run();
5611         snoozeNotificationRunnable.run();
5612 
5613         // snooze twice
5614         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
5615     }
5616 
5617     @Test
testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey()5618     public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception {
5619         final NotificationRecord notification = generateNotificationRecord(
5620                 mTestNotificationChannel, 1, "group", true);
5621         final NotificationRecord notification2 = generateNotificationRecord(
5622                 mTestNotificationChannel, 2, "group", true);
5623         mService.addNotification(notification);
5624         mService.addNotification(notification2);
5625         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
5626         when(mSnoozeHelper.getNotifications(
5627                 anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
5628         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5629 
5630         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5631                 mService.new SnoozeNotificationRunnable(
5632                         notification.getKey(), 100, null);
5633         snoozeNotificationRunnable.run();
5634         when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt()))
5635                 .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
5636         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
5637                 mService.new SnoozeNotificationRunnable(
5638                         notification2.getKey(), 100, null);
5639         snoozeNotificationRunnable2.run();
5640 
5641         // snooze twice
5642         verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
5643     }
5644 
5645     @Test
testSnoozeRunnable_snoozeNonGrouped()5646     public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
5647         final NotificationRecord nonGrouped = generateNotificationRecord(
5648                 mTestNotificationChannel, 1, null, false);
5649         final NotificationRecord grouped = generateNotificationRecord(
5650                 mTestNotificationChannel, 2, "group", false);
5651         mService.addNotification(grouped);
5652         mService.addNotification(nonGrouped);
5653         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5654 
5655         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5656                 mService.new SnoozeNotificationRunnable(
5657                         nonGrouped.getKey(), 100, null);
5658         snoozeNotificationRunnable.run();
5659 
5660         // only snooze the one notification
5661         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5662         assertTrue(nonGrouped.getStats().hasSnoozed());
5663 
5664         assertEquals(2, mNotificationRecordLogger.numCalls());
5665         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5666                 mNotificationRecordLogger.event(0));
5667         assertEquals(
5668                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5669                 mNotificationRecordLogger.event(1));
5670     }
5671 
5672     @Test
testSnoozeRunnable_snoozeSummary_withChildren()5673     public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception {
5674         final NotificationRecord parent = generateNotificationRecord(
5675                 mTestNotificationChannel, 1, "group", true);
5676         final NotificationRecord child = generateNotificationRecord(
5677                 mTestNotificationChannel, 2, "group", false);
5678         final NotificationRecord child2 = generateNotificationRecord(
5679                 mTestNotificationChannel, 3, "group", false);
5680         mService.addNotification(parent);
5681         mService.addNotification(child);
5682         mService.addNotification(child2);
5683         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5684 
5685         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5686                 mService.new SnoozeNotificationRunnable(
5687                         parent.getKey(), 100, null);
5688         snoozeNotificationRunnable.run();
5689 
5690         // snooze parent and children
5691         verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong());
5692     }
5693 
5694     @Test
testSnoozeRunnable_snoozeGroupChild_fellowChildren()5695     public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception {
5696         final NotificationRecord parent = generateNotificationRecord(
5697                 mTestNotificationChannel, 1, "group", true);
5698         final NotificationRecord child = generateNotificationRecord(
5699                 mTestNotificationChannel, 2, "group", false);
5700         final NotificationRecord child2 = generateNotificationRecord(
5701                 mTestNotificationChannel, 3, "group", false);
5702         mService.addNotification(parent);
5703         mService.addNotification(child);
5704         mService.addNotification(child2);
5705         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5706 
5707         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5708                 mService.new SnoozeNotificationRunnable(
5709                         child2.getKey(), 100, null);
5710         snoozeNotificationRunnable.run();
5711 
5712         // only snooze the one child
5713         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5714 
5715         assertEquals(2, mNotificationRecordLogger.numCalls());
5716         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5717                 mNotificationRecordLogger.event(0));
5718         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
5719                         .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1));
5720     }
5721 
5722     @Test
testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary()5723     public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception {
5724         final NotificationRecord parent = generateNotificationRecord(
5725                 mTestNotificationChannel, 1, "group", true);
5726         assertTrue(parent.getSbn().getNotification().isGroupSummary());
5727         final NotificationRecord child = generateNotificationRecord(
5728                 mTestNotificationChannel, 2, "group", false);
5729         mService.addNotification(parent);
5730         mService.addNotification(child);
5731         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5732 
5733         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5734                 mService.new SnoozeNotificationRunnable(
5735                         child.getKey(), 100, null);
5736         snoozeNotificationRunnable.run();
5737 
5738         // snooze child and summary
5739         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
5740 
5741         assertEquals(4, mNotificationRecordLogger.numCalls());
5742         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5743                 mNotificationRecordLogger.event(0));
5744         assertEquals(
5745                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5746                 mNotificationRecordLogger.event(1));
5747         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5748                 mNotificationRecordLogger.event(2));
5749         assertEquals(
5750                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5751                 mNotificationRecordLogger.event(3));
5752     }
5753 
5754     @Test
testSnoozeRunnable_snoozeGroupChild_noOthersInGroup()5755     public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception {
5756         final NotificationRecord child = generateNotificationRecord(
5757                 mTestNotificationChannel, 2, "group", false);
5758         mService.addNotification(child);
5759         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5760 
5761         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5762                 mService.new SnoozeNotificationRunnable(
5763                         child.getKey(), 100, null);
5764         snoozeNotificationRunnable.run();
5765 
5766         // snooze child only
5767         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5768 
5769         assertEquals(2, mNotificationRecordLogger.numCalls());
5770         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5771                 mNotificationRecordLogger.event(0));
5772         assertEquals(
5773                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5774                 mNotificationRecordLogger.event(1));
5775     }
5776 
5777     @Test
5778     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed()5779     public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception {
5780         final NotificationRecord parent = generateNotificationRecord(
5781                 mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true);
5782         final NotificationRecord child = generateNotificationRecord(
5783                 mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false);
5784         mService.addNotification(parent);
5785         mService.addNotification(child);
5786         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5787 
5788         // snooze child only
5789         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5790                 mService.new SnoozeNotificationRunnable(
5791                         child.getKey(), 100, null);
5792         snoozeNotificationRunnable.run();
5793 
5794         // only child should be snoozed
5795         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5796 
5797         // both group summary and child should be cancelled
5798         assertNull(mService.getNotificationRecord(parent.getKey()));
5799         assertNull(mService.getNotificationRecord(child.getKey()));
5800 
5801         assertEquals(4, mNotificationRecordLogger.numCalls());
5802         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5803                 mNotificationRecordLogger.event(0));
5804         assertEquals(
5805                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5806                 mNotificationRecordLogger.event(1));
5807     }
5808 
5809     @Test
testPostGroupChild_unsnoozeParent()5810     public void testPostGroupChild_unsnoozeParent() throws Exception {
5811         final NotificationRecord child = generateNotificationRecord(
5812                 mTestNotificationChannel, 2, "group", false);
5813 
5814         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing",
5815                 child.getSbn().getId(), child.getSbn().getNotification(),
5816                 child.getSbn().getUserId());
5817         waitForIdle();
5818 
5819         verify(mSnoozeHelper, times(1)).repostGroupSummary(
5820                 anyString(), anyInt(), eq(child.getGroupKey()));
5821     }
5822 
5823     @Test
testPostNonGroup_noUnsnoozing()5824     public void testPostNonGroup_noUnsnoozing() throws Exception {
5825         final NotificationRecord record = generateNotificationRecord(
5826                 mTestNotificationChannel, 2, null, false);
5827 
5828         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing",
5829                 record.getSbn().getId(), record.getSbn().getNotification(),
5830                 record.getSbn().getUserId());
5831         waitForIdle();
5832 
5833         verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
5834     }
5835 
5836     @Test
testPostGroupSummary_noUnsnoozing()5837     public void testPostGroupSummary_noUnsnoozing() throws Exception {
5838         final NotificationRecord parent = generateNotificationRecord(
5839                 mTestNotificationChannel, 2, "group", true);
5840 
5841         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostGroupSummary_noUnsnoozing",
5842                 parent.getSbn().getId(), parent.getSbn().getNotification(),
5843                 parent.getSbn().getUserId());
5844         waitForIdle();
5845 
5846         verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
5847     }
5848 
5849     @Test
testSystemNotificationListenerCanUnsnooze()5850     public void testSystemNotificationListenerCanUnsnooze() throws Exception {
5851         final NotificationRecord nr = generateNotificationRecord(
5852                 mTestNotificationChannel, 2, "group", false);
5853 
5854         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
5855                 "testSystemNotificationListenerCanUnsnooze",
5856                 nr.getSbn().getId(), nr.getSbn().getNotification(),
5857                 nr.getSbn().getUserId());
5858         waitForIdle();
5859         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5860                 mService.new SnoozeNotificationRunnable(
5861                         nr.getKey(), 100, null);
5862         snoozeNotificationRunnable.run();
5863 
5864         ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo(
5865                 null, new ComponentName(mPkg, "test_class"), mUid, true, null, 0, 234);
5866         listener.isSystem = true;
5867         when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener);
5868 
5869         mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey());
5870         waitForIdle();
5871         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
5872         assertEquals(1, notifs.length);
5873         assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey()));
5874     }
5875 
5876     @Test
testSetListenerAccessForUser()5877     public void testSetListenerAccessForUser() throws Exception {
5878         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5879         ComponentName c = ComponentName.unflattenFromString("package/Component");
5880         mBinderService.setNotificationListenerAccessGrantedForUser(
5881                 c, user.getIdentifier(), true, true);
5882 
5883 
5884         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
5885         verify(mListeners, times(1)).setPackageOrComponentEnabled(
5886                 c.flattenToString(), user.getIdentifier(), true, true, true);
5887         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5888                 c.flattenToString(), user.getIdentifier(), false, true, true);
5889         verify(mAssistants, never()).setPackageOrComponentEnabled(
5890                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5891     }
5892 
5893     @Test
testSetListenerAccessForUser_grantWithNameTooLong_throws()5894     public void testSetListenerAccessForUser_grantWithNameTooLong_throws() {
5895         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5896         ComponentName c = new ComponentName("com.example.package",
5897                 com.google.common.base.Strings.repeat("Blah", 150));
5898 
5899         assertThrows(IllegalArgumentException.class,
5900                 () -> mBinderService.setNotificationListenerAccessGrantedForUser(
5901                         c, user.getIdentifier(), /* enabled= */ true, true));
5902     }
5903 
5904     @Test
testSetListenerAccessForUser_revokeWithNameTooLong_okay()5905     public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception {
5906         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5907         ComponentName c = new ComponentName("com.example.package",
5908                 com.google.common.base.Strings.repeat("Blah", 150));
5909 
5910         mBinderService.setNotificationListenerAccessGrantedForUser(
5911                 c, user.getIdentifier(), /* enabled= */ false, true);
5912 
5913         verify(mListeners).setPackageOrComponentEnabled(
5914                 c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
5915     }
5916 
5917     @Test
testSetAssistantAccessForUser()5918     public void testSetAssistantAccessForUser() throws Exception {
5919         UserInfo ui = new UserInfo();
5920         ui.id = mContext.getUserId() + 10;
5921         UserHandle user = UserHandle.of(ui.id);
5922         List<UserInfo> uis = new ArrayList<>();
5923         uis.add(ui);
5924         ComponentName c = ComponentName.unflattenFromString("package/Component");
5925         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5926 
5927         mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true);
5928 
5929         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
5930         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5931                 c.flattenToString(), user.getIdentifier(), true, true, true);
5932         verify(mAssistants).setUserSet(ui.id, true);
5933         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5934                 c.flattenToString(), user.getIdentifier(), false, true);
5935         verify(mListeners, never()).setPackageOrComponentEnabled(
5936                 any(), anyInt(), anyBoolean(), anyBoolean());
5937     }
5938 
5939     @Test
testGetAssistantAllowedForUser()5940     public void testGetAssistantAllowedForUser() throws Exception {
5941         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5942         try {
5943             mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier());
5944         } catch (IllegalStateException e) {
5945             if (!e.getMessage().contains("At most one NotificationAssistant")) {
5946                 throw e;
5947             }
5948         }
5949         verify(mAssistants, times(1)).getAllowedComponents(user.getIdentifier());
5950     }
5951 
5952     @Test
testGetAssistantAllowed()5953     public void testGetAssistantAllowed() throws Exception {
5954         try {
5955             mBinderService.getAllowedNotificationAssistant();
5956         } catch (IllegalStateException e) {
5957             if (!e.getMessage().contains("At most one NotificationAssistant")) {
5958                 throw e;
5959             }
5960         }
5961         verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId());
5962     }
5963 
5964     @Test
testSetNASMigrationDoneAndResetDefault_enableNAS()5965     public void testSetNASMigrationDoneAndResetDefault_enableNAS() throws Exception {
5966         int userId = 10;
5967         setNASMigrationDone(false, userId);
5968         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
5969 
5970         mBinderService.setNASMigrationDoneAndResetDefault(userId, true);
5971 
5972         assertTrue(mService.isNASMigrationDone(userId));
5973         verify(mAssistants, times(1)).resetDefaultFromConfig();
5974     }
5975 
5976     @Test
testSetNASMigrationDoneAndResetDefault_disableNAS()5977     public void testSetNASMigrationDoneAndResetDefault_disableNAS() throws Exception {
5978         int userId = 10;
5979         setNASMigrationDone(false, userId);
5980         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
5981 
5982         mBinderService.setNASMigrationDoneAndResetDefault(userId, false);
5983 
5984         assertTrue(mService.isNASMigrationDone(userId));
5985         verify(mAssistants, times(1)).clearDefaults();
5986     }
5987 
5988     @Test
testSetNASMigrationDoneAndResetDefault_multiProfile()5989     public void testSetNASMigrationDoneAndResetDefault_multiProfile() throws Exception {
5990         int userId1 = 11;
5991         int userId2 = 12; //work profile
5992         setNASMigrationDone(false, userId1);
5993         setNASMigrationDone(false, userId2);
5994         setUsers(new int[]{userId1, userId2});
5995         when(mUm.isManagedProfile(userId2)).thenReturn(true);
5996         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2});
5997 
5998         mBinderService.setNASMigrationDoneAndResetDefault(userId1, true);
5999         assertTrue(mService.isNASMigrationDone(userId1));
6000         assertTrue(mService.isNASMigrationDone(userId2));
6001     }
6002 
6003     @Test
testSetNASMigrationDoneAndResetDefault_multiUser()6004     public void testSetNASMigrationDoneAndResetDefault_multiUser() throws Exception {
6005         int userId1 = 11;
6006         int userId2 = 12;
6007         setNASMigrationDone(false, userId1);
6008         setNASMigrationDone(false, userId2);
6009         setUsers(new int[]{userId1, userId2});
6010         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1});
6011         when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2});
6012 
6013         mBinderService.setNASMigrationDoneAndResetDefault(userId1, true);
6014         assertTrue(mService.isNASMigrationDone(userId1));
6015         assertFalse(mService.isNASMigrationDone(userId2));
6016     }
6017 
6018     @Test
testSetDndAccessForUser()6019     public void testSetDndAccessForUser() throws Exception {
6020         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
6021         ComponentName c = ComponentName.unflattenFromString("package/Component");
6022         mBinderService.setNotificationPolicyAccessGrantedForUser(
6023                 c.getPackageName(), user.getIdentifier(), true);
6024 
6025         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
6026         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6027                 c.getPackageName(), user.getIdentifier(), true, true);
6028         verify(mAssistants, never()).setPackageOrComponentEnabled(
6029                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6030         verify(mListeners, never()).setPackageOrComponentEnabled(
6031                 any(), anyInt(), anyBoolean(), anyBoolean());
6032     }
6033 
6034     @Test
testSetListenerAccess()6035     public void testSetListenerAccess() throws Exception {
6036         ComponentName c = ComponentName.unflattenFromString("package/Component");
6037         mBinderService.setNotificationListenerAccessGranted(c, true, true);
6038 
6039         verify(mListeners, times(1)).setPackageOrComponentEnabled(
6040                 c.flattenToString(), mContext.getUserId(), true, true, true);
6041         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6042                 c.flattenToString(), mContext.getUserId(), false, true, true);
6043         verify(mAssistants, never()).setPackageOrComponentEnabled(
6044                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6045     }
6046 
6047     @Test
testSetAssistantAccess()6048     public void testSetAssistantAccess() throws Exception {
6049         List<UserInfo> uis = new ArrayList<>();
6050         UserInfo ui = new UserInfo();
6051         ui.id = mContext.getUserId();
6052         uis.add(ui);
6053         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6054         ComponentName c = ComponentName.unflattenFromString("package/Component");
6055 
6056         mBinderService.setNotificationAssistantAccessGranted(c, true);
6057 
6058         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6059                 c.flattenToString(), ui.id, true, true, true);
6060         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6061                 c.flattenToString(), ui.id, false, true);
6062         verify(mListeners, never()).setPackageOrComponentEnabled(
6063                 any(), anyInt(), anyBoolean(), anyBoolean());
6064     }
6065 
6066     @Test
testSetAssistantAccess_multiProfile()6067     public void testSetAssistantAccess_multiProfile() throws Exception {
6068         List<UserInfo> uis = new ArrayList<>();
6069         UserInfo ui = new UserInfo();
6070         ui.id = mContext.getUserId();
6071         uis.add(ui);
6072         UserInfo ui10 = new UserInfo();
6073         ui10.id = mContext.getUserId() + 10;
6074         uis.add(ui10);
6075         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6076         ComponentName c = ComponentName.unflattenFromString("package/Component");
6077 
6078         mBinderService.setNotificationAssistantAccessGranted(c, true);
6079 
6080         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6081                 c.flattenToString(), ui.id, true, true, true);
6082         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6083                 c.flattenToString(), ui10.id, true, true, true);
6084 
6085         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6086                 c.flattenToString(), ui.id, false, true);
6087         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6088                 c.flattenToString(), ui10.id, false, true);
6089         verify(mListeners, never()).setPackageOrComponentEnabled(
6090                 any(), anyInt(), anyBoolean(), anyBoolean());
6091     }
6092 
6093     @Test
testSetAssistantAccess_nullWithAllowedAssistant()6094     public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception {
6095         ArrayList<ComponentName> componentList = new ArrayList<>();
6096         ComponentName c = ComponentName.unflattenFromString("package/Component");
6097         componentList.add(c);
6098         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
6099         List<UserInfo> uis = new ArrayList<>();
6100         UserInfo ui = new UserInfo();
6101         ui.id = mContext.getUserId();
6102         uis.add(ui);
6103         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6104 
6105         mBinderService.setNotificationAssistantAccessGranted(null, true);
6106 
6107         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6108                 c.flattenToString(), ui.id, true, false, true);
6109         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6110                 c.flattenToString(), ui.id, false,  false);
6111         verify(mListeners, never()).setPackageOrComponentEnabled(
6112                 any(), anyInt(), anyBoolean(), anyBoolean());
6113     }
6114 
6115     @Test
testSetAssistantAccessForUser_nullWithAllowedAssistant()6116     public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception {
6117         List<UserInfo> uis = new ArrayList<>();
6118         UserInfo ui = new UserInfo();
6119         ui.id = mContext.getUserId() + 10;
6120         uis.add(ui);
6121         UserHandle user = ui.getUserHandle();
6122         ArrayList<ComponentName> componentList = new ArrayList<>();
6123         ComponentName c = ComponentName.unflattenFromString("package/Component");
6124         componentList.add(c);
6125         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
6126         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6127 
6128         mBinderService.setNotificationAssistantAccessGrantedForUser(
6129                 null, user.getIdentifier(), true);
6130 
6131         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6132                 c.flattenToString(), user.getIdentifier(), true, false, true);
6133         verify(mAssistants).setUserSet(ui.id, true);
6134         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6135                 c.flattenToString(), user.getIdentifier(), false,  false);
6136         verify(mListeners, never()).setPackageOrComponentEnabled(
6137                 any(), anyInt(), anyBoolean(), anyBoolean());
6138     }
6139 
6140     @Test
testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()6141     public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()
6142             throws Exception {
6143         List<UserInfo> uis = new ArrayList<>();
6144         UserInfo ui = new UserInfo();
6145         ui.id = mContext.getUserId();
6146         uis.add(ui);
6147         UserInfo ui10 = new UserInfo();
6148         ui10.id = mContext.getUserId() + 10;
6149         uis.add(ui10);
6150         UserHandle user = ui.getUserHandle();
6151         ArrayList<ComponentName> componentList = new ArrayList<>();
6152         ComponentName c = ComponentName.unflattenFromString("package/Component");
6153         componentList.add(c);
6154         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
6155         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6156 
6157         mBinderService.setNotificationAssistantAccessGrantedForUser(
6158                     null, user.getIdentifier(), true);
6159 
6160         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6161                 c.flattenToString(), user.getIdentifier(), true, false, true);
6162         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6163                 c.flattenToString(), ui10.id, true, false, true);
6164         verify(mAssistants).setUserSet(ui.id, true);
6165         verify(mAssistants).setUserSet(ui10.id, true);
6166         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6167                 c.flattenToString(), user.getIdentifier(), false,  false);
6168         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6169                 c.flattenToString(), ui10.id, false,  false);
6170         verify(mListeners, never()).setPackageOrComponentEnabled(
6171                 any(), anyInt(), anyBoolean(), anyBoolean());
6172     }
6173 
6174     @Test
testSetDndAccess()6175     public void testSetDndAccess() throws Exception {
6176         ComponentName c = ComponentName.unflattenFromString("package/Component");
6177 
6178         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
6179 
6180         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6181                 c.getPackageName(), mContext.getUserId(), true, true);
6182         verify(mAssistants, never()).setPackageOrComponentEnabled(
6183                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6184         verify(mListeners, never()).setPackageOrComponentEnabled(
6185                 any(), anyInt(), anyBoolean(), anyBoolean());
6186     }
6187 
6188     @Test
testSetListenerAccess_onLowRam()6189     public void testSetListenerAccess_onLowRam() throws Exception {
6190         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6191         ComponentName c = ComponentName.unflattenFromString("package/Component");
6192         mBinderService.setNotificationListenerAccessGranted(c, true, true);
6193 
6194         verify(mListeners).setPackageOrComponentEnabled(
6195                 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6196         verify(mConditionProviders).setPackageOrComponentEnabled(
6197                 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6198         verify(mAssistants).migrateToXml();
6199         verify(mAssistants).resetDefaultAssistantsIfNecessary();
6200     }
6201 
6202     @Test
testSetAssistantAccess_onLowRam()6203     public void testSetAssistantAccess_onLowRam() throws Exception {
6204         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6205         ComponentName c = ComponentName.unflattenFromString("package/Component");
6206         List<UserInfo> uis = new ArrayList<>();
6207         UserInfo ui = new UserInfo();
6208         ui.id = mContext.getUserId();
6209         uis.add(ui);
6210         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6211 
6212         mBinderService.setNotificationAssistantAccessGranted(c, true);
6213 
6214         verify(mListeners).migrateToXml();
6215         verify(mConditionProviders).setPackageOrComponentEnabled(
6216                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6217         verify(mAssistants).migrateToXml();
6218         verify(mAssistants).resetDefaultAssistantsIfNecessary();
6219     }
6220 
6221     @Test
testSetDndAccess_onLowRam()6222     public void testSetDndAccess_onLowRam() throws Exception {
6223         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6224         ComponentName c = ComponentName.unflattenFromString("package/Component");
6225         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
6226 
6227         verify(mListeners).migrateToXml();
6228         verify(mConditionProviders).setPackageOrComponentEnabled(
6229                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6230         verify(mAssistants).migrateToXml();
6231         verify(mAssistants).resetDefaultAssistantsIfNecessary();
6232     }
6233 
6234     @Test
testSetListenerAccess_doesNothingOnLowRam_exceptWatch()6235     public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
6236         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
6237         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6238         ComponentName c = ComponentName.unflattenFromString("package/Component");
6239 
6240         mBinderService.setNotificationListenerAccessGranted(c, true, true);
6241 
6242         verify(mListeners, times(1)).setPackageOrComponentEnabled(
6243                 c.flattenToString(), mContext.getUserId(), true, true, true);
6244         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6245                 c.flattenToString(), mContext.getUserId(), false, true, true);
6246         verify(mAssistants, never()).setPackageOrComponentEnabled(
6247                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6248     }
6249 
6250     @Test
testSetAssistantAccess_doesNothingOnLowRam_exceptWatch()6251     public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
6252         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
6253         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6254         ComponentName c = ComponentName.unflattenFromString("package/Component");
6255         List<UserInfo> uis = new ArrayList<>();
6256         UserInfo ui = new UserInfo();
6257         ui.id = mContext.getUserId();
6258         uis.add(ui);
6259         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6260 
6261         mBinderService.setNotificationAssistantAccessGranted(c, true);
6262 
6263         verify(mListeners, never()).setPackageOrComponentEnabled(
6264                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6265         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6266                 c.flattenToString(), ui.id, false, true);
6267         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6268                 c.flattenToString(), ui.id, true, true, true);
6269     }
6270 
6271     @Test
testSetDndAccess_doesNothingOnLowRam_exceptWatch()6272     public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
6273         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
6274         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6275         ComponentName c = ComponentName.unflattenFromString("package/Component");
6276 
6277         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
6278 
6279         verify(mListeners, never()).setPackageOrComponentEnabled(
6280                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6281         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6282                 c.getPackageName(), mContext.getUserId(), true, true);
6283         verify(mAssistants, never()).setPackageOrComponentEnabled(
6284                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6285     }
6286 
6287     @Test
testOnlyAutogroupIfNeeded_newNotification_ghUpdate()6288     public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() {
6289         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
6290         mService.addEnqueuedNotification(r);
6291         NotificationManagerService.PostNotificationRunnable runnable =
6292                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
6293                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6294         runnable.run();
6295         waitForIdle();
6296 
6297         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6298     }
6299 
6300     @Test
testOnlyAutogroupIfNeeded_groupChanged_ghUpdate()6301     public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() {
6302         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6303                 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false);
6304         mService.addNotification(r);
6305 
6306         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
6307                 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false);
6308         mService.addEnqueuedNotification(update);
6309         NotificationManagerService.PostNotificationRunnable runnable =
6310                 mService.new PostNotificationRunnable(update.getKey(),
6311                         update.getSbn().getPackageName(), update.getUid(),
6312                         mPostNotificationTrackerFactory.newTracker(null));
6313         runnable.run();
6314         waitForIdle();
6315 
6316         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6317     }
6318 
6319     @Test
testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate()6320     public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() {
6321         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6322                 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false);
6323         mService.addNotification(r);
6324 
6325         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
6326                 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false);
6327         update.getNotification().flags = FLAG_AUTO_CANCEL;
6328         mService.addEnqueuedNotification(update);
6329         NotificationManagerService.PostNotificationRunnable runnable =
6330                 mService.new PostNotificationRunnable(update.getKey(),
6331                         update.getSbn().getPackageName(), update.getUid(),
6332                         mPostNotificationTrackerFactory.newTracker(null));
6333         runnable.run();
6334         waitForIdle();
6335 
6336         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6337     }
6338 
6339     @Test
testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate()6340     public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() {
6341         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6342                 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);
6343         mService.addNotification(r);
6344         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
6345                 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);
6346         update.getNotification().color = Color.BLACK;
6347         mService.addEnqueuedNotification(update);
6348 
6349         NotificationManagerService.PostNotificationRunnable runnable =
6350                 mService.new PostNotificationRunnable(update.getKey(),
6351                         update.getSbn().getPackageName(),
6352                         update.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6353         runnable.run();
6354         waitForIdle();
6355 
6356         verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
6357     }
6358 
6359     @Test
testDontAutogroupIfCritical()6360     public void testDontAutogroupIfCritical() throws Exception {
6361         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
6362         r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW);
6363         mService.addEnqueuedNotification(r);
6364         NotificationManagerService.PostNotificationRunnable runnable =
6365                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
6366                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6367         runnable.run();
6368 
6369         r = generateNotificationRecord(mTestNotificationChannel, 1, null, false);
6370         r.setCriticality(CriticalNotificationExtractor.CRITICAL);
6371         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
6372                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6373         mService.addEnqueuedNotification(r);
6374 
6375         runnable.run();
6376         waitForIdle();
6377 
6378         verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
6379     }
6380 
6381     @Test
testNoNotificationDuringSetupPermission()6382     public void testNoNotificationDuringSetupPermission() throws Exception {
6383         mContext.getTestablePermissions().setPermission(
6384                 android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED);
6385         Bundle extras = new Bundle();
6386         extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true);
6387         Notification.Builder nb = new Notification.Builder(mContext,
6388                 mTestNotificationChannel.getId())
6389                 .setContentTitle("foo")
6390                 .addExtras(extras)
6391                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
6392         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
6393                 "testNoNotificationDuringSetupPermission", mUid, 0,
6394                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
6395         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6396 
6397         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
6398                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
6399         waitForIdle();
6400 
6401         NotificationRecord posted = mService.findNotificationLocked(
6402                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
6403 
6404         assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP));
6405     }
6406 
6407     @Test
testNoFakeColorizedPermission()6408     public void testNoFakeColorizedPermission() throws Exception {
6409         mContext.getTestablePermissions().setPermission(
6410                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED);
6411         Notification.Builder nb = new Notification.Builder(mContext,
6412                 mTestNotificationChannel.getId())
6413                 .setContentTitle("foo")
6414                 .setColorized(true).setColor(Color.WHITE)
6415                 .setFlag(FLAG_CAN_COLORIZE, true)
6416                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
6417         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
6418                 "testNoFakeColorizedPermission", mUid, 0,
6419                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
6420         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6421 
6422         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
6423                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
6424         waitForIdle();
6425 
6426         NotificationRecord posted = mService.findNotificationLocked(
6427                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
6428 
6429         assertFalse(posted.getNotification().isColorized());
6430     }
6431 
6432     @Test
6433     @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
testMediaStyle_enforceNoClearFlagEnabled()6434     public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
6435         Notification.MediaStyle style = new Notification.MediaStyle();
6436         Notification.Builder nb = new Notification.Builder(mContext,
6437                 mTestNotificationChannel.getId())
6438                 .setStyle(style);
6439 
6440         NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
6441 
6442         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
6443     }
6444 
6445     @Test
6446     @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
testCustomMediaStyle_enforceNoClearFlagEnabled()6447     public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
6448         Notification.DecoratedMediaCustomViewStyle style =
6449                 new Notification.DecoratedMediaCustomViewStyle();
6450         Notification.Builder nb = new Notification.Builder(mContext,
6451                 mTestNotificationChannel.getId())
6452                 .setStyle(style);
6453 
6454         NotificationRecord posted = createAndPostNotification(nb,
6455                 "testCustomMediaStyleSetNoClearFlag");
6456 
6457         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
6458     }
6459 
6460     @Test
6461     @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
testMediaStyle_enforceNoClearFlagDisabled()6462     public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
6463         Notification.MediaStyle style = new Notification.MediaStyle();
6464         Notification.Builder nb = new Notification.Builder(mContext,
6465                 mTestNotificationChannel.getId())
6466                 .setStyle(style);
6467 
6468         NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
6469 
6470         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
6471     }
6472 
6473     @Test
6474     @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
testCustomMediaStyle_enforceNoClearFlagDisabled()6475     public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
6476         Notification.DecoratedMediaCustomViewStyle style =
6477                 new Notification.DecoratedMediaCustomViewStyle();
6478         Notification.Builder nb = new Notification.Builder(mContext,
6479                 mTestNotificationChannel.getId())
6480                 .setStyle(style);
6481 
6482         NotificationRecord posted = createAndPostNotification(nb,
6483                 "testCustomMediaStyleSetNoClearFlag");
6484 
6485         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
6486     }
6487 
6488     @Test
testMediaStyleRemote_hasPermission()6489     public void testMediaStyleRemote_hasPermission() throws RemoteException {
6490         String deviceName = "device";
6491         mContext.getTestablePermissions().setPermission(
6492                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED);
6493         Notification.MediaStyle style = new Notification.MediaStyle();
6494         style.setRemotePlaybackInfo(deviceName, 0, null);
6495         Notification.Builder nb = new Notification.Builder(mContext,
6496                 mTestNotificationChannel.getId())
6497                 .setStyle(style);
6498 
6499         NotificationRecord posted = createAndPostNotification(nb,
6500                 "testMediaStyleRemoteHasPermission");
6501         Bundle extras = posted.getNotification().extras;
6502 
6503         assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6504         assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6505     }
6506 
6507     @Test
testMediaStyleRemote_noPermission()6508     public void testMediaStyleRemote_noPermission() throws RemoteException {
6509         String deviceName = "device";
6510         mContext.getTestablePermissions().setPermission(
6511                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED);
6512         Notification.MediaStyle style = new Notification.MediaStyle();
6513         style.setRemotePlaybackInfo(deviceName, 0, null);
6514         Notification.Builder nb = new Notification.Builder(mContext,
6515                 mTestNotificationChannel.getId())
6516                 .setStyle(style);
6517 
6518         NotificationRecord posted = createAndPostNotification(nb,
6519                 "testMediaStyleRemoteNoPermission");
6520 
6521         assertFalse(posted.getNotification().extras
6522                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6523         assertFalse(posted.getNotification().extras
6524                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
6525         assertFalse(posted.getNotification().extras
6526                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
6527     }
6528 
6529     @Test
testCustomMediaStyleRemote_noPermission()6530     public void testCustomMediaStyleRemote_noPermission() throws RemoteException {
6531         String deviceName = "device";
6532         when(mPackageManager.checkPermission(
6533                 eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
6534                 .thenReturn(PERMISSION_DENIED);
6535         Notification.DecoratedMediaCustomViewStyle style =
6536                 new Notification.DecoratedMediaCustomViewStyle();
6537         style.setRemotePlaybackInfo(deviceName, 0, null);
6538         Notification.Builder nb = new Notification.Builder(mContext,
6539                 mTestNotificationChannel.getId())
6540                 .setStyle(style);
6541 
6542         NotificationRecord posted = createAndPostNotification(nb,
6543                 "testCustomMediaStyleRemoteNoPermission");
6544 
6545         assertFalse(posted.getNotification().extras
6546                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6547         assertFalse(posted.getNotification().extras
6548                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
6549         assertFalse(posted.getNotification().extras
6550                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
6551     }
6552 
6553     @Test
testSubstituteAppName_hasPermission()6554     public void testSubstituteAppName_hasPermission() throws RemoteException {
6555         String subName = "Substitute Name";
6556         mContext.getTestablePermissions().setPermission(
6557                 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED);
6558         Bundle extras = new Bundle();
6559         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
6560         Notification.Builder nb = new Notification.Builder(mContext,
6561                 mTestNotificationChannel.getId())
6562                 .addExtras(extras);
6563 
6564         NotificationRecord posted = createAndPostNotification(nb,
6565                 "testSubstituteAppNameHasPermission");
6566 
6567         assertTrue(posted.getNotification().extras
6568                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
6569         assertEquals(posted.getNotification().extras
6570                 .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName);
6571     }
6572 
6573     @Test
testSubstituteAppName_noPermission()6574     public void testSubstituteAppName_noPermission() throws RemoteException {
6575         mContext.getTestablePermissions().setPermission(
6576                 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED);
6577         Bundle extras = new Bundle();
6578         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
6579         Notification.Builder nb = new Notification.Builder(mContext,
6580                 mTestNotificationChannel.getId())
6581                 .addExtras(extras);
6582 
6583         NotificationRecord posted = createAndPostNotification(nb,
6584                 "testSubstituteAppNameNoPermission");
6585 
6586         assertFalse(posted.getNotification().extras
6587                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
6588     }
6589 
6590     @Test
testGetNotificationCountLocked()6591     public void testGetNotificationCountLocked() {
6592         String sampleTagToExclude = null;
6593         int sampleIdToExclude = 0;
6594         for (int i = 0; i < 20; i++) {
6595             NotificationRecord r =
6596                     generateNotificationRecord(mTestNotificationChannel, i, null, false);
6597             mService.addEnqueuedNotification(r);
6598 
6599         }
6600         for (int i = 0; i < 20; i++) {
6601             NotificationRecord r =
6602                     generateNotificationRecord(mTestNotificationChannel, i, null, false);
6603             mService.addNotification(r);
6604             sampleTagToExclude = r.getSbn().getTag();
6605             sampleIdToExclude = i;
6606         }
6607 
6608         // another package
6609         Notification n =
6610                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
6611                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6612                 .build();
6613 
6614         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0,
6615                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
6616         NotificationRecord otherPackage =
6617                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6618         mService.addEnqueuedNotification(otherPackage);
6619         mService.addNotification(otherPackage);
6620 
6621         // Same notifications are enqueued as posted, everything counts b/c id and tag don't match
6622         // anything that's currently enqueued or posted
6623         int userId = mUserId;
6624         assertEquals(40,
6625                 mService.getNotificationCount(mPkg, userId, 0, null));
6626         assertEquals(40,
6627                 mService.getNotificationCount(mPkg, userId, 0, "tag2"));
6628 
6629         // return all for package "a" - "banana" tag isn't used
6630         assertEquals(2,
6631                 mService.getNotificationCount("a", userId, 0, "banana"));
6632 
6633         // exclude a known notification - it's excluded from only the posted list, not enqueued
6634         assertEquals(39, mService.getNotificationCount(
6635                 mPkg, userId, sampleIdToExclude, sampleTagToExclude));
6636     }
6637 
6638     @Test
testAddAutogroup_requestsSort()6639     public void testAddAutogroup_requestsSort() throws Exception {
6640         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6641         mService.addNotification(r);
6642         mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true);
6643 
6644         verify(mRankingHandler, times(1)).requestSort();
6645     }
6646 
6647     @Test
testRemoveAutogroup_requestsSort()6648     public void testRemoveAutogroup_requestsSort() throws Exception {
6649         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6650         r.setOverrideGroupKey("TEST");
6651         mService.addNotification(r);
6652         mService.removeAutogroupKeyLocked(r.getKey());
6653 
6654         verify(mRankingHandler, times(1)).requestSort();
6655     }
6656 
6657     @Test
testReaddAutogroup_noSort()6658     public void testReaddAutogroup_noSort() throws Exception {
6659         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6660         r.setOverrideGroupKey("TEST");
6661         mService.addNotification(r);
6662         mService.addAutogroupKeyLocked(r.getKey(), "grpName", true);
6663 
6664         verify(mRankingHandler, never()).requestSort();
6665     }
6666 
6667     @Test
6668     @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST)
testAutogroupSuppressSort_noSort()6669     public void testAutogroupSuppressSort_noSort() throws Exception {
6670         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6671         mService.addNotification(r);
6672         mService.addAutogroupKeyLocked(r.getKey(), "grpName", false);
6673 
6674         verify(mRankingHandler, never()).requestSort();
6675     }
6676 
6677     @Test
6678     @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST)
testAutogroupOnPost_skipManualSort()6679     public void testAutogroupOnPost_skipManualSort() throws Exception {
6680         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6681         mService.addNotification(r);
6682         verify(mRankingHandler, never()).requestSort();
6683     }
6684 
6685     @Test
testHandleRankingSort_sendsUpdateOnSignalExtractorChange()6686     public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception {
6687         mService.setPreferencesHelper(mPreferencesHelper);
6688         NotificationManagerService.WorkerHandler handler = mock(
6689                 NotificationManagerService.WorkerHandler.class);
6690         mService.setHandler(handler);
6691 
6692         Map<String, Answer> answers = getSignalExtractorSideEffects();
6693         for (String message : answers.keySet()) {
6694             mService.clearNotifications();
6695             final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6696             mService.addNotification(r);
6697 
6698             doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r);
6699 
6700             mService.handleRankingSort();
6701         }
6702         verify(handler, times(answers.size())).scheduleSendRankingUpdate();
6703     }
6704 
6705     @Test
testHandleRankingSort_noUpdateWhenNoSignalChange()6706     public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception {
6707         mService.setRankingHelper(mRankingHelper);
6708         NotificationManagerService.WorkerHandler handler = mock(
6709                 NotificationManagerService.WorkerHandler.class);
6710         mService.setHandler(handler);
6711 
6712         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6713         mService.addNotification(r);
6714 
6715         mService.handleRankingSort();
6716         verify(handler, never()).scheduleSendRankingUpdate();
6717     }
6718 
6719     @Test
testReadPolicyXml_readApprovedServicesFromXml()6720     public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception {
6721         final String upgradeXml = "<notification-policy version=\"1\">"
6722                 + "<ranking></ranking>"
6723                 + "<enabled_listeners>"
6724                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
6725                 + "</enabled_listeners>"
6726                 + "<enabled_assistants>"
6727                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
6728                 + "</enabled_assistants>"
6729                 + "<dnd_apps>"
6730                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
6731                 + "</dnd_apps>"
6732                 + "</notification-policy>";
6733         mService.readPolicyXml(
6734                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
6735                 false,
6736                 UserHandle.USER_ALL, null);
6737         verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
6738         verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
6739         verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
6740 
6741         // numbers are inflated for setup
6742         verify(mListeners, times(1)).migrateToXml();
6743         verify(mConditionProviders, times(1)).migrateToXml();
6744         verify(mAssistants, times(1)).migrateToXml();
6745         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
6746     }
6747 
6748     @Test
testReadPolicyXml_readSnoozedNotificationsFromXml()6749     public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception {
6750         final String upgradeXml = "<notification-policy version=\"1\">"
6751                 + "<snoozed-notifications>></snoozed-notifications>"
6752                 + "</notification-policy>";
6753         mService.readPolicyXml(
6754                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
6755                 false,
6756                 UserHandle.USER_ALL, null);
6757         verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong());
6758     }
6759 
6760     @Test
testReadPolicyXml_readApprovedServicesFromSettings()6761     public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
6762         final String preupgradeXml = "<notification-policy version=\"1\">"
6763                 + "<ranking></ranking>"
6764                 + "</notification-policy>";
6765         mService.readPolicyXml(
6766                 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
6767                 false,
6768                 UserHandle.USER_ALL, null);
6769         verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt());
6770         verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt());
6771         verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt());
6772 
6773         // numbers are inflated for setup
6774         verify(mListeners, times(2)).migrateToXml();
6775         verify(mConditionProviders, times(2)).migrateToXml();
6776         verify(mAssistants, times(2)).migrateToXml();
6777         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
6778     }
6779 
6780     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser()6781     public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception {
6782         final String policyXml = "<notification-policy version=\"1\">"
6783                 + "<ranking></ranking>"
6784                 + "<enabled_listeners>"
6785                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6786                 + "</enabled_listeners>"
6787                 + "<enabled_assistants>"
6788                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6789                 + "</enabled_assistants>"
6790                 + "<dnd_apps>"
6791                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6792                 + "</dnd_apps>"
6793                 + "</notification-policy>";
6794         UserInfo ui = new UserInfo(10, "Clone", UserInfo.FLAG_PROFILE);
6795         ui.userType = USER_TYPE_PROFILE_CLONE;
6796         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6797         mService.readPolicyXml(
6798                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6799                 true,
6800                 10, null);
6801         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
6802         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
6803         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
6804     }
6805 
6806     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser()6807     public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception {
6808         final String policyXml = "<notification-policy version=\"1\">"
6809                 + "<ranking></ranking>"
6810                 + "<enabled_listeners>"
6811                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6812                 + "</enabled_listeners>"
6813                 + "<enabled_assistants>"
6814                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6815                 + "</enabled_assistants>"
6816                 + "<dnd_apps>"
6817                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6818                 + "</dnd_apps>"
6819                 + "</notification-policy>";
6820         UserInfo ui = new UserInfo(10, "Work", UserInfo.FLAG_PROFILE);
6821         ui.userType = USER_TYPE_PROFILE_MANAGED;
6822         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6823         mService.readPolicyXml(
6824                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6825                 true,
6826                 10, null);
6827         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
6828         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
6829         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
6830     }
6831 
6832     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser()6833     public void testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser() throws Exception {
6834         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
6835                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
6836         final String policyXml = "<notification-policy version=\"1\">"
6837                 + "<ranking></ranking>"
6838                 + "<enabled_listeners>"
6839                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6840                 + "</enabled_listeners>"
6841                 + "<enabled_assistants>"
6842                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6843                 + "</enabled_assistants>"
6844                 + "<dnd_apps>"
6845                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6846                 + "</dnd_apps>"
6847                 + "</notification-policy>";
6848         UserInfo ui = new UserInfo(10, "Private", UserInfo.FLAG_PROFILE);
6849         ui.userType = USER_TYPE_PROFILE_PRIVATE;
6850         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6851         mService.readPolicyXml(
6852                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6853                 true,
6854                 10, null);
6855         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
6856         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
6857         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
6858     }
6859 
6860     @Test
testReadPolicyXml_restoresManagedServicesForNonManagedUser()6861     public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception {
6862         final String policyXml = "<notification-policy version=\"1\">"
6863                 + "<ranking></ranking>"
6864                 + "<enabled_listeners>"
6865                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6866                 + "</enabled_listeners>"
6867                 + "<enabled_assistants>"
6868                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6869                 + "</enabled_assistants>"
6870                 + "<dnd_apps>"
6871                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6872                 + "</dnd_apps>"
6873                 + "</notification-policy>";
6874         UserInfo ui = new UserInfo();
6875         ui.id = 10;
6876         ui.userType = USER_TYPE_FULL_SECONDARY;
6877         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6878         mService.readPolicyXml(
6879                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6880                 true,
6881                 10, null);
6882         verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10));
6883         verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10));
6884         verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10));
6885     }
6886 
6887     @Test
6888     @EnableFlags(android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING)
testReadPolicyXml_backupRestoreLogging()6889     public void testReadPolicyXml_backupRestoreLogging() throws Exception {
6890         BackupRestoreEventLogger logger = mock(BackupRestoreEventLogger.class);
6891 
6892         if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
6893             // By default, the ZenModeHelper only has a configuration for the system user.
6894             // If the current user is not the system user, the user must be updated.
6895             mService.mZenModeHelper.onUserSwitched(ActivityManager.getCurrentUser());
6896         }
6897         UserInfo ui = new UserInfo(ActivityManager.getCurrentUser(), "Clone", UserInfo.FLAG_FULL);
6898         ui.userType = USER_TYPE_FULL_SYSTEM;
6899         when(mUmInternal.getUserInfo(ActivityManager.getCurrentUser())).thenReturn(ui);
6900         when(mPermissionHelper.getNotificationPermissionValues(ActivityManager.getCurrentUser()))
6901                 .thenReturn(new ArrayMap<>());
6902         TypedXmlSerializer serializer = Xml.newFastSerializer();
6903         ByteArrayOutputStream baos = new ByteArrayOutputStream();
6904         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
6905         serializer.startDocument(null, true);
6906         mService.writePolicyXml(baos, true, ActivityManager.getCurrentUser(), logger);
6907         serializer.flush();
6908 
6909         mService.readPolicyXml(
6910                 new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
6911                 true, ActivityManager.getCurrentUser(), logger);
6912 
6913         verify(logger).logItemsBackedUp(DATA_TYPE_ZEN_CONFIG, 1);
6914         verify(logger, never())
6915                 .logItemsBackupFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString());
6916 
6917         verify(logger).logItemsRestored(DATA_TYPE_ZEN_CONFIG, 1);
6918         verify(logger, never())
6919                 .logItemsRestoreFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString());
6920     }
6921 
6922     @Test
testLocaleChangedCallsUpdateDefaultZenModeRules()6923     public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception {
6924         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
6925         mService.mZenModeHelper = mZenModeHelper;
6926         mService.mLocaleChangeReceiver.onReceive(mContext,
6927                 new Intent(Intent.ACTION_LOCALE_CHANGED));
6928 
6929         verify(mZenModeHelper).updateZenRulesOnLocaleChange();
6930     }
6931 
simulateNotificationTimeout(String notificationKey)6932     private void simulateNotificationTimeout(String notificationKey) {
6933         if (Flags.allNotifsNeedTtl()) {
6934             mService.mNotificationManagerPrivate.timeoutNotification(notificationKey);
6935         } else {
6936             final Bundle extras = new Bundle();
6937             extras.putString(EXTRA_KEY, notificationKey);
6938             final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT);
6939             intent.putExtras(extras);
6940             mNotificationTimeoutReceiver.onReceive(getContext(), intent);
6941         }
6942     }
6943 
6944     @Test
testTimeout_CancelsNotification()6945     public void testTimeout_CancelsNotification() throws Exception {
6946         final NotificationRecord notif = generateNotificationRecord(
6947                 mTestNotificationChannel, 1, null, false);
6948         mService.addNotification(notif);
6949 
6950         simulateNotificationTimeout(notif.getKey());
6951         waitForIdle();
6952 
6953         // Check that the notification was cancelled.
6954         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
6955         assertThat(notifsAfter.length).isEqualTo(0);
6956         assertThat(mService.getNotificationRecord(notif.getKey())).isNull();
6957     }
6958 
6959     @Test
testTimeout_NoCancelForegroundServiceNotification()6960     public void testTimeout_NoCancelForegroundServiceNotification() throws Exception {
6961         // Creates a notification with FLAG_FOREGROUND_SERVICE
6962         final NotificationRecord notif = generateNotificationRecord(null);
6963         notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
6964         mService.addNotification(notif);
6965 
6966         simulateNotificationTimeout(notif.getKey());
6967         waitForIdle();
6968 
6969         // Check that the notification was not cancelled.
6970         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
6971         assertThat(notifsAfter.length).isEqualTo(1);
6972         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
6973     }
6974 
6975     @Test
testTimeout_NoCancelUserInitJobNotification()6976     public void testTimeout_NoCancelUserInitJobNotification() throws Exception {
6977         // Create a notification with FLAG_USER_INITIATED_JOB
6978         final NotificationRecord notif = generateNotificationRecord(null);
6979         notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB;
6980         mService.addNotification(notif);
6981 
6982         simulateNotificationTimeout(notif.getKey());
6983         waitForIdle();
6984 
6985         // Check that the notification was not cancelled.
6986         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
6987         assertThat(notifsAfter.length).isEqualTo(1);
6988         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
6989     }
6990 
6991     @Test
6992     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testTimeout_NoCancelLifetimeExtensionNotification()6993     public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception {
6994         // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY
6995         final NotificationRecord notif = generateNotificationRecord(null);
6996         notif.getSbn().getNotification().flags =
6997                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
6998         mService.addNotification(notif);
6999 
7000         simulateNotificationTimeout(notif.getKey());
7001         waitForIdle();
7002 
7003         // Check that the notification was not cancelled.
7004         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
7005         assertThat(notifsAfter.length).isEqualTo(1);
7006         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
7007 
7008         // Checks that a post update is sent.
7009         verify(mWorkerHandler, times(1))
7010                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
7011         ArgumentCaptor<NotificationRecord> captor =
7012                 ArgumentCaptor.forClass(NotificationRecord.class);
7013         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
7014                 anyBoolean());
7015         assertThat(captor.getValue().getNotification().flags
7016                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
7017                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
7018     }
7019 
7020     @Test
testBumpFGImportance_channelChangePreOApp()7021     public void testBumpFGImportance_channelChangePreOApp() throws Exception {
7022         Notification.Builder nb = new Notification.Builder(mContext,
7023                 NotificationChannel.DEFAULT_CHANNEL_ID)
7024                 .setContentTitle("foo")
7025                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7026                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
7027                 .setPriority(Notification.PRIORITY_MIN);
7028 
7029         StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9,
7030                 "testBumpFGImportance_channelChangePreOApp",
7031                 Binder.getCallingUid(), 0, nb.build(),
7032                 UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
7033 
7034         mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
7035                 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
7036         waitForIdle();
7037 
7038         assertEquals(IMPORTANCE_LOW,
7039                 mService.getNotificationRecord(sbn.getKey()).getImportance());
7040         assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance(
7041                 sbn.getPackageName()));
7042 
7043         nb = new Notification.Builder(mContext)
7044                 .setContentTitle("foo")
7045                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7046                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
7047                 .setPriority(Notification.PRIORITY_MIN);
7048 
7049         sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9,
7050                 "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(),
7051                 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
7052 
7053         mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1,
7054                 "testBumpFGImportance_channelChangePreOApp",
7055                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
7056         waitForIdle();
7057         assertEquals(IMPORTANCE_LOW,
7058                 mService.getNotificationRecord(sbn.getKey()).getImportance());
7059 
7060         NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
7061                 PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID);
7062         assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance());
7063     }
7064 
7065     @Test
testStats_updatedOnDirectReply()7066     public void testStats_updatedOnDirectReply() throws Exception {
7067         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7068         mService.addNotification(r);
7069 
7070         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7071         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied());
7072         verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r));
7073 
7074         assertEquals(1, mNotificationRecordLogger.numCalls());
7075         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
7076                 mNotificationRecordLogger.event(0));
7077     }
7078 
7079     @Test
7080     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate()7081     public void testStats_DirectReplyLifetimeExtendedPostsUpdate() throws Exception {
7082         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7083         // Marks the notification as having already been lifetime extended and canceled.
7084         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7085         r.setCanceledAfterLifetimeExtension(true);
7086         r.setPostSilently(true);
7087         mService.addNotification(r);
7088 
7089         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7090         waitForIdle();
7091 
7092         // At the moment prepareNotifyPostedLocked is called on the listeners,
7093         // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial
7094         // values.
7095         doAnswer(
7096                 invocation -> {
7097                     int flags = ((NotificationRecord) invocation.getArgument(0))
7098                             .getSbn().getNotification().flags;
7099                     assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
7100                     boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0))
7101                             .shouldPostSilently();
7102                     assertThat(shouldPostSilently).isTrue();
7103                     return null;
7104                 }
7105         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
7106 
7107         // Checks that the record gets marked as a direct reply having occurred.
7108         assertThat(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied())
7109                 .isTrue();
7110         // Checks that a post update is sent.
7111         verify(mWorkerHandler, times(1))
7112                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
7113         ArgumentCaptor<NotificationRecord> captor =
7114                 ArgumentCaptor.forClass(NotificationRecord.class);
7115         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
7116                 anyBoolean());
7117         assertThat(captor.getValue().getNotification().flags
7118                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
7119                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
7120         // FLAG_ONLY_ALERT_ONCE was not present on the original notification, so it's not here.
7121         assertThat(captor.getValue().getNotification().flags
7122                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0);
7123         assertThat(captor.getValue().shouldPostSilently()).isTrue();
7124         assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isTrue();
7125     }
7126 
7127     @Test
7128     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently()7129     public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently()
7130             throws Exception {
7131         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7132         // Marks the notification as having already been lifetime extended and canceled.
7133         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7134         r.setPostSilently(false);
7135         mService.addNotification(r);
7136 
7137         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7138         waitForIdle();
7139 
7140         // Checks that a post update is sent with shouldPostSilently set to true.
7141         doAnswer(
7142                 invocation -> {
7143                     boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0))
7144                             .shouldPostSilently();
7145                     assertThat(shouldPostSilently).isTrue();
7146                     return null;
7147                 }
7148         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
7149 
7150         // Checks that shouldPostSilently is restored to its false state afterward.
7151         assertThat(mService.getNotificationRecord(r.getKey()).shouldPostSilently()).isFalse();
7152     }
7153 
7154     @Test
7155     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag()7156     public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag()
7157             throws Exception {
7158         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7159         // Marks the notification as having already been lifetime extended and canceled.
7160         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7161         mService.addNotification(r);
7162 
7163         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7164         waitForIdle();
7165 
7166         // Checks that a post update is sent with FLAG_ONLY_ALERT_ONCE set to true.
7167         doAnswer(
7168                 invocation -> {
7169                     int flags = ((NotificationRecord) invocation.getArgument(0))
7170                             .getSbn().getNotification().flags;
7171                     assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
7172                     return null;
7173                 }
7174         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
7175 
7176         // Checks that the flag is removed afterward.
7177         assertThat(mService.getNotificationRecord(r.getKey()).getSbn().getNotification().flags
7178                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0);
7179     }
7180 
7181     @Test
7182     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds()7183     public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception {
7184         // Creates a lifetime extended notification.
7185         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
7186         original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7187         mService.addNotification(original);
7188 
7189         // Post an update for that notification.
7190         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
7191                 original.getSbn().getTag(), mUid, 0,
7192                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
7193                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
7194                         .setContentTitle("new title").build(),
7195                 UserHandle.getUserHandleForUid(mUid), null, 0);
7196         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7197         mService.addEnqueuedNotification(update);
7198 
7199         NotificationManagerService.PostNotificationRunnable runnable =
7200                 mService.new PostNotificationRunnable(update.getKey(),
7201                         update.getSbn().getPackageName(),
7202                         update.getUid(),
7203                         mPostNotificationTrackerFactory.newTracker(null));
7204         runnable.run();
7205         waitForIdle();
7206 
7207         // Checks the update was sent, and that update contains the new title, and does not contain
7208         // the lifetime extension flag.
7209         ArgumentCaptor<NotificationRecord> captor =
7210                 ArgumentCaptor.forClass(NotificationRecord.class);
7211         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
7212                 anyBoolean());
7213         assertThat(captor.getValue().getNotification().flags
7214                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
7215         assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isFalse();
7216         assertThat(captor.getValue()
7217                 .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString())
7218                 .isEqualTo("new title");
7219     }
7220 
7221     @Test
testStats_updatedOnUserExpansion()7222     public void testStats_updatedOnUserExpansion() throws Exception {
7223         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7224         mService.addNotification(r);
7225 
7226         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true,
7227                 NOTIFICATION_LOCATION_UNKNOWN);
7228         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
7229                 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true)));
7230         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7231 
7232         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false,
7233                 NOTIFICATION_LOCATION_UNKNOWN);
7234         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
7235                 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false)));
7236         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7237 
7238         assertEquals(2, mNotificationRecordLogger.numCalls());
7239         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER,
7240                 mNotificationRecordLogger.event(0));
7241         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER,
7242                 mNotificationRecordLogger.event(1));
7243     }
7244 
7245     @Test
testStats_notUpdatedOnAutoExpansion()7246     public void testStats_notUpdatedOnAutoExpansion() throws Exception {
7247         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7248         mService.addNotification(r);
7249 
7250         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
7251                 NOTIFICATION_LOCATION_UNKNOWN);
7252         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7253         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
7254                 eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true)));
7255 
7256         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false,
7257                 NOTIFICATION_LOCATION_UNKNOWN);
7258         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7259         verify(mAssistants).notifyAssistantExpansionChangedLocked(
7260                 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false)));
7261     }
7262 
7263     @Test
testStats_updatedOnViewSettings()7264     public void testStats_updatedOnViewSettings() throws Exception {
7265         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7266         mService.addNotification(r);
7267 
7268         mService.mNotificationDelegate.onNotificationSettingsViewed(r.getKey());
7269         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasViewedSettings());
7270     }
7271 
7272     @Test
testStats_updatedOnVisibilityChanged()7273     public void testStats_updatedOnVisibilityChanged() throws Exception {
7274         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7275         mService.addNotification(r);
7276 
7277         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true);
7278         mService.mNotificationDelegate.onNotificationVisibilityChanged(
7279                 new NotificationVisibility[] {nv}, new NotificationVisibility[]{});
7280         verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true));
7281         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
7282         mService.mNotificationDelegate.onNotificationVisibilityChanged(
7283                 new NotificationVisibility[] {}, new NotificationVisibility[]{nv});
7284         verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false));
7285         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
7286     }
7287 
7288     @Test
testStats_dismissalSurface()7289     public void testStats_dismissalSurface() throws Exception {
7290         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7291         r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7292         mService.addNotification(r);
7293 
7294         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
7295         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(),
7296                 r.getKey(), NotificationStats.DISMISSAL_AOD,
7297                 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv);
7298         waitForIdle();
7299 
7300         assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface());
7301 
7302         // Using mService.addNotification() does not generate a NotificationRecordLogger log,
7303         // so we only get the cancel notification.
7304         assertEquals(1, mNotificationRecordLogger.numCalls());
7305 
7306         assertEquals(
7307                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
7308                 mNotificationRecordLogger.event(0));
7309         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
7310     }
7311 
7312     @Test
testStats_dismissalSentiment()7313     public void testStats_dismissalSentiment() throws Exception {
7314         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7315         mService.addNotification(r);
7316 
7317         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
7318         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(),
7319                 r.getKey(), NotificationStats.DISMISSAL_AOD,
7320                 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv);
7321         waitForIdle();
7322 
7323         assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE,
7324                 r.getStats().getDismissalSentiment());
7325     }
7326 
7327     @Test
testTextChangedSet_forNewNotifs()7328     public void testTextChangedSet_forNewNotifs() throws Exception {
7329         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
7330         mService.addEnqueuedNotification(original);
7331 
7332         NotificationManagerService.PostNotificationRunnable runnable =
7333                 mService.new PostNotificationRunnable(original.getKey(),
7334                         original.getSbn().getPackageName(),
7335                         original.getUid(),
7336                         mPostNotificationTrackerFactory.newTracker(null));
7337         runnable.run();
7338         waitForIdle();
7339 
7340         assertTrue(original.isTextChanged());
7341     }
7342 
7343     @Test
testVisuallyInterruptive_notSeen()7344     public void testVisuallyInterruptive_notSeen() throws Exception {
7345         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
7346         mService.addNotification(original);
7347 
7348         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
7349                 original.getSbn().getTag(), mUid, 0,
7350                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
7351                         .setContentTitle("new title").build(),
7352                 UserHandle.getUserHandleForUid(mUid), null, 0);
7353         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7354         mService.addEnqueuedNotification(update);
7355 
7356         NotificationManagerService.PostNotificationRunnable runnable =
7357                 mService.new PostNotificationRunnable(update.getKey(),
7358                         update.getSbn().getPackageName(),
7359                         update.getUid(),
7360                         mPostNotificationTrackerFactory.newTracker(null));
7361         runnable.run();
7362         waitForIdle();
7363 
7364         assertFalse(update.isInterruptive());
7365     }
7366 
7367     @Test
testApplyAdjustmentMultiUser()7368     public void testApplyAdjustmentMultiUser() throws Exception {
7369         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7370         mService.addNotification(r);
7371         NotificationManagerService.WorkerHandler handler = mock(
7372                 NotificationManagerService.WorkerHandler.class);
7373         mService.setHandler(handler);
7374 
7375         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false);
7376 
7377         Bundle signals = new Bundle();
7378         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7379                 USER_SENTIMENT_NEGATIVE);
7380         Adjustment adjustment = new Adjustment(
7381                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7382         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
7383 
7384         waitForIdle();
7385 
7386         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
7387     }
7388 
7389     @Test
testAssistantBlockingTriggersCancel()7390     public void testAssistantBlockingTriggersCancel() throws Exception {
7391         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7392         mService.addNotification(r);
7393         NotificationManagerService.WorkerHandler handler = mock(
7394                 NotificationManagerService.WorkerHandler.class);
7395         mService.setHandler(handler);
7396 
7397         Bundle signals = new Bundle();
7398         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE);
7399         Adjustment adjustment = new Adjustment(
7400                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7401         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
7402         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
7403 
7404         waitForIdle();
7405 
7406         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
7407         verify(handler, times(1)).scheduleCancelNotification(any(), eq(0));
7408     }
7409 
7410     @Test
testApplyEnqueuedAdjustmentFromAssistant_singleUser()7411     public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception {
7412         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7413         mService.addEnqueuedNotification(r);
7414         NotificationManagerService.WorkerHandler handler = mock(
7415                 NotificationManagerService.WorkerHandler.class);
7416         mService.setHandler(handler);
7417         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7418 
7419         Bundle signals = new Bundle();
7420         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7421                 USER_SENTIMENT_NEGATIVE);
7422         Adjustment adjustment = new Adjustment(
7423                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7424         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7425 
7426         assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
7427     }
7428 
7429     @Test
testApplyEnqueuedAdjustmentFromAssistant_importance()7430     public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception {
7431         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7432         mService.addEnqueuedNotification(r);
7433         NotificationManagerService.WorkerHandler handler = mock(
7434                 NotificationManagerService.WorkerHandler.class);
7435         mService.setHandler(handler);
7436         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7437 
7438         Bundle signals = new Bundle();
7439         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
7440         Adjustment adjustment = new Adjustment(
7441                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7442         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7443 
7444         assertEquals(IMPORTANCE_LOW, r.getImportance());
7445     }
7446 
7447     @Test
testApplyEnqueuedAdjustmentFromAssistant_crossUser()7448     public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception {
7449         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7450         mService.addEnqueuedNotification(r);
7451         NotificationManagerService.WorkerHandler handler = mock(
7452                 NotificationManagerService.WorkerHandler.class);
7453         mService.setHandler(handler);
7454         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false);
7455 
7456         Bundle signals = new Bundle();
7457         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7458                 USER_SENTIMENT_NEGATIVE);
7459         Adjustment adjustment = new Adjustment(
7460                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7461         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7462 
7463         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
7464 
7465         waitForIdle();
7466 
7467         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
7468     }
7469 
7470     @Test
testUserSentimentChangeTriggersUpdate()7471     public void testUserSentimentChangeTriggersUpdate() throws Exception {
7472         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7473         mService.addNotification(r);
7474         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7475 
7476         Bundle signals = new Bundle();
7477         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7478                 USER_SENTIMENT_NEGATIVE);
7479         Adjustment adjustment = new Adjustment(
7480                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7481         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
7482 
7483         waitForIdle();
7484 
7485         verify(mRankingHandler, timeout(300).times(1)).requestSort();
7486     }
7487 
7488     @Test
testTooLateAdjustmentTriggersUpdate()7489     public void testTooLateAdjustmentTriggersUpdate() throws Exception {
7490         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7491         mService.addNotification(r);
7492         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7493 
7494         Bundle signals = new Bundle();
7495         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7496                 USER_SENTIMENT_NEGATIVE);
7497         Adjustment adjustment = new Adjustment(
7498                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7499         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7500 
7501         waitForIdle();
7502 
7503         verify(mRankingHandler, times(1)).requestSort();
7504     }
7505 
7506     @Test
testApplyAdjustmentsLogged()7507     public void testApplyAdjustmentsLogged() throws Exception {
7508         NotificationManagerService.WorkerHandler handler = mock(
7509                 NotificationManagerService.WorkerHandler.class);
7510         mService.setHandler(handler);
7511         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7512 
7513         // Set up notifications that will be adjusted
7514         final NotificationRecord r1 = generateNotificationRecord(
7515                 mTestNotificationChannel, 1, null, true);
7516         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7517         mService.addNotification(r1);
7518         final NotificationRecord r2 = generateNotificationRecord(
7519                 mTestNotificationChannel, 2, null, true);
7520         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7521         mService.addNotification(r2);
7522 
7523         // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously
7524         // logged.
7525         final NotificationRecord r3 = generateNotificationRecord(
7526                 mTestNotificationChannel, 3, null, true);
7527         r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7528         mService.addNotification(r3);
7529 
7530         List<Adjustment> adjustments = new ArrayList<>();
7531 
7532         // Test an adjustment that's associated with a ranking change and one that's not
7533         Bundle signals1 = new Bundle();
7534         signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH);
7535         Adjustment adjustment1 = new Adjustment(
7536                 r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
7537                 r1.getUser().getIdentifier());
7538         adjustments.add(adjustment1);
7539 
7540         // This one wouldn't trigger a ranking change, but should still trigger a log.
7541         Bundle signals2 = new Bundle();
7542         signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f);
7543         Adjustment adjustment2 = new Adjustment(
7544                 r2.getSbn().getPackageName(), r2.getKey(), signals2, "",
7545                 r2.getUser().getIdentifier());
7546         adjustments.add(adjustment2);
7547 
7548         mBinderService.applyAdjustmentsFromAssistant(null, adjustments);
7549         verify(mRankingHandler, times(1)).requestSort();
7550 
7551         // Actually apply the adjustments & recalculate importance when run
7552         doAnswer(invocationOnMock -> {
7553             ((NotificationRecord) invocationOnMock.getArguments()[0])
7554                     .applyAdjustments();
7555             ((NotificationRecord) invocationOnMock.getArguments()[0])
7556                     .calculateImportance();
7557             return null;
7558         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
7559 
7560         // Now make sure that when the sort happens, we actually log the changes.
7561         mService.handleRankingSort();
7562 
7563         // Even though the ranking score change is not meant to trigger a ranking update,
7564         // during this process the package visibility & canShowBadge values are changing
7565         // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead
7566         // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed
7567         // accordingly to confirm the adjustments happened to the 2 relevant notifications.
7568         verify(handler, times(3)).scheduleSendRankingUpdate();
7569         assertEquals(IMPORTANCE_HIGH, r1.getImportance());
7570         assertTrue(r2.rankingScoreMatches(-0.5f));
7571         assertEquals(2, mNotificationRecordLogger.numCalls());
7572         assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(0));
7573         assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(1));
7574         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
7575         assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId());
7576     }
7577 
7578     @Test
testSensitiveAdjustmentsLogged()7579     public void testSensitiveAdjustmentsLogged() throws Exception {
7580         NotificationManagerService.WorkerHandler handler = mock(
7581                 NotificationManagerService.WorkerHandler.class);
7582         mService.setHandler(handler);
7583         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
7584         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
7585 
7586         // Set up notifications that will be adjusted
7587         final NotificationRecord r1 = spy(generateNotificationRecord(
7588                 mTestNotificationChannel, 1, null, true));
7589         when(r1.getLifespanMs(anyLong())).thenReturn(1);
7590 
7591         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7592         mService.addEnqueuedNotification(r1);
7593 
7594         // Test an adjustment for an enqueued notification
7595         Bundle signals = new Bundle();
7596         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true);
7597         Adjustment adjustment1 = new Adjustment(
7598                 r1.getSbn().getPackageName(), r1.getKey(), signals, "",
7599                 r1.getUser().getIdentifier());
7600         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1);
7601         assertTrue(mService.checkLastSensitiveLog(false, true, 1));
7602 
7603         // Set up notifications that will be adjusted
7604         final NotificationRecord r2 = spy(generateNotificationRecord(
7605                 mTestNotificationChannel, 1, null, true));
7606         when(r2.getLifespanMs(anyLong())).thenReturn(2);
7607 
7608         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7609         mService.addNotification(r2);
7610         Adjustment adjustment2 = new Adjustment(
7611                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7612                 r2.getUser().getIdentifier());
7613         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2);
7614         assertTrue(mService.checkLastSensitiveLog(true, true, 2));
7615 
7616         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, false);
7617         Adjustment adjustment3 = new Adjustment(
7618                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7619                 r2.getUser().getIdentifier());
7620         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3);
7621         assertTrue(mService.checkLastSensitiveLog(true, false, 2));
7622     }
7623 
7624     @Test
7625     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testClassificationChannelAdjustmentsLogged()7626     public void testClassificationChannelAdjustmentsLogged() throws Exception {
7627         NotificationManagerService.WorkerHandler handler = mock(
7628                 NotificationManagerService.WorkerHandler.class);
7629         mService.setHandler(handler);
7630         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
7631         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
7632         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
7633         when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
7634 
7635         // Set up notifications that will be adjusted
7636         final NotificationRecord r1 = spy(generateNotificationRecord(
7637                 mTestNotificationChannel, 1, null, true));
7638         when(r1.getLifespanMs(anyLong())).thenReturn(234);
7639 
7640         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7641         // Enqueues the notification to be posted, so hasPosted will be false.
7642         mService.addEnqueuedNotification(r1);
7643 
7644         // Test an adjustment for an enqueued notification
7645         Bundle signals = new Bundle();
7646         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
7647         Adjustment adjustment1 = new Adjustment(
7648                 r1.getSbn().getPackageName(), r1.getKey(), signals, "",
7649                 r1.getUser().getIdentifier());
7650         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1);
7651         assertTrue(mService.checkLastClassificationChannelLog(false /*hasPosted*/,
7652                 true /*isAlerting*/, 3 /*TYPE_NEWS*/, 234));
7653 
7654         // Set up notifications that will be adjusted
7655         // This notification starts on a low importance channel, so isAlerting is false.
7656         NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel(
7657                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW);
7658         final NotificationRecord r2 = spy(generateNotificationRecord(
7659                 mLowImportanceNotificationChannel, 1, null, true));
7660         when(r2.getLifespanMs(anyLong())).thenReturn(345);
7661 
7662         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7663         // Adds the notification as already posted, so hasPosted will be true.
7664         mService.addNotification(r2);
7665         // The signal is removed when used so it has to be readded.
7666         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
7667         Adjustment adjustment2 = new Adjustment(
7668                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7669                 r2.getUser().getIdentifier());
7670         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2);
7671         assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/,
7672                 false /*isAlerting*/, 3 /*TYPE_NEWS*/, 345)); // currently failing
7673 
7674         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION);
7675         Adjustment adjustment3 = new Adjustment(
7676                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7677                 r2.getUser().getIdentifier());
7678         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3);
7679         assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/,
7680                 false /*isAlerting*/, 1 /*TYPE_PROMOTION*/, 345));
7681     }
7682 
7683     @Test
testAdjustmentToImportanceNone_cancelsNotification()7684     public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception {
7685         NotificationManagerService.WorkerHandler handler = mock(
7686                 NotificationManagerService.WorkerHandler.class);
7687         mService.setHandler(handler);
7688         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7689         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
7690 
7691         // Set up notifications: r1 is adjusted, r2 is not
7692         final NotificationRecord r1 = generateNotificationRecord(
7693                 mTestNotificationChannel, 1, null, true);
7694         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7695         mService.addNotification(r1);
7696         final NotificationRecord r2 = generateNotificationRecord(
7697                 mTestNotificationChannel, 2, null, true);
7698         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7699         mService.addNotification(r2);
7700 
7701         // Test an adjustment that sets importance to none (meaning it's cancelling)
7702         Bundle signals1 = new Bundle();
7703         signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
7704         Adjustment adjustment1 = new Adjustment(
7705                 r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
7706                 r1.getUser().getIdentifier());
7707 
7708         mBinderService.applyAdjustmentFromAssistant(null, adjustment1);
7709 
7710         // Actually apply the adjustments & recalculate importance when run
7711         doAnswer(invocationOnMock -> {
7712             ((NotificationRecord) invocationOnMock.getArguments()[0])
7713                     .applyAdjustments();
7714             ((NotificationRecord) invocationOnMock.getArguments()[0])
7715                     .calculateImportance();
7716             return null;
7717         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
7718 
7719         // run the CancelNotificationRunnable when it happens
7720         ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor =
7721                 ArgumentCaptor.forClass(
7722                         NotificationManagerService.CancelNotificationRunnable.class);
7723 
7724         verify(handler, times(1)).scheduleCancelNotification(
7725                 captor.capture(), eq(0));
7726 
7727         // Run the runnable given to the cancel notification, and see if it logs properly
7728         NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue();
7729         runnable.run();
7730         assertEquals(1, mNotificationRecordLogger.numCalls());
7731         assertEquals(
7732                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT,
7733                 mNotificationRecordLogger.event(0));
7734     }
7735 
7736     @Test
testEnqueuedAdjustmentAppliesAdjustments()7737     public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
7738         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7739         mService.addEnqueuedNotification(r);
7740         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7741 
7742         Bundle signals = new Bundle();
7743         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7744                 USER_SENTIMENT_NEGATIVE);
7745         Adjustment adjustment = new Adjustment(
7746                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7747         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7748 
7749         assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
7750     }
7751 
7752     @Test
testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications()7753     public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception {
7754         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel);
7755         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel);
7756         mService.addEnqueuedNotification(r1);
7757         mService.addEnqueuedNotification(r2);
7758         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7759 
7760         Bundle signals = new Bundle();
7761         signals.putInt(Adjustment.KEY_IMPORTANCE,
7762                 IMPORTANCE_HIGH);
7763         Adjustment adjustment = new Adjustment(
7764                 r1.getSbn().getPackageName(), r1.getKey(), signals,
7765                 "", r1.getUser().getIdentifier());
7766 
7767         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7768 
7769         assertEquals(IMPORTANCE_HIGH, r1.getImportance());
7770         assertEquals(IMPORTANCE_HIGH, r2.getImportance());
7771     }
7772 
7773     @Test
testRestore()7774     public void testRestore() throws Exception {
7775         int systemChecks = mService.countSystemChecks;
7776         mBinderService.applyRestore(null, USER_SYSTEM);
7777         assertEquals(1, mService.countSystemChecks - systemChecks);
7778     }
7779 
7780     @Test
testBackupEmptySound()7781     public void testBackupEmptySound() throws Exception {
7782         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
7783         channel.setSound(Uri.EMPTY, null);
7784 
7785         TypedXmlSerializer serializer = Xml.newFastSerializer();
7786         ByteArrayOutputStream baos = new ByteArrayOutputStream();
7787         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
7788         channel.writeXmlForBackup(serializer, getContext());
7789 
7790         TypedXmlPullParser parser = Xml.newFastPullParser();
7791         parser.setInput(new BufferedInputStream(
7792                 new ByteArrayInputStream(baos.toByteArray())), null);
7793         NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
7794         restored.populateFromXmlForRestore(parser, true, getContext());
7795 
7796         assertNull(restored.getSound());
7797     }
7798 
7799     @Test
testBackup()7800     public void testBackup() throws Exception {
7801         mService.setPreferencesHelper(mPreferencesHelper);
7802         int systemChecks = mService.countSystemChecks;
7803         when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
7804                 .thenReturn(new ArraySet<>());
7805         mBinderService.getBackupPayload(1);
7806         assertEquals(1, mService.countSystemChecks - systemChecks);
7807     }
7808 
7809     @Test
testEmptyVibration_noException()7810     public void testEmptyVibration_noException() throws Exception {
7811         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
7812         channel.setVibrationPattern(new long[0]);
7813 
7814         TypedXmlSerializer serializer = Xml.newFastSerializer();
7815         ByteArrayOutputStream baos = new ByteArrayOutputStream();
7816         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
7817         channel.writeXml(serializer);
7818     }
7819 
7820     @Test
updateUriPermissions_update()7821     public void updateUriPermissions_update() throws Exception {
7822         NotificationChannel c = new NotificationChannel(
7823                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
7824         c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
7825         Message message1 = new Message("", 0, "");
7826         message1.setData("",
7827                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1));
7828         Message message2 = new Message("", 1, "");
7829         message2.setData("",
7830                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2));
7831 
7832         Notification.Builder nbA = new Notification.Builder(mContext, c.getId())
7833                 .setContentTitle("foo")
7834                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7835                 .setStyle(new Notification.MessagingStyle("")
7836                         .addMessage(message1)
7837                         .addMessage(message2));
7838         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
7839                 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
7840                 null, 0), c);
7841 
7842         // First post means we grant access to both
7843         reset(mUgm);
7844         reset(mUgmInternal);
7845         when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
7846         mService.updateUriPermissions(recordA, null, mContext.getPackageName(),
7847                 USER_SYSTEM);
7848         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
7849                 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
7850         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
7851                 eq(message2.getDataUri()), anyInt(), anyInt(), anyInt());
7852 
7853         Notification.Builder nbB = new Notification.Builder(mContext, c.getId())
7854                 .setContentTitle("foo")
7855                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7856                 .setStyle(new Notification.MessagingStyle("").addMessage(message2));
7857         NotificationRecord recordB =
7858                 new NotificationRecord(
7859                         mContext,
7860                         new StatusBarNotification(
7861                                 mPkg,
7862                                 mPkg,
7863                                 0,
7864                                 "tag",
7865                                 mUid,
7866                                 0,
7867                                 nbB.build(),
7868                                 UserHandle.getUserHandleForUid(mUid),
7869                                 null,
7870                                 0),
7871                         c);
7872 
7873         // Update means we drop access to first
7874         reset(mUgmInternal);
7875         mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(),
7876                 USER_SYSTEM);
7877         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(),
7878                 eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1));
7879 
7880         // Update back means we grant access to first again
7881         reset(mUgm);
7882         mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(),
7883                 USER_SYSTEM);
7884         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
7885                 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
7886 
7887         // And update to empty means we drop everything
7888         reset(mUgmInternal);
7889         mService.updateUriPermissions(null, recordB, mContext.getPackageName(),
7890                 USER_SYSTEM);
7891         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null),
7892                 anyInt(), anyInt());
7893     }
7894 
7895     @Test
updateUriPermissions_posterDoesNotOwnUri()7896     public void updateUriPermissions_posterDoesNotOwnUri() throws Exception {
7897         NotificationChannel c = new NotificationChannel(
7898                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
7899         c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
7900         Message message1 = new Message("", 0, "");
7901         message1.setData("",
7902                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1));
7903 
7904         Notification.Builder nbA = new Notification.Builder(mContext, c.getId())
7905                 .setContentTitle("foo")
7906                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7907                 .setStyle(new Notification.MessagingStyle("")
7908                         .addMessage(message1));
7909         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
7910                 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
7911                 null, 0), c);
7912 
7913         doThrow(new SecurityException("no access")).when(mUgm)
7914                 .grantUriPermissionFromOwner(
7915                         any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt());
7916 
7917         when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
7918         mService.updateUriPermissions(recordA, null, mContext.getPackageName(),  USER_SYSTEM);
7919 
7920         // yay, no crash
7921     }
7922 
7923     @Test
testVisitUris()7924     public void testVisitUris() throws Exception {
7925         final Uri audioContents = Uri.parse("content://com.example/audio");
7926         final Uri backgroundImage = Uri.parse("content://com.example/background");
7927         final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon");
7928         final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon");
7929         final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
7930         final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
7931         final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
7932         final Person person1 = new Person.Builder()
7933                 .setName("Messaging Person")
7934                 .setIcon(personIcon1)
7935                 .build();
7936         final Person person2 = new Person.Builder()
7937                 .setName("People List Person 1")
7938                 .setIcon(personIcon2)
7939                 .build();
7940         final Person person3 = new Person.Builder()
7941                 .setName("People List Person 2")
7942                 .setIcon(personIcon3)
7943                 .build();
7944         final Uri historyUri1 = Uri.parse("content://com.example/history1");
7945         final Uri historyUri2 = Uri.parse("content://com.example/history2");
7946         final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1,
7947                 "a");
7948         final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2,
7949                 "b");
7950 
7951         Bundle extras = new Bundle();
7952         extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents);
7953         extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString());
7954         extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1);
7955         extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST,
7956                 new ArrayList<>(Arrays.asList(person2, person3)));
7957         extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
7958                 new RemoteInputHistoryItem[]{historyItem1, historyItem2});
7959 
7960         Notification n = new Notification.Builder(mContext, "a")
7961                 .setContentTitle("notification with uris")
7962                 .setSmallIcon(smallIcon)
7963                 .setLargeIcon(largeIcon)
7964                 .addExtras(extras)
7965                 .build();
7966 
7967         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
7968         n.visitUris(visitor);
7969         verify(visitor, times(1)).accept(eq(audioContents));
7970         verify(visitor, times(1)).accept(eq(backgroundImage));
7971         verify(visitor, times(1)).accept(eq(smallIcon.getUri()));
7972         verify(visitor, times(1)).accept(eq(largeIcon.getUri()));
7973         verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
7974         verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
7975         verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
7976         verify(visitor, times(1)).accept(eq(historyUri1));
7977         verify(visitor, times(1)).accept(eq(historyUri2));
7978     }
7979 
7980     @Test
testVisitUris_publicVersion()7981     public void testVisitUris_publicVersion() throws Exception {
7982         final Icon smallIconPublic = Icon.createWithContentUri("content://media/small/icon");
7983         final Icon largeIconPrivate = Icon.createWithContentUri("content://media/large/icon");
7984 
7985         Notification publicVersion = new Notification.Builder(mContext, "a")
7986                 .setContentTitle("notification with uris")
7987                 .setSmallIcon(smallIconPublic)
7988                 .build();
7989         Notification n = new Notification.Builder(mContext, "a")
7990                 .setLargeIcon(largeIconPrivate)
7991                 .setPublicVersion(publicVersion)
7992                 .build();
7993 
7994         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
7995         n.visitUris(visitor);
7996         verify(visitor, times(1)).accept(eq(smallIconPublic.getUri()));
7997         verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri()));
7998     }
7999 
8000     @Test
testVisitUris_audioContentsString()8001     public void testVisitUris_audioContentsString() throws Exception {
8002         final Uri audioContents = Uri.parse("content://com.example/audio");
8003 
8004         Bundle extras = new Bundle();
8005         extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString());
8006 
8007         Notification n = new Notification.Builder(mContext, "a")
8008                 .setContentTitle("notification with uris")
8009                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
8010                 .addExtras(extras)
8011                 .build();
8012 
8013         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8014         n.visitUris(visitor);
8015         verify(visitor, times(1)).accept(eq(audioContents));
8016     }
8017 
8018     @Test
testVisitUris_messagingStyle()8019     public void testVisitUris_messagingStyle() {
8020         final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
8021         final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
8022         final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
8023         final Person person1 = new Person.Builder()
8024                 .setName("Messaging Person 1")
8025                 .setIcon(personIcon1)
8026                 .build();
8027         final Person person2 = new Person.Builder()
8028                 .setName("Messaging Person 2")
8029                 .setIcon(personIcon2)
8030                 .build();
8031         final Person person3 = new Person.Builder()
8032                 .setName("Messaging Person 3")
8033                 .setIcon(personIcon3)
8034                 .build();
8035         Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut");
8036 
8037         Notification.Builder builder = new Notification.Builder(mContext, "a")
8038                 .setCategory(Notification.CATEGORY_MESSAGE)
8039                 .setContentTitle("new message!")
8040                 .setContentText("Conversation Notification")
8041                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8042         Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message(
8043                 "Marco?", System.currentTimeMillis(), person2);
8044         Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message(
8045                 "Polo!", System.currentTimeMillis(), person3);
8046         Notification.MessagingStyle style = new Notification.MessagingStyle(person1)
8047                 .addMessage(message1)
8048                 .addMessage(message2)
8049                 .setShortcutIcon(shortcutIcon);
8050         builder.setStyle(style);
8051         Notification n = builder.build();
8052 
8053         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8054         n.visitUris(visitor);
8055 
8056         verify(visitor, times(1)).accept(eq(shortcutIcon.getUri()));
8057         verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
8058         verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
8059         verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
8060     }
8061 
8062     @Test
testVisitUris_callStyle()8063     public void testVisitUris_callStyle() {
8064         Icon personIcon = Icon.createWithContentUri("content://media/person");
8065         Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
8066         Person callingPerson = new Person.Builder().setName("Someone")
8067                 .setIcon(personIcon)
8068                 .build();
8069         PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
8070                 PendingIntent.FLAG_IMMUTABLE);
8071         Notification n = new Notification.Builder(mContext, "a")
8072                 .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
8073                         .setVerificationIcon(verificationIcon))
8074                 .setContentTitle("Calling...")
8075                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
8076                 .build();
8077 
8078         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8079         n.visitUris(visitor);
8080 
8081         verify(visitor, times(1)).accept(eq(personIcon.getUri()));
8082         verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
8083         hangUpIntent.cancel();
8084     }
8085 
8086     @Test
testVisitUris_styleExtrasWithoutStyle()8087     public void testVisitUris_styleExtrasWithoutStyle() {
8088         Notification.Builder notification = new Notification.Builder(mContext, "a")
8089                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8090 
8091         Bundle messagingExtras = new Bundle();
8092         messagingExtras.putParcelable(Notification.EXTRA_MESSAGING_PERSON,
8093                 personWithIcon("content://user"));
8094         messagingExtras.putParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES,
8095                 new Bundle[] { new Notification.MessagingStyle.Message("Heyhey!",
8096                         System.currentTimeMillis() - 100,
8097                         personWithIcon("content://historicalMessenger")).toBundle()});
8098         messagingExtras.putParcelableArray(Notification.EXTRA_MESSAGES,
8099                 new Bundle[] { new Notification.MessagingStyle.Message("Are you there?",
8100                         System.currentTimeMillis(),
8101                         personWithIcon("content://messenger")).toBundle()});
8102         messagingExtras.putParcelable(Notification.EXTRA_CONVERSATION_ICON,
8103                 Icon.createWithContentUri("content://conversationShortcut"));
8104         notification.addExtras(messagingExtras);
8105 
8106         Bundle callExtras = new Bundle();
8107         callExtras.putParcelable(Notification.EXTRA_CALL_PERSON,
8108                 personWithIcon("content://caller"));
8109         callExtras.putParcelable(Notification.EXTRA_VERIFICATION_ICON,
8110                 Icon.createWithContentUri("content://callVerification"));
8111         notification.addExtras(callExtras);
8112 
8113         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8114         notification.build().visitUris(visitor);
8115 
8116         verify(visitor).accept(eq(Uri.parse("content://user")));
8117         verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
8118         verify(visitor).accept(eq(Uri.parse("content://messenger")));
8119         verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
8120         verify(visitor).accept(eq(Uri.parse("content://caller")));
8121         verify(visitor).accept(eq(Uri.parse("content://callVerification")));
8122     }
8123 
personWithIcon(String iconUri)8124     private static Person personWithIcon(String iconUri) {
8125         return new Person.Builder()
8126                 .setName("Mr " + iconUri)
8127                 .setIcon(Icon.createWithContentUri(iconUri))
8128                 .build();
8129     }
8130 
8131     @Test
testVisitUris_wearableExtender()8132     public void testVisitUris_wearableExtender() {
8133         Icon actionIcon = Icon.createWithContentUri("content://media/action");
8134         Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
8135         PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
8136                 PendingIntent.FLAG_IMMUTABLE);
8137         Notification n = new Notification.Builder(mContext, "a")
8138                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
8139                 .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
8140                 .extend(new Notification.WearableExtender().addAction(
8141                         new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
8142                 .build();
8143 
8144         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8145         n.visitUris(visitor);
8146 
8147         verify(visitor).accept(eq(actionIcon.getUri()));
8148         verify(visitor).accept(eq(wearActionIcon.getUri()));
8149     }
8150 
8151     @Test
testSetNotificationPolicy_preP_setOldFields()8152     public void testSetNotificationPolicy_preP_setOldFields() {
8153         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8154         mService.mZenModeHelper = mZenModeHelper;
8155         NotificationManager.Policy userPolicy =
8156                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8157         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8158 
8159         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8160                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
8161 
8162         int expected = SUPPRESSED_EFFECT_BADGE
8163                 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
8164                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS
8165                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8166         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
8167 
8168         assertEquals(expected, actual);
8169     }
8170 
8171     @Test
testSetNotificationPolicy_preP_setNewFields()8172     public void testSetNotificationPolicy_preP_setNewFields() {
8173         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8174         mService.mZenModeHelper = mZenModeHelper;
8175         NotificationManager.Policy userPolicy =
8176                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8177         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8178 
8179         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8180                 SUPPRESSED_EFFECT_NOTIFICATION_LIST);
8181 
8182         int expected = SUPPRESSED_EFFECT_BADGE;
8183         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
8184 
8185         assertEquals(expected, actual);
8186     }
8187 
8188     @Test
testSetNotificationPolicy_preP_setOldNewFields()8189     public void testSetNotificationPolicy_preP_setOldNewFields() {
8190         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8191         mService.mZenModeHelper = mZenModeHelper;
8192         NotificationManager.Policy userPolicy =
8193                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8194         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8195 
8196         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8197                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
8198 
8199         int expected =
8200                 SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
8201         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
8202 
8203         assertEquals(expected, actual);
8204     }
8205 
8206     @Test
testSetNotificationPolicy_P_setOldFields()8207     public void testSetNotificationPolicy_P_setOldFields() {
8208         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8209         mService.mZenModeHelper = mZenModeHelper;
8210         NotificationManager.Policy userPolicy =
8211                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8212         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8213 
8214         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8215                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
8216 
8217         int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
8218                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
8219                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8220         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8221 
8222         assertEquals(expected, actual);
8223     }
8224 
8225     @Test
testSetNotificationPolicy_P_setNewFields()8226     public void testSetNotificationPolicy_P_setNewFields() {
8227         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8228         mService.mZenModeHelper = mZenModeHelper;
8229         NotificationManager.Policy userPolicy =
8230                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8231         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8232 
8233         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8234                 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
8235                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
8236 
8237         int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
8238                 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
8239                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8240         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8241 
8242         assertEquals(expected, actual);
8243     }
8244 
8245     @Test
testSetNotificationPolicy_P_setOldNewFields()8246     public void testSetNotificationPolicy_P_setOldNewFields() {
8247         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8248         mService.mZenModeHelper = mZenModeHelper;
8249         NotificationManager.Policy userPolicy =
8250                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8251         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8252 
8253         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8254                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
8255 
8256         int expected =  SUPPRESSED_EFFECT_STATUS_BAR;
8257         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8258 
8259         assertEquals(expected, actual);
8260 
8261         appPolicy = new NotificationManager.Policy(0, 0, 0,
8262                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
8263                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
8264 
8265         expected =  SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
8266                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8267         actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8268 
8269         assertEquals(expected, actual);
8270     }
8271 
8272     @Test
testVisualDifference_foreground()8273     public void testVisualDifference_foreground() {
8274         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8275                 .setContentTitle("foo");
8276         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8277                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8278         NotificationRecord r1 =
8279                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8280 
8281         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8282                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
8283                 .setContentTitle("bar");
8284         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8285                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8286         NotificationRecord r2 =
8287                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8288 
8289         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8290     }
8291 
8292     @Test
testVisualDifference_diffTitle()8293     public void testVisualDifference_diffTitle() {
8294         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8295                 .setContentTitle("foo");
8296         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8297                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8298         NotificationRecord r1 =
8299                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8300 
8301         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8302                 .setContentTitle("bar");
8303         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8304                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8305         NotificationRecord r2 =
8306                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8307 
8308         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8309     }
8310 
8311     @Test
testVisualDifference_inboxStyle()8312     public void testVisualDifference_inboxStyle() {
8313         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8314                 .setStyle(new Notification.InboxStyle()
8315                     .addLine("line1").addLine("line2"));
8316         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8317                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8318         NotificationRecord r1 =
8319                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8320 
8321         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8322                 .setStyle(new Notification.InboxStyle()
8323                         .addLine("line1").addLine("line2_changed"));
8324         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8325                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8326         NotificationRecord r2 =
8327                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8328 
8329         assertTrue(mService.isVisuallyInterruptive(r1, r2)); // line 2 changed unnoticed
8330 
8331         Notification.Builder nb3 = new Notification.Builder(mContext, "")
8332                 .setStyle(new Notification.InboxStyle()
8333                         .addLine("line1"));
8334         StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8335                 nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8336         NotificationRecord r3 =
8337                 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class));
8338 
8339         assertTrue(mService.isVisuallyInterruptive(r1, r3)); // line 2 removed unnoticed
8340 
8341         Notification.Builder nb4 = new Notification.Builder(mContext, "")
8342                 .setStyle(new Notification.InboxStyle()
8343                         .addLine("line1").addLine("line2").addLine("line3"));
8344         StatusBarNotification sbn4 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8345                 nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8346         NotificationRecord r4 =
8347                 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class));
8348 
8349         assertTrue(mService.isVisuallyInterruptive(r1, r4)); // line 3 added unnoticed
8350 
8351         Notification.Builder nb5 = new Notification.Builder(mContext, "")
8352             .setContentText("not an inbox");
8353         StatusBarNotification sbn5 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8354                 nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8355         NotificationRecord r5 =
8356                 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class));
8357 
8358         assertTrue(mService.isVisuallyInterruptive(r1, r5)); // changed Styles, went unnoticed
8359     }
8360 
8361     @Test
testVisualDifference_diffText()8362     public void testVisualDifference_diffText() {
8363         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8364                 .setContentText("foo");
8365         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8366                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8367         NotificationRecord r1 =
8368                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8369 
8370         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8371                 .setContentText("bar");
8372         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8373                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8374         NotificationRecord r2 =
8375                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8376 
8377         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8378     }
8379 
8380     @Test
testVisualDifference_sameText()8381     public void testVisualDifference_sameText() {
8382         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8383                 .setContentText("foo");
8384         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8385                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8386         NotificationRecord r1 =
8387                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8388 
8389         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8390                 .setContentText("foo");
8391         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8392                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8393         NotificationRecord r2 =
8394                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8395 
8396         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8397     }
8398 
8399     @Test
testVisualDifference_sameTextButStyled()8400     public void testVisualDifference_sameTextButStyled() {
8401         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8402                 .setContentText(Html.fromHtml("<b>foo</b>"));
8403         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8404                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8405         NotificationRecord r1 =
8406                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8407 
8408         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8409                 .setContentText(Html.fromHtml("<b>foo</b>"));
8410         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8411                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8412         NotificationRecord r2 =
8413                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8414 
8415         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8416     }
8417 
8418     @Test
testVisualDifference_diffTextButStyled()8419     public void testVisualDifference_diffTextButStyled() {
8420         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8421                 .setContentText(Html.fromHtml("<b>foo</b>"));
8422         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8423                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8424         NotificationRecord r1 =
8425                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8426 
8427         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8428                 .setContentText(Html.fromHtml("<b>bar</b>"));
8429         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8430                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8431         NotificationRecord r2 =
8432                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8433 
8434         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8435     }
8436 
8437     @Test
testVisualDifference_diffProgress()8438     public void testVisualDifference_diffProgress() {
8439         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8440                 .setProgress(100, 90, false);
8441         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8442                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8443         NotificationRecord r1 =
8444                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8445 
8446         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8447                 .setProgress(100, 100, false);
8448         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8449                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8450         NotificationRecord r2 =
8451                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8452 
8453         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8454     }
8455 
8456     @Test
testVisualDifference_diffProgressNotDone()8457     public void testVisualDifference_diffProgressNotDone() {
8458         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8459                 .setProgress(100, 90, false);
8460         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8461                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8462         NotificationRecord r1 =
8463                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8464 
8465         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8466                 .setProgress(100, 91, false);
8467         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8468                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8469         NotificationRecord r2 =
8470                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8471 
8472         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8473     }
8474 
8475     @Test
testVisualDifference_sameProgressStillDone()8476     public void testVisualDifference_sameProgressStillDone() {
8477         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8478                 .setProgress(100, 100, false);
8479         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8480                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8481         NotificationRecord r1 =
8482                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8483 
8484         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8485                 .setProgress(100, 100, false);
8486         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8487                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8488         NotificationRecord r2 =
8489                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8490 
8491         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8492     }
8493 
8494     @Test
testVisualDifference_summary()8495     public void testVisualDifference_summary() {
8496         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8497                 .setGroup("bananas")
8498                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
8499                 .setContentText("foo");
8500         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8501                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8502         NotificationRecord r1 =
8503                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8504 
8505         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8506                 .setGroup("bananas")
8507                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
8508                 .setContentText("bar");
8509         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8510                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8511         NotificationRecord r2 =
8512                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8513 
8514         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8515     }
8516 
8517     @Test
testVisualDifference_summaryNewNotification()8518     public void testVisualDifference_summaryNewNotification() {
8519         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8520                 .setGroup("bananas")
8521                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
8522                 .setContentText("bar");
8523         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8524                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8525         NotificationRecord r2 =
8526                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8527 
8528         assertFalse(mService.isVisuallyInterruptive(null, r2));
8529     }
8530 
8531     @Test
testVisualDifference_sameImages()8532     public void testVisualDifference_sameImages() {
8533         Icon large = Icon.createWithResource(mContext, 1);
8534         Notification n1 = new Notification.Builder(mContext, "channel")
8535                 .setSmallIcon(1).setLargeIcon(large).build();
8536         Notification n2 = new Notification.Builder(mContext, "channel")
8537                 .setSmallIcon(1).setLargeIcon(large).build();
8538 
8539         NotificationRecord r1 = notificationToRecord(n1);
8540         NotificationRecord r2 = notificationToRecord(n2);
8541 
8542         assertThat(mService.isVisuallyInterruptive(r1, r2)).isFalse();
8543     }
8544 
8545     @Test
testVisualDifference_differentSmallImage()8546     public void testVisualDifference_differentSmallImage() {
8547         Icon large = Icon.createWithResource(mContext, 1);
8548         Notification n1 = new Notification.Builder(mContext, "channel")
8549                 .setSmallIcon(1).setLargeIcon(large).build();
8550         Notification n2 = new Notification.Builder(mContext, "channel")
8551                 .setSmallIcon(2).setLargeIcon(large).build();
8552 
8553         NotificationRecord r1 = notificationToRecord(n1);
8554         NotificationRecord r2 = notificationToRecord(n2);
8555 
8556         assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue();
8557     }
8558 
8559     @Test
testVisualDifference_differentLargeImage()8560     public void testVisualDifference_differentLargeImage() {
8561         Icon large1 = Icon.createWithResource(mContext, 1);
8562         Icon large2 = Icon.createWithResource(mContext, 2);
8563         Notification n1 = new Notification.Builder(mContext, "channel")
8564                 .setSmallIcon(1).setLargeIcon(large1).build();
8565         Notification n2 = new Notification.Builder(mContext, "channel")
8566                 .setSmallIcon(1).setLargeIcon(large2).build();
8567 
8568         NotificationRecord r1 = notificationToRecord(n1);
8569         NotificationRecord r2 = notificationToRecord(n2);
8570 
8571         assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue();
8572     }
8573 
8574     @Test
8575     @EnableFlags({android.app.Flags.FLAG_SORT_SECTION_BY_TIME})
testVisualDifference_userInitiatedJob()8576     public void testVisualDifference_userInitiatedJob() {
8577         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8578                 .setContentTitle("foo");
8579         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8580                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8581         NotificationRecord r1 =
8582                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8583 
8584         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8585                 .setFlag(FLAG_USER_INITIATED_JOB, true)
8586                 .setContentTitle("bar");
8587         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8588                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8589         NotificationRecord r2 =
8590                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8591 
8592         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8593     }
8594 
notificationToRecord(Notification n)8595     private NotificationRecord notificationToRecord(Notification n) {
8596         return new NotificationRecord(
8597                 mContext,
8598                 new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, n,
8599                         UserHandle.getUserHandleForUid(mUid), null, 0),
8600                 mock(NotificationChannel.class));
8601     }
8602 
8603     @Test
testHideAndUnhideNotificationsOnSuspendedPackageBroadcast()8604     public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
8605         // post 2 notification from this package
8606         final NotificationRecord notif1 = generateNotificationRecord(
8607                 mTestNotificationChannel, 1, null, true);
8608         final NotificationRecord notif2 = generateNotificationRecord(
8609                 mTestNotificationChannel, 2, null, false);
8610         mService.addNotification(notif1);
8611         mService.addNotification(notif2);
8612 
8613         // on broadcast, hide the 2 notifications
8614         simulatePackageSuspendBroadcast(true, mPkg, notif1.getUid());
8615         ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class);
8616         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
8617         assertEquals(2, captorHide.getValue().size());
8618 
8619         // on broadcast, unhide the 2 notifications
8620         simulatePackageSuspendBroadcast(false, mPkg, notif1.getUid());
8621         ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class);
8622         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
8623         assertEquals(2, captorUnhide.getValue().size());
8624     }
8625 
8626     @Test
testNoNotificationsHiddenOnSuspendedPackageBroadcast()8627     public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() {
8628         // post 2 notification from this package
8629         final NotificationRecord notif1 = generateNotificationRecord(
8630                 mTestNotificationChannel, 1, null, true);
8631         final NotificationRecord notif2 = generateNotificationRecord(
8632                 mTestNotificationChannel, 2, null, false);
8633         mService.addNotification(notif1);
8634         mService.addNotification(notif2);
8635 
8636         // on broadcast, nothing is hidden since no notifications are of package "test_package"
8637         simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid());
8638         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
8639         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
8640         assertEquals(0, captor.getValue().size());
8641     }
8642 
8643     @Test
testNotificationFromDifferentUserHidden()8644     public void testNotificationFromDifferentUserHidden() {
8645         // post 2 notification from this package
8646         final NotificationRecord notif1 = generateNotificationRecord(
8647                 mTestNotificationChannel, 1, null, true);
8648         final NotificationRecord notif2 = generateNotificationRecord(
8649                 mTestNotificationChannel, 2, null, false);
8650         mService.addNotification(notif1);
8651         mService.addNotification(notif2);
8652 
8653         // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG
8654         simulatePackageSuspendBroadcast(true, mPkg, 10);
8655         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
8656         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
8657         assertEquals(0, captor.getValue().size());
8658     }
8659 
8660     @Test
testHideAndUnhideNotificationsOnDistractingPackageBroadcast()8661     public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() {
8662         // Post 2 notifications from 2 packages
8663         NotificationRecord pkgA = new NotificationRecord(mContext,
8664                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
8665         mService.addNotification(pkgA);
8666         NotificationRecord pkgB = new NotificationRecord(mContext,
8667                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
8668         mService.addNotification(pkgB);
8669 
8670         // on broadcast, hide one of the packages
8671         simulatePackageDistractionBroadcast(
8672                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"},
8673                 new int[] {1000});
8674         ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
8675         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
8676         assertEquals(1, captorHide.getValue().size());
8677         assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
8678 
8679         // on broadcast, unhide the package
8680         simulatePackageDistractionBroadcast(
8681                 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"},
8682                 new int[] {1000});
8683         ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
8684         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
8685         assertEquals(1, captorUnhide.getValue().size());
8686         assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName());
8687     }
8688 
8689     @Test
testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg()8690     public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() {
8691         // Post 2 notifications from 2 packages
8692         NotificationRecord pkgA = new NotificationRecord(mContext,
8693                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
8694         mService.addNotification(pkgA);
8695         NotificationRecord pkgB = new NotificationRecord(mContext,
8696                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
8697         mService.addNotification(pkgB);
8698 
8699         // on broadcast, hide one of the packages
8700         simulatePackageDistractionBroadcast(
8701                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"},
8702                 new int[] {1000, 1001});
8703         ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
8704 
8705         // should be called only once.
8706         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
8707         assertEquals(2, captorHide.getValue().size());
8708         assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
8709         assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName());
8710 
8711         // on broadcast, unhide the package
8712         simulatePackageDistractionBroadcast(
8713                 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"},
8714                 new int[] {1000, 1001});
8715         ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
8716 
8717         // should be called only once.
8718         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
8719         assertEquals(2, captorUnhide.getValue().size());
8720         assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName());
8721         assertEquals("b", captorUnhide.getValue().get(1).getSbn().getPackageName());
8722     }
8723 
8724     @Test
testNoNotificationsHiddenOnDistractingPackageBroadcast()8725     public void testNoNotificationsHiddenOnDistractingPackageBroadcast() {
8726         // post notification from this package
8727         final NotificationRecord notif1 = generateNotificationRecord(
8728                 mTestNotificationChannel, 1, null, true);
8729         mService.addNotification(notif1);
8730 
8731         // on broadcast, nothing is hidden since no notifications are of package "test_package"
8732         simulatePackageDistractionBroadcast(
8733                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"},
8734                 new int[]{notif1.getUid()});
8735         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
8736         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
8737         assertEquals(0, captor.getValue().size());
8738     }
8739 
8740     @Test
testCanUseManagedServicesNullPkg()8741     public void testCanUseManagedServicesNullPkg() {
8742         assertEquals(true, mService.canUseManagedServices(null, 0, null));
8743     }
8744 
8745 
8746     @Test
testCanUseManagedServicesNoValidPkg()8747     public void testCanUseManagedServicesNoValidPkg() {
8748         assertEquals(true, mService.canUseManagedServices("d", 0, null));
8749     }
8750 
8751     @Test
testCanUseManagedServices_hasPermission()8752     public void testCanUseManagedServices_hasPermission() throws Exception {
8753         when(mPackageManager.checkPermission("perm", "pkg", 0))
8754                 .thenReturn(PackageManager.PERMISSION_GRANTED);
8755 
8756         assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm"));
8757     }
8758 
8759     @Test
testCanUseManagedServices_noPermission()8760     public void testCanUseManagedServices_noPermission() throws Exception {
8761         when(mPackageManager.checkPermission("perm", "pkg", 0))
8762                 .thenReturn(PackageManager.PERMISSION_DENIED);
8763 
8764         assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm"));
8765     }
8766 
8767     @Test
testCanUseManagedServices_permDoesNotMatter()8768     public void testCanUseManagedServices_permDoesNotMatter() {
8769         assertEquals(true, mService.canUseManagedServices("pkg", 0, null));
8770     }
8771 
8772     @Test
testOnNotificationVisibilityChanged_triggersInterruptionUsageStat()8773     public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() {
8774         final NotificationRecord r = generateNotificationRecord(
8775                 mTestNotificationChannel, 1, null, true);
8776         r.setTextChanged(true);
8777         mService.addNotification(r);
8778 
8779         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
8780                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
8781                 new NotificationVisibility[]{});
8782 
8783         verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
8784     }
8785 
8786     @Test
testOnNotificationVisibilityChanged_triggersVisibilityLog()8787     public void testOnNotificationVisibilityChanged_triggersVisibilityLog() {
8788         final NotificationRecord r = generateNotificationRecord(
8789                 mTestNotificationChannel, 1, null, true);
8790         r.setTextChanged(true);
8791         r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
8792         mService.addNotification(r);
8793 
8794         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
8795                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
8796                 new NotificationVisibility[]{});
8797 
8798         assertEquals(1, mNotificationRecordLogger.numCalls());
8799         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN,
8800                 mNotificationRecordLogger.event(0));
8801         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
8802 
8803         mService.mNotificationDelegate.onNotificationVisibilityChanged(
8804                 new NotificationVisibility[]{},
8805                 new NotificationVisibility[]
8806                         {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}
8807         );
8808 
8809         assertEquals(2, mNotificationRecordLogger.numCalls());
8810         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE,
8811                 mNotificationRecordLogger.event(1));
8812         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
8813     }
8814 
8815     @Test
testSetNotificationsShownFromListener_triggersInterruptionUsageStat()8816     public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat()
8817             throws RemoteException {
8818         final NotificationRecord r = generateNotificationRecord(
8819                 mTestNotificationChannel, 1, null, true);
8820         r.setTextChanged(true);
8821         mService.addNotification(r);
8822 
8823         mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
8824 
8825         verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
8826     }
8827 
8828     @Test
testSetNotificationsShownFromListener_protectsCrossUserInformation()8829     public void testSetNotificationsShownFromListener_protectsCrossUserInformation()
8830             throws RemoteException {
8831         Notification.Builder nb = new Notification.Builder(
8832                 mContext, mTestNotificationChannel.getId())
8833                 .setContentTitle("foo")
8834                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8835         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
8836                 "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
8837                 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
8838                 null, 0);
8839         final NotificationRecord r =
8840                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8841         r.setTextChanged(true);
8842         mService.addNotification(r);
8843 
8844         // no security exception!
8845         mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
8846 
8847         verify(mAppUsageStats, never()).reportInterruptiveNotification(
8848                 anyString(), anyString(), anyInt());
8849     }
8850 
8851     @Test
testCancelNotificationsFromListener_protectsCrossUserInformation()8852     public void testCancelNotificationsFromListener_protectsCrossUserInformation()
8853             throws RemoteException {
8854         Notification.Builder nb = new Notification.Builder(
8855                 mContext, mTestNotificationChannel.getId())
8856                 .setContentTitle("foo")
8857                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8858         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
8859                 "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
8860                 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
8861                 null, 0);
8862         final NotificationRecord r =
8863                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8864         r.setTextChanged(true);
8865         mService.addNotification(r);
8866 
8867         // no security exception!
8868         mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()});
8869 
8870         waitForIdle();
8871         assertEquals(1, mService.getNotificationRecordCount());
8872     }
8873 
8874     @Test
testMaybeRecordInterruptionLocked_doesNotRecordTwice()8875     public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
8876             throws RemoteException {
8877         final NotificationRecord r = generateNotificationRecord(
8878                 mTestNotificationChannel, 1, null, true);
8879         r.setInterruptive(true);
8880         mService.addNotification(r);
8881 
8882         mService.maybeRecordInterruptionLocked(r);
8883         mService.maybeRecordInterruptionLocked(r);
8884 
8885         verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
8886                 anyString(), anyString(), anyInt());
8887         verify(mHistoryManager, times(1)).addNotification(any());
8888     }
8889 
8890     @Test
testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()8891     public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()
8892             throws RemoteException {
8893         final NotificationRecord r = generateNotificationRecord(
8894                 mTestNotificationChannel, 1, null, true);
8895         r.setInterruptive(true);
8896         r.getSbn().getNotification().setSmallIcon(null);
8897         mService.addNotification(r);
8898 
8899         mService.maybeRecordInterruptionLocked(r);
8900 
8901         verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
8902                 anyString(), anyString(), anyInt());
8903         verify(mHistoryManager, never()).addNotification(any());
8904     }
8905 
8906     @Test
testBubble()8907     public void testBubble() throws Exception {
8908         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE);
8909         assertFalse(mBinderService.areBubblesAllowed(mPkg));
8910         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
8911                 BUBBLE_PREFERENCE_NONE);
8912     }
8913 
8914     @Test
testUserApprovedBubblesForPackageSelected()8915     public void testUserApprovedBubblesForPackageSelected() throws Exception {
8916         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_SELECTED);
8917         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
8918                 BUBBLE_PREFERENCE_SELECTED);
8919     }
8920 
8921     @Test
testUserApprovedBubblesForPackageAll()8922     public void testUserApprovedBubblesForPackageAll() throws Exception {
8923         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_ALL);
8924         assertTrue(mBinderService.areBubblesAllowed(mPkg));
8925         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
8926                 BUBBLE_PREFERENCE_ALL);
8927     }
8928 
8929     @Test
testUserRejectsBubblesForPackage()8930     public void testUserRejectsBubblesForPackage() throws Exception {
8931         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE);
8932         assertFalse(mBinderService.areBubblesAllowed(mPkg));
8933     }
8934 
8935     @Test
testAreBubblesEnabled()8936     public void testAreBubblesEnabled() throws Exception {
8937         Settings.Secure.putInt(mContext.getContentResolver(),
8938                 Settings.Secure.NOTIFICATION_BUBBLES, 1);
8939         mService.mPreferencesHelper.updateBubblesEnabled();
8940         assertTrue(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
8941     }
8942 
8943     @Test
testAreBubblesEnabled_false()8944     public void testAreBubblesEnabled_false() throws Exception {
8945         Settings.Secure.putIntForUser(mContext.getContentResolver(),
8946                 Settings.Secure.NOTIFICATION_BUBBLES, 0, UserHandle.getUserId(mUid));
8947         mService.mPreferencesHelper.updateBubblesEnabled();
8948         assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
8949     }
8950 
8951     @Test
testAreBubblesEnabled_exception()8952     public void testAreBubblesEnabled_exception() throws Exception {
8953         try {
8954             assertTrue(mBinderService.areBubblesEnabled(
8955                     UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE)));
8956             fail("Cannot call cross user without permission");
8957         } catch (SecurityException e) {
8958             // pass
8959         }
8960         // cross user, with permission, no problem
8961         enableInteractAcrossUsers();
8962         assertTrue(mBinderService.areBubblesEnabled(
8963                 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE)));
8964     }
8965 
8966     @Test
testIsCallerInstantApp_primaryUser()8967     public void testIsCallerInstantApp_primaryUser() throws Exception {
8968         ApplicationInfo info = new ApplicationInfo();
8969         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
8970         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
8971         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
8972 
8973         assertTrue(mService.isCallerInstantApp(45770, 0));
8974 
8975         info.privateFlags = 0;
8976         assertFalse(mService.isCallerInstantApp(575370, 0));
8977     }
8978 
8979     @Test
testIsCallerInstantApp_secondaryUser()8980     public void testIsCallerInstantApp_secondaryUser() throws Exception {
8981         ApplicationInfo info = new ApplicationInfo();
8982         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
8983         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
8984         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
8985         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
8986 
8987         assertTrue(mService.isCallerInstantApp(68638450, 10));
8988     }
8989 
8990     @Test
testIsCallerInstantApp_userAllNotification()8991     public void testIsCallerInstantApp_userAllNotification() throws Exception {
8992         ApplicationInfo info = new ApplicationInfo();
8993         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
8994         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM)))
8995                 .thenReturn(info);
8996         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
8997 
8998         assertTrue(mService.isCallerInstantApp(45770, UserHandle.USER_ALL));
8999 
9000         info.privateFlags = 0;
9001         assertFalse(mService.isCallerInstantApp(575370, UserHandle.USER_ALL ));
9002     }
9003 
9004     @Test
testResolveNotificationUid_sameApp_nonSystemUser()9005     public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception {
9006         ApplicationInfo info = new ApplicationInfo();
9007         info.uid = Binder.getCallingUid();
9008         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
9009         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
9010 
9011         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10);
9012 
9013         assertEquals(info.uid, actualUid);
9014     }
9015 
9016     @Test
testResolveNotificationUid_sameApp()9017     public void testResolveNotificationUid_sameApp() throws Exception {
9018         ApplicationInfo info = new ApplicationInfo();
9019         info.uid = Binder.getCallingUid();
9020         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
9021 
9022         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
9023 
9024         assertEquals(info.uid, actualUid);
9025     }
9026 
9027     @Test
testResolveNotificationUid_sameAppDiffPackage()9028     public void testResolveNotificationUid_sameAppDiffPackage() throws Exception {
9029         ApplicationInfo info = new ApplicationInfo();
9030         info.uid = Binder.getCallingUid();
9031         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
9032 
9033         int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0);
9034 
9035         assertEquals(info.uid, actualUid);
9036     }
9037 
9038     @Test
testResolveNotificationUid_sameAppWrongUid()9039     public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
9040         ApplicationInfo info = new ApplicationInfo();
9041         info.uid = 1356347;
9042         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info);
9043 
9044         try {
9045             mService.resolveNotificationUid("caller", "caller", 9, 0);
9046             fail("Incorrect uid didn't throw security exception");
9047         } catch (SecurityException e) {
9048             // yay
9049         }
9050     }
9051 
9052     @Test
testResolveNotificationUid_delegateAllowed()9053     public void testResolveNotificationUid_delegateAllowed() throws Exception {
9054         int expectedUid = 123;
9055 
9056         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
9057         mService.setPreferencesHelper(mPreferencesHelper);
9058         when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt()))
9059                 .thenReturn(true);
9060 
9061         assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0));
9062     }
9063 
9064     @Test
testResolveNotificationUid_androidAllowed()9065     public void testResolveNotificationUid_androidAllowed() throws Exception {
9066         int expectedUid = 123;
9067 
9068         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
9069         // no delegate
9070 
9071         assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0));
9072     }
9073 
9074     @Test
testPostFromAndroidForNonExistentPackage()9075     public void testPostFromAndroidForNonExistentPackage() throws Exception {
9076         final String notReal = "NOT REAL";
9077         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow(
9078                 PackageManager.NameNotFoundException.class);
9079         ApplicationInfo ai = new ApplicationInfo();
9080         ai.uid = -1;
9081         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
9082 
9083         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
9084         try {
9085             mInternalService.enqueueNotification(notReal, "android", 0, 0,
9086                     "testPostFromAndroidForNonExistentPackage",
9087                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
9088             fail("can't post notifications for nonexistent packages, even if you exist");
9089         } catch (SecurityException e) {
9090             // yay
9091         }
9092     }
9093 
9094     @Test
testCancelFromAndroidForNonExistentPackage()9095     public void testCancelFromAndroidForNonExistentPackage() throws Exception {
9096         final String notReal = "NOT REAL";
9097         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
9098                 PackageManager.NameNotFoundException.class);
9099         ApplicationInfo ai = new ApplicationInfo();
9100         ai.uid = -1;
9101         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
9102 
9103         // unlike the post case, ignore instead of throwing
9104         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
9105 
9106         mInternalService.cancelNotification(notReal, "android", 0, 0, "tag",
9107                 sbn.getId(), sbn.getUserId());
9108     }
9109 
9110     @Test
testResolveNotificationUid_delegateNotAllowed()9111     public void testResolveNotificationUid_delegateNotAllowed() throws Exception {
9112         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123);
9113         // no delegate
9114 
9115         try {
9116             mService.resolveNotificationUid("caller", "target", 9, 0);
9117             fail("Incorrect uid didn't throw security exception");
9118         } catch (SecurityException e) {
9119             // yay
9120         }
9121     }
9122 
9123     @Test
testRemoveForegroundServiceFlagFromNotification_enqueued()9124     public void testRemoveForegroundServiceFlagFromNotification_enqueued() {
9125         when(mAmi.applyForegroundServiceNotification(
9126                 any(), anyString(), anyInt(), anyString(), anyInt()))
9127                 .thenReturn(SHOW_IMMEDIATELY);
9128         Notification n = new Notification.Builder(mContext, "").build();
9129         n.flags |= FLAG_FOREGROUND_SERVICE;
9130 
9131         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
9132                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9133         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9134 
9135         mService.addEnqueuedNotification(r);
9136 
9137         mInternalService.removeForegroundServiceFlagFromNotification(
9138                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9139 
9140         waitForIdle();
9141 
9142         verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
9143     }
9144 
9145     @Test
testRemoveForegroundServiceFlagFromNotification_posted()9146     public void testRemoveForegroundServiceFlagFromNotification_posted() {
9147         when(mAmi.applyForegroundServiceNotification(
9148                 any(), anyString(), anyInt(), anyString(), anyInt()))
9149                 .thenReturn(SHOW_IMMEDIATELY);
9150         Notification n = new Notification.Builder(mContext, "").build();
9151         n.flags |= FLAG_FOREGROUND_SERVICE;
9152 
9153         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
9154                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9155         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9156 
9157         mService.addNotification(r);
9158 
9159         mInternalService.removeForegroundServiceFlagFromNotification(
9160                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9161 
9162         waitForIdle();
9163 
9164         ArgumentCaptor<NotificationRecord> captor =
9165                 ArgumentCaptor.forClass(NotificationRecord.class);
9166         verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
9167 
9168         assertEquals(0, captor.getValue().getNotification().flags);
9169     }
9170 
9171     @Test
testCannotRemoveForegroundFlagWhenOverLimit_enqueued()9172     public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() {
9173         when(mAmi.applyForegroundServiceNotification(
9174                 any(), anyString(), anyInt(), anyString(), anyInt()))
9175                 .thenReturn(SHOW_IMMEDIATELY);
9176         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
9177             Notification n = new Notification.Builder(mContext, "").build();
9178             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
9179                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
9180             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9181             mService.addEnqueuedNotification(r);
9182         }
9183         Notification n = new Notification.Builder(mContext, "").build();
9184         n.flags |= FLAG_FOREGROUND_SERVICE;
9185 
9186         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
9187                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
9188                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9189         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9190 
9191         mService.addEnqueuedNotification(r);
9192 
9193         mInternalService.removeForegroundServiceFlagFromNotification(
9194                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9195 
9196         waitForIdle();
9197 
9198         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
9199                 mService.getNotificationRecordCount());
9200     }
9201 
9202     @Test
testCannotRemoveForegroundFlagWhenOverLimit_posted()9203     public void testCannotRemoveForegroundFlagWhenOverLimit_posted() {
9204         when(mAmi.applyForegroundServiceNotification(
9205                 any(), anyString(), anyInt(), anyString(), anyInt()))
9206                 .thenReturn(SHOW_IMMEDIATELY);
9207         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
9208             Notification n = new Notification.Builder(mContext, "").build();
9209             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
9210                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
9211             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9212             mService.addNotification(r);
9213         }
9214         Notification n = new Notification.Builder(mContext, "").build();
9215         n.flags |= FLAG_FOREGROUND_SERVICE;
9216 
9217         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
9218                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
9219                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9220         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9221 
9222         mService.addNotification(r);
9223 
9224         mInternalService.removeForegroundServiceFlagFromNotification(
9225                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9226 
9227         waitForIdle();
9228 
9229         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
9230                 mService.getNotificationRecordCount());
9231     }
9232 
9233     @Test
testAllowForegroundCustomToasts()9234     public void testAllowForegroundCustomToasts() throws Exception {
9235         final String testPackage = "testPackageName";
9236         assertEquals(0, mService.mToastQueue.size());
9237         mService.isSystemUid = false;
9238         mService.isSystemAppId = false;
9239         setToastRateIsWithinQuota(true);
9240         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9241 
9242         // package is not suspended
9243         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9244                 .thenReturn(false);
9245 
9246         // notifications from this package are blocked by the user
9247         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
9248 
9249         setAppInForegroundForToasts(mUid, true);
9250 
9251         // enqueue toast -> toast should still enqueue
9252         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9253         assertEquals(1, mService.mToastQueue.size());
9254         assertThat(wasEnqueued).isTrue();
9255     }
9256 
9257     @Test
testDisallowBackgroundCustomToasts()9258     public void testDisallowBackgroundCustomToasts() throws Exception {
9259         final String testPackage = "testPackageName";
9260         assertEquals(0, mService.mToastQueue.size());
9261         mService.isSystemUid = false;
9262         mService.isSystemAppId = false;
9263         setToastRateIsWithinQuota(true);
9264         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9265 
9266         // package is not suspended
9267         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9268                 .thenReturn(false);
9269 
9270         setAppInForegroundForToasts(mUid, false);
9271 
9272         // enqueue toast -> no toasts enqueued
9273         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9274         assertEquals(0, mService.mToastQueue.size());
9275         assertThat(wasEnqueued).isFalse();
9276     }
9277 
9278     @Test
testDontCallShowToastAgainOnTheSameCustomToast()9279     public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception {
9280         final String testPackage = "testPackageName";
9281         assertEquals(0, mService.mToastQueue.size());
9282         mService.isSystemUid = false;
9283         mService.isSystemAppId = false;
9284         setToastRateIsWithinQuota(true);
9285         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9286 
9287         // package is not suspended
9288         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9289                 .thenReturn(false);
9290 
9291         setAppInForegroundForToasts(mUid, true);
9292 
9293         Binder token = new Binder();
9294         ITransientNotification callback = mock(ITransientNotification.class);
9295         INotificationManager nmService = (INotificationManager) mService.mService;
9296 
9297         // first time trying to show the toast, showToast gets called
9298         enqueueToast(nmService, testPackage, token, callback);
9299         verify(callback, times(1)).show(any());
9300 
9301         // second time trying to show the same toast, showToast isn't called again (total number of
9302         // invocations stays at one)
9303         enqueueToast(nmService, testPackage, token, callback);
9304         verify(callback, times(1)).show(any());
9305     }
9306 
9307     @Test
testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()9308     public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()
9309             throws Exception {
9310         final String testPackage = "testPackageName";
9311         assertEquals(0, mService.mToastQueue.size());
9312         mService.isSystemUid = false;
9313         mService.isSystemAppId = false;
9314         setToastRateIsWithinQuota(false); // rate limit reached
9315         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9316 
9317         // package is not suspended
9318         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9319                 .thenReturn(false);
9320 
9321         setAppInForegroundForToasts(mUid, true);
9322 
9323         Binder token = new Binder();
9324         ITransientNotification callback = mock(ITransientNotification.class);
9325         INotificationManager nmService = (INotificationManager) mService.mService;
9326 
9327         enqueueToast(nmService, testPackage, token, callback);
9328         verify(callback, times(1)).show(any());
9329     }
9330 
9331     @Test
testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()9332     public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()
9333             throws Exception {
9334         final String testPackage = "testPackageName";
9335         assertEquals(0, mService.mToastQueue.size());
9336         mService.isSystemUid = false;
9337         mService.isSystemAppId = false;
9338         setToastRateIsWithinQuota(true);
9339         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9340 
9341         // package is not suspended
9342         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9343                 .thenReturn(false);
9344 
9345         setAppInForegroundForToasts(mUid, true);
9346 
9347         Binder token1 = new Binder();
9348         Binder token2 = new Binder();
9349         ITransientNotification callback1 = mock(ITransientNotification.class);
9350         ITransientNotification callback2 = mock(ITransientNotification.class);
9351         INotificationManager nmService = (INotificationManager) mService.mService;
9352 
9353         enqueueToast(nmService, testPackage, token1, callback1);
9354         enqueueToast(nmService, testPackage, token2, callback2);
9355 
9356         assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued.
9357         verify(callback1, times(1)).show(any()); // First toast shown.
9358 
9359         setAppInForegroundForToasts(mUid, false);
9360 
9361         mService.cancelToastLocked(0); // Remove the first toast, and show next.
9362 
9363         assertEquals(0, mService.mToastQueue.size()); // Both toasts processed.
9364         verify(callback2, never()).show(any()); // Second toast was never shown.
9365     }
9366 
9367     @Test
testAllowForegroundTextToasts()9368     public void testAllowForegroundTextToasts() throws Exception {
9369         final String testPackage = "testPackageName";
9370         assertEquals(0, mService.mToastQueue.size());
9371         mService.isSystemUid = false;
9372         mService.isSystemAppId = false;
9373         setToastRateIsWithinQuota(true);
9374         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9375 
9376         // package is not suspended
9377         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9378                 .thenReturn(false);
9379 
9380         setAppInForegroundForToasts(mUid, true);
9381 
9382         // enqueue toast -> toast should still enqueue
9383         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9384         assertEquals(1, mService.mToastQueue.size());
9385         assertThat(wasEnqueued).isTrue();
9386     }
9387 
9388     @Test
testAllowBackgroundTextToasts()9389     public void testAllowBackgroundTextToasts() throws Exception {
9390         final String testPackage = "testPackageName";
9391         assertEquals(0, mService.mToastQueue.size());
9392         mService.isSystemUid = false;
9393         mService.isSystemAppId = false;
9394         setToastRateIsWithinQuota(true);
9395         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9396 
9397         // package is not suspended
9398         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9399                 .thenReturn(false);
9400 
9401         setAppInForegroundForToasts(mUid, false);
9402 
9403         // enqueue toast -> toast should still enqueue
9404         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9405         assertEquals(1, mService.mToastQueue.size());
9406         assertThat(wasEnqueued).isTrue();
9407     }
9408 
9409     @Test
testDontCallShowToastAgainOnTheSameTextToast()9410     public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception {
9411         final String testPackage = "testPackageName";
9412         assertEquals(0, mService.mToastQueue.size());
9413         mService.isSystemUid = false;
9414         mService.isSystemAppId = false;
9415         setToastRateIsWithinQuota(true);
9416         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9417 
9418         // package is not suspended
9419         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9420                 .thenReturn(false);
9421 
9422         setAppInForegroundForToasts(mUid, true);
9423 
9424         Binder token = new Binder();
9425         INotificationManager nmService = (INotificationManager) mService.mService;
9426 
9427         // first time trying to show the toast, showToast gets called
9428         enqueueTextToast(testPackage, "Text");
9429         verify(mStatusBar, times(1))
9430                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9431 
9432         // second time trying to show the same toast, showToast isn't called again (total number of
9433         // invocations stays at one)
9434         enqueueTextToast(testPackage, "Text");
9435         verify(mStatusBar, times(1))
9436                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9437     }
9438 
9439     @Test
testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()9440     public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()
9441             throws Exception {
9442         final String testPackage = "testPackageName";
9443         assertEquals(0, mService.mToastQueue.size());
9444         mService.isSystemUid = false;
9445         mService.isSystemAppId = false;
9446         setToastRateIsWithinQuota(false); // rate limit reached
9447         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9448         setAppInForegroundForToasts(mUid, false);
9449 
9450         // package is not suspended
9451         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9452                 .thenReturn(false);
9453 
9454         Binder token = new Binder();
9455         INotificationManager nmService = (INotificationManager) mService.mService;
9456 
9457         enqueueTextToast(testPackage, "Text");
9458         verify(mStatusBar, times(0))
9459                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9460     }
9461 
9462     @Test
testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()9463     public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()
9464             throws Exception {
9465         final String testPackage = "testPackageName";
9466         assertEquals(0, mService.mToastQueue.size());
9467         mService.isSystemUid = false;
9468         mService.isSystemAppId = false;
9469         setToastRateIsWithinQuota(false); // rate limit reached
9470         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9471         setAppInForegroundForToasts(mUid, true);
9472 
9473         // package is not suspended
9474         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9475                 .thenReturn(false);
9476 
9477         Binder token = new Binder();
9478         INotificationManager nmService = (INotificationManager) mService.mService;
9479 
9480         enqueueTextToast(testPackage, "Text");
9481         verify(mStatusBar, times(1))
9482                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9483     }
9484 
9485     @Test
testTextToastRateLimiterAllowsLimitAvoidanceWithPermission()9486     public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception {
9487         final String testPackage = "testPackageName";
9488         assertEquals(0, mService.mToastQueue.size());
9489         mService.isSystemUid = false;
9490         mService.isSystemAppId = false;
9491         setToastRateIsWithinQuota(false); // rate limit reached
9492         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true);
9493         setAppInForegroundForToasts(mUid, false);
9494 
9495         // package is not suspended
9496         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9497                 .thenReturn(false);
9498 
9499         Binder token = new Binder();
9500         INotificationManager nmService = (INotificationManager) mService.mService;
9501 
9502         enqueueTextToast(testPackage, "Text");
9503         verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
9504                 anyInt());
9505     }
9506 
9507     @Test
testRateLimitedToasts_windowsRemoved()9508     public void testRateLimitedToasts_windowsRemoved() throws Exception {
9509         final String testPackage = "testPackageName";
9510         assertEquals(0, mService.mToastQueue.size());
9511         mService.isSystemUid = false;
9512         mService.isSystemAppId = false;
9513         setToastRateIsWithinQuota(false); // rate limit reached
9514         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9515         setAppInForegroundForToasts(mUid, false);
9516 
9517         // package is not suspended
9518         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9519                 .thenReturn(false);
9520 
9521         Binder token = new Binder();
9522         INotificationManager nmService = (INotificationManager) mService.mService;
9523 
9524         enqueueTextToast(testPackage, "Text");
9525 
9526         // window token was added when enqueued
9527         ArgumentCaptor<Binder> binderCaptor =
9528                 ArgumentCaptor.forClass(Binder.class);
9529         verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(),
9530                 eq(TYPE_TOAST), anyInt(), eq(null));
9531 
9532         // but never shown
9533         verify(mStatusBar, times(0))
9534                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9535 
9536         // and removed when rate limited
9537         verify(mWindowManagerInternal)
9538                 .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt());
9539     }
9540 
9541     @Test
backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast()9542     public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
9543             Exception {
9544         final String testPackage = "testPackageName";
9545         assertEquals(0, mService.mToastQueue.size());
9546         mService.isSystemUid = true;
9547         setToastRateIsWithinQuota(true);
9548         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9549 
9550         // package is not suspended
9551         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9552                 .thenReturn(false);
9553 
9554         // notifications from this package are blocked by the user
9555         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
9556 
9557         setAppInForegroundForToasts(mUid, false);
9558 
9559         // enqueue toast -> toast should still enqueue
9560         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9561         assertEquals(1, mService.mToastQueue.size());
9562         assertThat(wasEnqueued).isTrue();
9563         verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any());
9564     }
9565 
9566     @Test
foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9567     public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws
9568             Exception {
9569         final String testPackage = "testPackageName";
9570         assertEquals(0, mService.mToastQueue.size());
9571         mService.isSystemUid = false;
9572         mService.isSystemAppId = false;
9573         setToastRateIsWithinQuota(true);
9574         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9575 
9576         // package is not suspended
9577         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9578                 .thenReturn(false);
9579 
9580         setAppInForegroundForToasts(mUid, true);
9581 
9582         // enqueue toast -> toast should still enqueue
9583         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9584         assertEquals(1, mService.mToastQueue.size());
9585         assertThat(wasEnqueued).isTrue();
9586         verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());
9587     }
9588 
9589     @Test
backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9590     public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws
9591             Exception {
9592         final String testPackage = "testPackageName";
9593         assertEquals(0, mService.mToastQueue.size());
9594         mService.isSystemUid = false;
9595         mService.isSystemAppId = false;
9596         setToastRateIsWithinQuota(true);
9597         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9598 
9599         // package is not suspended
9600         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9601                 .thenReturn(false);
9602 
9603         setAppInForegroundForToasts(mUid, false);
9604 
9605         // enqueue toast -> toast should still enqueue
9606         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9607         assertEquals(1, mService.mToastQueue.size());
9608         assertThat(wasEnqueued).isTrue();
9609         verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());
9610     }
9611 
9612     @Test
testTextToastsCallStatusBar()9613     public void testTextToastsCallStatusBar() throws Exception {
9614         allowTestPackageToToast();
9615 
9616         // enqueue toast -> no toasts enqueued
9617         boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text");
9618         assertThat(wasEnqueued).isTrue();
9619 
9620         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
9621     }
9622 
9623     @Test
testTextToastsCallStatusBar_nonUiContext_defaultDisplay()9624     public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay()
9625             throws Exception {
9626         allowTestPackageToToast();
9627 
9628         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY);
9629 
9630         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
9631     }
9632 
9633     @Test
testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()9634     public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()
9635             throws Exception {
9636         allowTestPackageToToast();
9637         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9638 
9639         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID);
9640 
9641         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9642     }
9643 
9644     @Test
testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()9645     public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()
9646             throws Exception {
9647         mockIsVisibleBackgroundUsersSupported(true);
9648         mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID);
9649         allowTestPackageToToast();
9650 
9651         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY);
9652 
9653         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
9654 
9655     }
9656 
9657     @Test
testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()9658     public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()
9659             throws Exception {
9660         mockIsVisibleBackgroundUsersSupported(true);
9661         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9662         mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used
9663         allowTestPackageToToast();
9664 
9665         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID);
9666 
9667         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9668     }
9669 
9670     @Test
testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()9671     public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()
9672             throws Exception {
9673         mockIsVisibleBackgroundUsersSupported(true);
9674         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9675         mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID);
9676         allowTestPackageToToast();
9677 
9678         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY);
9679 
9680         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9681     }
9682 
9683     @Test
testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()9684     public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()
9685             throws Exception {
9686         mockIsVisibleBackgroundUsersSupported(true);
9687         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9688         mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used
9689         allowTestPackageToToast();
9690 
9691         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID);
9692 
9693         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9694     }
9695 
9696     @Test
testTextToastsCallStatusBar_userNotVisibleOnDisplay()9697     public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception {
9698         final String testPackage = "testPackageName";
9699         assertEquals(0, mService.mToastQueue.size());
9700         mService.isSystemUid = false;
9701         mService.isSystemAppId = false;
9702         setToastRateIsWithinQuota(true);
9703         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9704         mockIsUserVisible(DEFAULT_DISPLAY, false);
9705 
9706         // package is not suspended
9707         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
9708                 .thenReturn(false);
9709 
9710         // enqueue toast -> no toasts enqueued
9711         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9712         verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
9713                 anyInt());
9714         assertEquals(0, mService.mToastQueue.size());
9715         assertThat(wasEnqueued).isFalse();
9716     }
9717 
9718     @Test
testDisallowToastsFromSuspendedPackages()9719     public void testDisallowToastsFromSuspendedPackages() throws Exception {
9720         final String testPackage = "testPackageName";
9721         assertEquals(0, mService.mToastQueue.size());
9722         mService.isSystemUid = false;
9723         mService.isSystemAppId = false;
9724         setToastRateIsWithinQuota(true);
9725         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9726 
9727         // package is suspended
9728         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9729                 .thenReturn(true);
9730 
9731         // notifications from this package are NOT blocked by the user
9732         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
9733 
9734         // enqueue toast -> no toasts enqueued
9735         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9736         verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
9737                 anyInt());
9738         assertEquals(0, mService.mToastQueue.size());
9739         assertThat(wasEnqueued).isFalse();
9740     }
9741 
9742     @Test
testDisallowToastsFromBlockedApps()9743     public void testDisallowToastsFromBlockedApps() throws Exception {
9744         final String testPackage = "testPackageName";
9745         assertEquals(0, mService.mToastQueue.size());
9746         mService.isSystemUid = false;
9747         mService.isSystemAppId = false;
9748         setToastRateIsWithinQuota(true);
9749         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9750 
9751         // package is not suspended
9752         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9753                 .thenReturn(false);
9754 
9755         // notifications from this package are blocked by the user
9756         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
9757 
9758         setAppInForegroundForToasts(mUid, false);
9759 
9760         // enqueue toast -> no toasts enqueued
9761         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9762         assertEquals(0, mService.mToastQueue.size());
9763         assertThat(wasEnqueued).isFalse();
9764     }
9765 
9766     @Test
testAlwaysAllowSystemToasts()9767     public void testAlwaysAllowSystemToasts() throws Exception {
9768         final String testPackage = "testPackageName";
9769         assertEquals(0, mService.mToastQueue.size());
9770         mService.isSystemUid = true;
9771         setToastRateIsWithinQuota(true);
9772         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9773 
9774         // package is suspended
9775         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9776                 .thenReturn(true);
9777 
9778         // notifications from this package ARE blocked by the user
9779         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
9780 
9781         setAppInForegroundForToasts(mUid, false);
9782 
9783         // enqueue toast -> system toast can still be enqueued
9784         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9785         assertEquals(1, mService.mToastQueue.size());
9786         assertThat(wasEnqueued).isTrue();
9787     }
9788 
9789     @Test
testLimitNumberOfQueuedToastsFromPackage()9790     public void testLimitNumberOfQueuedToastsFromPackage() throws Exception {
9791         final String testPackage = "testPackageName";
9792         assertEquals(0, mService.mToastQueue.size());
9793         mService.isSystemUid = false;
9794         mService.isSystemAppId = false;
9795         setToastRateIsWithinQuota(true);
9796         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9797 
9798         // package is not suspended
9799         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9800                 .thenReturn(false);
9801 
9802         INotificationManager nmService = (INotificationManager) mService.mService;
9803 
9804         // Trying to quickly enqueue more toast than allowed.
9805         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) {
9806             boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9807             if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) {
9808                 assertThat(wasEnqueued).isTrue();
9809             } else {
9810                 assertThat(wasEnqueued).isFalse();
9811             }
9812         }
9813         // Only allowed number enqueued, rest ignored.
9814         assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size());
9815     }
9816 
9817     @Test
testPrioritizeSystemToasts()9818     public void testPrioritizeSystemToasts() throws Exception {
9819         // Insert non-system toasts
9820         final String testPackage = "testPackageName";
9821         assertEquals(0, mService.mToastQueue.size());
9822         mService.isSystemUid = false;
9823         mService.isSystemAppId = false;
9824         setToastRateIsWithinQuota(true);
9825         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9826 
9827         // package is not suspended
9828         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9829                 .thenReturn(false);
9830 
9831         INotificationManager nmService = (INotificationManager) mService.mService;
9832 
9833         // Enqueue maximum number of toasts for test package
9834         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
9835             enqueueTextToast(testPackage, "Text");
9836         }
9837 
9838         // Enqueue system toast
9839         final String testPackageSystem = "testPackageNameSystem";
9840         mService.isSystemUid = true;
9841         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false);
9842         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, mUserId))
9843                 .thenReturn(false);
9844 
9845         enqueueToast(testPackageSystem, new TestableToastCallback());
9846 
9847         // System toast is inserted at the front of the queue, behind current showing toast
9848         assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg);
9849     }
9850 
9851     @Test
testPrioritizeSystemToasts_enqueueAfterExistingSystemToast()9852     public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception {
9853         // Insert system toasts
9854         final String testPackageSystem1 = "testPackageNameSystem1";
9855         assertEquals(0, mService.mToastQueue.size());
9856         mService.isSystemUid = true;
9857         setToastRateIsWithinQuota(true);
9858         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false);
9859 
9860         // package is not suspended
9861         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, mUserId))
9862                 .thenReturn(false);
9863 
9864         INotificationManager nmService = (INotificationManager) mService.mService;
9865 
9866         // Enqueue maximum number of toasts for test package
9867         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
9868             enqueueTextToast(testPackageSystem1, "Text");
9869         }
9870 
9871         // Enqueue another system toast
9872         final String testPackageSystem2 = "testPackageNameSystem2";
9873         mService.isSystemUid = true;
9874         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false);
9875         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, mUserId))
9876                 .thenReturn(false);
9877 
9878         enqueueToast(testPackageSystem2, new TestableToastCallback());
9879 
9880         // System toast is inserted at the back of the queue, after the other system toasts
9881         assertEquals(testPackageSystem2,
9882                 mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg);
9883     }
9884 
setAppInForegroundForToasts(int uid, boolean inForeground)9885     private void setAppInForegroundForToasts(int uid, boolean inForeground) {
9886         int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE;
9887         when(mActivityManager.getUidImportance(mUid)).thenReturn(importance);
9888         when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground);
9889     }
9890 
setToastRateIsWithinQuota(boolean isWithinQuota)9891     private void setToastRateIsWithinQuota(boolean isWithinQuota) {
9892         when(mToastRateLimiter.isWithinQuota(
9893                 anyInt(),
9894                 anyString(),
9895                 eq(NotificationManagerService.TOAST_QUOTA_TAG)))
9896                 .thenReturn(isWithinQuota);
9897     }
9898 
setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission)9899     private void setIfPackageHasPermissionToAvoidToastRateLimiting(
9900             String pkg, boolean hasPermission) throws Exception {
9901         when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS,
9902                 pkg, mUserId))
9903                 .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED);
9904     }
9905 
9906     @Test
testOnPanelRevealedAndHidden()9907     public void testOnPanelRevealedAndHidden() {
9908         int items = 5;
9909         mService.mNotificationDelegate.onPanelRevealed(false, items);
9910         verify(mAssistants, times(1)).onPanelRevealed(eq(items));
9911 
9912         mService.mNotificationDelegate.onPanelHidden();
9913         verify(mAssistants, times(1)).onPanelHidden();
9914 
9915         assertEquals(2, mNotificationRecordLogger.numCalls());
9916         assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN,
9917                 mNotificationRecordLogger.event(0));
9918         assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE,
9919                 mNotificationRecordLogger.event(1));
9920     }
9921 
9922     @Test
9923     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testOnNotificationSmartReplySent()9924     public void testOnNotificationSmartReplySent() {
9925         final int replyIndex = 2;
9926         final String reply = "Hello";
9927         final boolean modifiedBeforeSending = true;
9928         final boolean generatedByAssistant = true;
9929 
9930         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9931         r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
9932         mService.addNotification(r);
9933 
9934         mService.mNotificationDelegate.onNotificationSmartReplySent(
9935                 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
9936                 modifiedBeforeSending);
9937         verify(mAssistants).notifyAssistantSuggestedReplySent(
9938                 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant));
9939         assertEquals(1, mNotificationRecordLogger.numCalls());
9940         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
9941                 mNotificationRecordLogger.event(0));
9942         // Check that r.recordSmartReplied was called.
9943         assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
9944                 .isGreaterThan(0);
9945         assertThat(r.getStats().hasSmartReplied()).isTrue();
9946     }
9947 
9948     @Test
9949     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate()9950     public void testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate() throws Exception {
9951         final int replyIndex = 2;
9952         final String reply = "Hello";
9953         final boolean modifiedBeforeSending = true;
9954 
9955         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9956         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
9957         r.getSbn().getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
9958         r.setSuggestionsGeneratedByAssistant(true);
9959         r.setCanceledAfterLifetimeExtension(true);
9960         r.setPostSilently(true);
9961         mService.addNotification(r);
9962 
9963         mService.mNotificationDelegate.onNotificationSmartReplySent(
9964                 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
9965                 modifiedBeforeSending);
9966         waitForIdle();
9967 
9968         // At the moment prepareNotifyPostedLocked is called on the listeners,
9969         // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial
9970         // values.
9971         doAnswer(
9972                 invocation -> {
9973                     int flags = ((NotificationRecord) invocation.getArgument(0))
9974                             .getSbn().getNotification().flags;
9975                     assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
9976                     boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0))
9977                             .shouldPostSilently();
9978                     assertThat(shouldPostSilently).isTrue();
9979                     return null;
9980                 }
9981         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
9982 
9983         // Checks that a post update is sent.
9984         verify(mWorkerHandler, times(1))
9985                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
9986         ArgumentCaptor<NotificationRecord> captor =
9987                 ArgumentCaptor.forClass(NotificationRecord.class);
9988         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
9989                 anyBoolean());
9990         assertThat(captor.getValue().getNotification().flags
9991                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
9992                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
9993         // Flag was present before, so it's set afterward
9994         assertThat(captor.getValue().getNotification().flags
9995                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
9996         // Should post silently was set before, so it's set afterward.
9997         assertThat(captor.getValue().shouldPostSilently()).isTrue();
9998     }
9999 
10000     @Test
testOnNotificationActionClick()10001     public void testOnNotificationActionClick() {
10002         final int actionIndex = 2;
10003         final Notification.Action action =
10004                 new Notification.Action.Builder(null, "text", mActivityIntent).build();
10005         final boolean generatedByAssistant = false;
10006 
10007         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10008         mService.addNotification(r);
10009 
10010         NotificationVisibility notificationVisibility =
10011                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10012         mService.mNotificationDelegate.onNotificationActionClick(
10013                 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
10014                 generatedByAssistant);
10015         verify(mAssistants).notifyAssistantActionClicked(
10016                 eq(r), eq(action), eq(generatedByAssistant));
10017 
10018         assertEquals(1, mNotificationRecordLogger.numCalls());
10019         assertEquals(
10020                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2,
10021                 mNotificationRecordLogger.event(0));
10022     }
10023 
10024     @Test
10025     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testActionClickLifetimeExtendedCancel()10026     public void testActionClickLifetimeExtendedCancel() throws Exception {
10027         final Notification.Action action =
10028                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
10029                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
10030 
10031         // Creates a notification marked as being lifetime extended.
10032         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10033         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10034         mService.addNotification(r);
10035 
10036         StatusBarNotification[] notifs =
10037                 mBinderService.getActiveNotifications(mPkg);
10038         assertThat(notifs.length).isEqualTo(1);
10039         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10040 
10041         // Call on action click.
10042         NotificationVisibility notificationVisibility =
10043                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10044         mService.mNotificationDelegate.onNotificationActionClick(
10045                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
10046                 /*generatedByAssistant=*/false);
10047 
10048         // Lifetime extended flag persists.
10049         assertThat(r.getSbn().getNotification().flags
10050                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
10051 
10052         mTestableLooper.moveTimeForward(210);
10053         waitForIdle();
10054         verify(mWorkerHandler, times(1))
10055                 .scheduleCancelNotification(
10056                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
10057 
10058         // Check that the cancelation occurred and the notification is gone.
10059         notifs = mBinderService.getActiveNotifications(mPkg);
10060         assertThat(notifs.length).isEqualTo(0);
10061         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
10062     }
10063 
10064     @Test
10065     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testActionClickLifetimeExtendedCancel_PreventByNoDismiss()10066     public void testActionClickLifetimeExtendedCancel_PreventByNoDismiss() throws Exception {
10067         final Notification.Action action =
10068                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
10069                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
10070 
10071         // Creates a notification marked as being lifetime extended.
10072         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10073         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10074         // Make the notification non-dismissable
10075         r.getSbn().getNotification().flags |= FLAG_NO_DISMISS;
10076         mService.addNotification(r);
10077 
10078         StatusBarNotification[] notifs =
10079                 mBinderService.getActiveNotifications(mPkg);
10080         assertThat(notifs.length).isEqualTo(1);
10081         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10082 
10083         // Call on action click.
10084         NotificationVisibility notificationVisibility =
10085                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10086         mService.mNotificationDelegate.onNotificationActionClick(
10087                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
10088                 /*generatedByAssistant=*/false);
10089 
10090         // Lifetime extended flag persists.
10091         assertThat(r.getSbn().getNotification().flags
10092                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
10093 
10094         mTestableLooper.moveTimeForward(210);
10095         waitForIdle();
10096         verify(mWorkerHandler, times(1))
10097                 .scheduleCancelNotification(
10098                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
10099 
10100         // The cancellation is dropped and the notification is still present, with the update.
10101         notifs = mBinderService.getActiveNotifications(mPkg);
10102         assertThat(notifs.length).isEqualTo(1);
10103         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10104     }
10105 
10106     @Test
10107     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testUpdateOnActionClickDropsLifetimeExtendedCancel()10108     public void testUpdateOnActionClickDropsLifetimeExtendedCancel() throws Exception {
10109         final Notification.Action action =
10110                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
10111                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
10112 
10113         // Creates a notification marked as being lifetime extended.
10114         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10115         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10116         mService.addNotification(r);
10117 
10118         StatusBarNotification[] notifs =
10119                 mBinderService.getActiveNotifications(mPkg);
10120         assertThat(notifs.length).isEqualTo(1);
10121         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10122 
10123         // Call on action click.
10124         NotificationVisibility notificationVisibility =
10125                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10126         mService.mNotificationDelegate.onNotificationActionClick(
10127                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
10128                 /*generatedByAssistant=*/false);
10129 
10130         // The "app" sends an update of the notification in response.
10131         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
10132                 r.getSbn().getId(), r.getSbn().getNotification(), r.getSbn().getUserId());
10133 
10134         mTestableLooper.moveTimeForward(210);
10135         waitForIdle();
10136         verify(mWorkerHandler, times(1))
10137                 .scheduleCancelNotification(
10138                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
10139 
10140         // The cancellation is dropped and the notification is still present, with the update.
10141         notifs = mBinderService.getActiveNotifications(mPkg);
10142         assertThat(notifs.length).isEqualTo(1);
10143         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10144     }
10145 
10146     @Test
testOnAssistantNotificationActionClick()10147     public void testOnAssistantNotificationActionClick() {
10148         final int actionIndex = 1;
10149         final Notification.Action action =
10150                 new Notification.Action.Builder(null, "text", mActivityIntent).build();
10151         final boolean generatedByAssistant = true;
10152 
10153         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10154         mService.addNotification(r);
10155 
10156         NotificationVisibility notificationVisibility =
10157                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10158         mService.mNotificationDelegate.onNotificationActionClick(
10159                 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
10160                 generatedByAssistant);
10161         verify(mAssistants).notifyAssistantActionClicked(
10162                 eq(r), eq(action), eq(generatedByAssistant));
10163 
10164         assertEquals(1, mNotificationRecordLogger.numCalls());
10165         assertEquals(
10166                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1,
10167                 mNotificationRecordLogger.event(0));
10168     }
10169 
10170 
10171     @Test
testLogSmartSuggestionsVisible_triggerOnExpandAndVisible()10172     public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() {
10173         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10174         mService.addNotification(r);
10175 
10176         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
10177                 NOTIFICATION_LOCATION_UNKNOWN);
10178         NotificationVisibility[] notificationVisibility = new NotificationVisibility[] {
10179                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
10180         };
10181         mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
10182                 new NotificationVisibility[0]);
10183 
10184         assertEquals(1, mService.countLogSmartSuggestionsVisible);
10185     }
10186 
10187     @Test
testLogSmartSuggestionsVisible_noTriggerOnExpand()10188     public void testLogSmartSuggestionsVisible_noTriggerOnExpand() {
10189         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10190         mService.addNotification(r);
10191 
10192         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
10193                 NOTIFICATION_LOCATION_UNKNOWN);
10194 
10195         assertEquals(0, mService.countLogSmartSuggestionsVisible);
10196     }
10197 
10198     @Test
testLogSmartSuggestionsVisible_noTriggerOnVisible()10199     public void testLogSmartSuggestionsVisible_noTriggerOnVisible() {
10200         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10201         mService.addNotification(r);
10202 
10203         NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{
10204                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
10205         };
10206         mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
10207                 new NotificationVisibility[0]);
10208 
10209         assertEquals(0, mService.countLogSmartSuggestionsVisible);
10210     }
10211 
10212     @Test
testReportSeen_delegated()10213     public void testReportSeen_delegated() {
10214         Notification.Builder nb =
10215                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
10216                         .setContentTitle("foo")
10217                         .setSmallIcon(android.R.drawable.sym_def_app_icon);
10218 
10219         StatusBarNotification sbn = new StatusBarNotification(mPkg, "opPkg", 0, "tag", mUid, 0,
10220                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10221         NotificationRecord r =  new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10222 
10223         mService.reportSeen(r);
10224         verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt());
10225 
10226     }
10227 
10228     @Test
testReportSeen_notDelegated()10229     public void testReportSeen_notDelegated() {
10230         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10231 
10232         mService.reportSeen(r);
10233         verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt());
10234     }
10235 
10236     @Test
testNotificationStats_notificationError()10237     public void testNotificationStats_notificationError() {
10238         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10239         mService.addNotification(r);
10240 
10241         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, r.getSbn().getId(),
10242                 r.getSbn().getTag(), mUid, 0,
10243                 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(),
10244                 UserHandle.getUserHandleForUid(mUid), null, 0);
10245         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10246         mService.addEnqueuedNotification(update);
10247         assertNull(update.getSbn().getNotification().getSmallIcon());
10248 
10249         NotificationManagerService.PostNotificationRunnable runnable =
10250                 mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(),
10251                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
10252         runnable.run();
10253         waitForIdle();
10254 
10255         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
10256         verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture());
10257         assertNotNull(captor.getValue());
10258     }
10259 
10260     @Test
testCanNotifyAsUser_crossUser()10261     public void testCanNotifyAsUser_crossUser() throws Exception {
10262         // same user no problem
10263         mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId());
10264 
10265         // cross user, no permission, problem
10266         try {
10267             mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
10268             fail("Should not be callable cross user without cross user permission");
10269         } catch (SecurityException e) {
10270             // good
10271         }
10272 
10273         // cross user, with permission, no problem
10274         enableInteractAcrossUsers();
10275         mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
10276     }
10277 
10278     @Test
testGetNotificationChannels_crossUser()10279     public void testGetNotificationChannels_crossUser() throws Exception {
10280         // same user no problem
10281         mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
10282 
10283         // cross user, no permission, problem
10284         try {
10285             mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
10286             fail("Should not be callable cross user without cross user permission");
10287         } catch (SecurityException e) {
10288             // good
10289         }
10290 
10291         // cross user, with permission, no problem
10292         enableInteractAcrossUsers();
10293         mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
10294     }
10295 
10296     @Test
setDefaultAssistantForUser_fromConfigXml()10297     public void setDefaultAssistantForUser_fromConfigXml() {
10298         ComponentName xmlConfig = new ComponentName("config", "xml");
10299         ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(xmlConfig));
10300         when(mResources
10301                 .getString(
10302                         com.android.internal.R.string.config_defaultAssistantAccessComponent))
10303                 .thenReturn(xmlConfig.flattenToString());
10304         when(mContext.getResources()).thenReturn(mResources);
10305         when(mAssistants.queryPackageForServices(eq(null), anyInt(), anyInt()))
10306                 .thenReturn(components);
10307         when(mAssistants.getDefaultComponents())
10308                 .thenReturn(components);
10309         mService.setNotificationAssistantAccessGrantedCallback(
10310                 mNotificationAssistantAccessGrantedCallback);
10311 
10312 
10313         mService.setDefaultAssistantForUser(0);
10314 
10315         verify(mNotificationAssistantAccessGrantedCallback)
10316                 .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
10317     }
10318 
10319     @Test
clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne()10320     public void clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne() throws RemoteException {
10321         ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
10322                 generateResetComponentValues();
10323         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners);
10324         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
10325         ComponentName deviceConfig1 = new ComponentName("device", "config1");
10326         ComponentName deviceConfig2 = new ComponentName("device", "config2");
10327         changes.put(true, new ArrayList(Arrays.asList(deviceConfig1, deviceConfig2)));
10328         changes.put(false, new ArrayList());
10329         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes);
10330         mService.getBinderService().clearData("device", 0, false);
10331         verify(mAssistants, times(1))
10332                 .setPackageOrComponentEnabled(
10333                         eq("device/config2"),
10334                         eq(0), eq(true), eq(false));
10335         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
10336                 eq("device"), eq(0), eq(false), eq(true));
10337     }
10338 
10339     @Test
testNASSettingUpgrade_userSetNull()10340     public void testNASSettingUpgrade_userSetNull() throws RemoteException {
10341         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component1");
10342         TestableNotificationManagerService service = spy(mService);
10343         int userId = 11;
10344         setUsers(new int[]{userId});
10345         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
10346         setNASMigrationDone(false, userId);
10347         when(mAssistants.getDefaultFromConfig())
10348                 .thenReturn(newDefaultComponent);
10349         when(mAssistants.getAllowedComponents(anyInt()))
10350                 .thenReturn(new ArrayList<>());
10351         when(mAssistants.hasUserSet(userId)).thenReturn(true);
10352 
10353         service.migrateDefaultNAS();
10354         assertTrue(service.isNASMigrationDone(userId));
10355         verify(mAssistants, times(1)).clearDefaults();
10356     }
10357 
10358     @Test
testNASSettingUpgrade_userSet()10359     public void testNASSettingUpgrade_userSet() throws RemoteException {
10360         ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1");
10361         TestableNotificationManagerService service = spy(mService);
10362         int userId = 11;
10363         setUsers(new int[]{userId});
10364         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
10365         setNASMigrationDone(false, userId);
10366         when(mAssistants.getDefaultFromConfig())
10367                 .thenReturn(defaultComponent);
10368         when(mAssistants.getAllowedComponents(anyInt()))
10369                 .thenReturn(new ArrayList(Arrays.asList(defaultComponent)));
10370         when(mAssistants.hasUserSet(userId)).thenReturn(true);
10371 
10372         service.migrateDefaultNAS();
10373         verify(mAssistants, times(1)).setUserSet(userId, false);
10374         //resetDefaultAssistantsIfNecessary should invoke from readPolicyXml() and migration
10375         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
10376     }
10377 
10378     @Test
testNASSettingUpgrade_multiUser()10379     public void testNASSettingUpgrade_multiUser() throws RemoteException {
10380         ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
10381         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
10382         TestableNotificationManagerService service = spy(mService);
10383         int userId1 = 11;
10384         int userId2 = 12;
10385         setUsers(new int[]{userId1, userId2});
10386         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1});
10387         when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2});
10388 
10389         setNASMigrationDone(false, userId1);
10390         setNASMigrationDone(false, userId2);
10391         when(mAssistants.getDefaultComponents())
10392                 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)));
10393         when(mAssistants.getDefaultFromConfig())
10394                 .thenReturn(newDefaultComponent);
10395         //User1: set different NAS
10396         when(mAssistants.getAllowedComponents(userId1))
10397                 .thenReturn(Arrays.asList(oldDefaultComponent));
10398         //User2: set to none
10399         when(mAssistants.getAllowedComponents(userId2))
10400                 .thenReturn(new ArrayList<>());
10401 
10402         when(mAssistants.hasUserSet(userId1)).thenReturn(true);
10403         when(mAssistants.hasUserSet(userId2)).thenReturn(true);
10404 
10405         service.migrateDefaultNAS();
10406         // user1's setting get reset
10407         verify(mAssistants, times(1)).setUserSet(userId1, false);
10408         verify(mAssistants, times(0)).setUserSet(eq(userId2), anyBoolean());
10409         assertTrue(service.isNASMigrationDone(userId2));
10410 
10411     }
10412 
10413     @Test
testNASSettingUpgrade_multiProfile()10414     public void testNASSettingUpgrade_multiProfile() throws RemoteException {
10415         ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
10416         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
10417         TestableNotificationManagerService service = spy(mService);
10418         int userId1 = 11;
10419         int userId2 = 12; //work profile
10420         setUsers(new int[]{userId1, userId2});
10421         when(mUm.isManagedProfile(userId2)).thenReturn(true);
10422         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2});
10423 
10424         setNASMigrationDone(false, userId1);
10425         setNASMigrationDone(false, userId2);
10426         when(mAssistants.getDefaultComponents())
10427                 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)));
10428         when(mAssistants.getDefaultFromConfig())
10429                 .thenReturn(newDefaultComponent);
10430         //Both profiles: set different NAS
10431         when(mAssistants.getAllowedComponents(userId1))
10432                 .thenReturn(Arrays.asList(oldDefaultComponent));
10433         when(mAssistants.getAllowedComponents(userId2))
10434                 .thenReturn(Arrays.asList(oldDefaultComponent));
10435 
10436         when(mAssistants.hasUserSet(userId1)).thenReturn(true);
10437         when(mAssistants.hasUserSet(userId2)).thenReturn(true);
10438 
10439         service.migrateDefaultNAS();
10440         assertFalse(service.isNASMigrationDone(userId1));
10441         assertFalse(service.isNASMigrationDone(userId2));
10442     }
10443 
10444 
10445 
10446     @Test
testNASSettingUpgrade_clearDataAfterMigrationIsDone()10447     public void testNASSettingUpgrade_clearDataAfterMigrationIsDone() throws RemoteException {
10448         ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component");
10449         TestableNotificationManagerService service = spy(mService);
10450         int userId = 12;
10451         setUsers(new int[]{userId});
10452         when(mAssistants.getDefaultComponents())
10453                 .thenReturn(new ArraySet<>(Arrays.asList(defaultComponent)));
10454         when(mAssistants.hasUserSet(userId)).thenReturn(true);
10455         setNASMigrationDone(true, userId);
10456 
10457         //Test User clear data
10458         ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
10459                 generateResetComponentValues();
10460         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners);
10461         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
10462         changes.put(true, new ArrayList(Arrays.asList(defaultComponent)));
10463         changes.put(false, new ArrayList());
10464         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes);
10465 
10466         //Clear data
10467         service.getBinderService().clearData("package", userId, false);
10468         //Test migrate flow again
10469         service.migrateDefaultNAS();
10470 
10471         //Migration should not happen again
10472         verify(mAssistants, times(0)).setUserSet(userId, false);
10473         verify(mAssistants, times(0)).clearDefaults();
10474         //resetDefaultAssistantsIfNecessary should only invoke once from readPolicyXml()
10475         verify(mAssistants, times(1)).resetDefaultAssistantsIfNecessary();
10476 
10477     }
10478 
setNASMigrationDone(boolean done, int userId)10479     private void setNASMigrationDone(boolean done, int userId) {
10480         Settings.Secure.putIntForUser(mContext.getContentResolver(),
10481                 Settings.Secure.NAS_SETTINGS_UPDATED, done ? 1 : 0, userId);
10482     }
10483 
setUsers(int[] userIds)10484     private void setUsers(int[] userIds) {
10485         List<UserInfo> users = new ArrayList<>();
10486         for (int id: userIds) {
10487             users.add(new UserInfo(id, String.valueOf(id), 0));
10488         }
10489         for (UserInfo user : users) {
10490             when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
10491         }
10492         when(mUm.getUsers()).thenReturn(users);
10493     }
10494 
10495     @Test
clearDefaultListenersPackageShouldEnableIt()10496     public void clearDefaultListenersPackageShouldEnableIt() throws RemoteException {
10497         ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants =
10498                 generateResetComponentValues();
10499         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changedAssistants);
10500         ComponentName deviceConfig = new ComponentName("device", "config");
10501         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
10502         changes.put(true, new ArrayList(Arrays.asList(deviceConfig)));
10503         changes.put(false, new ArrayList());
10504         when(mListeners.resetComponents(anyString(), anyInt()))
10505             .thenReturn(changes);
10506         mService.getBinderService().clearData("device", 0, false);
10507         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
10508                 eq("device"), eq(0), eq(false), eq(true));
10509     }
10510 
10511     @Test
clearDefaultDnDPackageShouldEnableIt()10512     public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException {
10513         ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues();
10514         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed);
10515         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed);
10516         mService.getBinderService().clearData("pkgName", 0, false);
10517         verify(mConditionProviders, times(1)).resetPackage(
10518                         eq("pkgName"), eq(0));
10519     }
10520 
10521     @Test
testFlagBubble()10522     public void testFlagBubble() throws RemoteException {
10523         setUpPrefsForBubbles(mPkg, mUid,
10524                 true /* global */,
10525                 BUBBLE_PREFERENCE_ALL /* app */,
10526                 true /* channel */);
10527 
10528         NotificationRecord nr =
10529                 generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble");
10530 
10531         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10532                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10533         waitForIdle();
10534 
10535         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10536         assertEquals(1, notifs.length);
10537         assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0);
10538         assertTrue(mService.getNotificationRecord(
10539                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10540     }
10541 
10542     @Test
testFlagBubble_noFlag_appNotAllowed()10543     public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException {
10544         setUpPrefsForBubbles(mPkg, mUid,
10545                 true /* global */,
10546                 BUBBLE_PREFERENCE_NONE /* app */,
10547                 true /* channel */);
10548 
10549         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10550                         "testFlagBubble_noFlag_appNotAllowed");
10551 
10552         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10553                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10554         waitForIdle();
10555 
10556         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10557         assertEquals(1, notifs.length);
10558         assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0);
10559         assertFalse(mService.getNotificationRecord(
10560                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10561     }
10562 
10563     @Test
testFlagBubbleNotifs_noFlag_whenAppForeground()10564     public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException {
10565         setUpPrefsForBubbles(mPkg, mUid,
10566                 true /* global */,
10567                 BUBBLE_PREFERENCE_ALL /* app */,
10568                 true /* channel */);
10569 
10570         // Notif with bubble metadata but not our other misc requirements
10571         Notification.Builder nb = new Notification.Builder(mContext,
10572                 mTestNotificationChannel.getId())
10573                 .setContentTitle("foo")
10574                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
10575                 .setBubbleMetadata(getBubbleMetadata());
10576         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 0,
10577                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10578         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10579 
10580         // Say we're foreground
10581         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
10582                 IMPORTANCE_FOREGROUND);
10583         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10584                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10585         waitForIdle();
10586 
10587         // if notif isn't configured properly it doesn't get to bubble just because app is
10588         // foreground.
10589         assertFalse(mService.getNotificationRecord(
10590                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10591     }
10592 
10593     @Test
testFlagBubbleNotifs_flag_messaging()10594     public void testFlagBubbleNotifs_flag_messaging() throws RemoteException {
10595         setUpPrefsForBubbles(mPkg, mUid,
10596                 true /* global */,
10597                 BUBBLE_PREFERENCE_ALL /* app */,
10598                 true /* channel */);
10599 
10600         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10601                 "testFlagBubbleNotifs_flag_messaging");
10602 
10603         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10604                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10605         waitForIdle();
10606 
10607         // yes allowed, yes messaging, yes bubble
10608         assertTrue(mService.getNotificationRecord(
10609                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10610     }
10611 
10612     @Test
testFlagBubbleNotifs_noFlag_noShortcut()10613     public void testFlagBubbleNotifs_noFlag_noShortcut() throws RemoteException {
10614         setUpPrefsForBubbles(mPkg, mUid,
10615                 true /* global */,
10616                 BUBBLE_PREFERENCE_ALL /* app */,
10617                 true /* channel */);
10618 
10619         Notification.Builder nb = getMessageStyleNotifBuilder(true, null, false, true);
10620         nb.setShortcutId(null);
10621         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
10622                 null, mUid, 0,
10623                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10624 
10625         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
10626                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
10627         waitForIdle();
10628 
10629         // no shortcut no bubble
10630         assertFalse(mService.getNotificationRecord(
10631                 sbn.getKey()).getNotification().isBubbleNotification());
10632     }
10633 
10634     @Test
testFlagBubbleNotifs_noFlag_messaging_appNotAllowed()10635     public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException {
10636         setUpPrefsForBubbles(mPkg, mUid,
10637                 true /* global */,
10638                 BUBBLE_PREFERENCE_NONE /* app */,
10639                 true /* channel */);
10640 
10641         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10642                 "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed");
10643 
10644         // Post the notification
10645         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10646                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10647         waitForIdle();
10648 
10649         // not allowed, no bubble
10650         assertFalse(mService.getNotificationRecord(
10651                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10652     }
10653 
10654     @Test
testFlagBubbleNotifs_noFlag_notBubble()10655     public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException {
10656         setUpPrefsForBubbles(mPkg, mUid,
10657                 true /* global */,
10658                 BUBBLE_PREFERENCE_ALL /* app */,
10659                 true /* channel */);
10660 
10661         // Messaging notif WITHOUT bubble metadata
10662         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */,
10663                 null /* groupKey */, false /* isSummary */, true);
10664 
10665         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
10666                 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0,
10667                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10668         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10669 
10670         // Post the notification
10671         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10672                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10673         waitForIdle();
10674 
10675         // no bubble metadata, no bubble
10676         assertFalse(mService.getNotificationRecord(
10677                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10678     }
10679 
10680     @Test
testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed()10681     public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException {
10682         setUpPrefsForBubbles(mPkg, mUid,
10683                 true /* global */,
10684                 BUBBLE_PREFERENCE_ALL /* app */,
10685                 false /* channel */);
10686 
10687         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10688                 "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed");
10689         nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE);
10690 
10691         // Post the notification
10692         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10693                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10694         waitForIdle();
10695 
10696         // channel not allowed, no bubble
10697         assertFalse(mService.getNotificationRecord(
10698                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10699     }
10700 
10701     @Test
testCancelNotificationsFromApp_cancelsBubbles()10702     public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception {
10703         final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
10704         nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
10705 
10706         // Post the notification
10707         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
10708                 "testAppCancelNotifications_cancelsBubbles",
10709                 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(),
10710                 nrBubble.getSbn().getUserId());
10711         waitForIdle();
10712 
10713         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10714         assertEquals(1, notifs.length);
10715         assertEquals(1, mService.getNotificationRecordCount());
10716 
10717         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
10718                 "testAppCancelNotifications_cancelsBubbles", nrBubble.getSbn().getId(),
10719                 nrBubble.getSbn().getUserId());
10720         waitForIdle();
10721 
10722         StatusBarNotification[] notifs2 = mBinderService.getActiveNotifications(mPkg);
10723         assertEquals(0, notifs2.length);
10724         assertEquals(0, mService.getNotificationRecordCount());
10725     }
10726 
10727     @Test
testCancelAllNotificationsFromApp_cancelsBubble()10728     public void testCancelAllNotificationsFromApp_cancelsBubble() throws Exception {
10729         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10730         nr.getSbn().getNotification().flags |= FLAG_BUBBLE;
10731         mService.addNotification(nr);
10732 
10733         mBinderService.cancelAllNotifications(mPkg, nr.getSbn().getUserId());
10734         waitForIdle();
10735 
10736         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10737         assertEquals(0, notifs.length);
10738         assertEquals(0, mService.getNotificationRecordCount());
10739     }
10740 
10741     @Test
testCancelAllNotificationsFromListener_ignoresBubbles()10742     public void testCancelAllNotificationsFromListener_ignoresBubbles() throws Exception {
10743         final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel);
10744         final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
10745         nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
10746 
10747         mService.addNotification(nrNormal);
10748         mService.addNotification(nrBubble);
10749 
10750         mService.getBinderService().cancelNotificationsFromListener(null, null);
10751         waitForIdle();
10752 
10753         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10754         assertEquals(1, notifs.length);
10755         assertEquals(1, mService.getNotificationRecordCount());
10756     }
10757 
10758     @Test
testCancelNotificationsFromListener_cancelsNonBubble()10759     public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception {
10760         // Add non-bubble notif
10761         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10762         mService.addNotification(nr);
10763 
10764         // Cancel via listener
10765         String[] keys = {nr.getSbn().getKey()};
10766         mService.getBinderService().cancelNotificationsFromListener(null, keys);
10767         waitForIdle();
10768 
10769         // Notif not active anymore
10770         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10771         assertEquals(0, notifs.length);
10772         assertEquals(0, mService.getNotificationRecordCount());
10773         // Cancel event is logged
10774         assertEquals(1, mNotificationRecordLogger.numCalls());
10775         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
10776             .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
10777     }
10778 
10779     @Test
testCancelNotificationsFromListener_suppressesBubble()10780     public void testCancelNotificationsFromListener_suppressesBubble() throws Exception {
10781         // Add bubble notif
10782         setUpPrefsForBubbles(mPkg, mUid,
10783             true /* global */,
10784             BUBBLE_PREFERENCE_ALL /* app */,
10785             true /* channel */);
10786         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
10787 
10788         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10789             nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10790         waitForIdle();
10791 
10792         // Cancel via listener
10793         String[] keys = {nr.getSbn().getKey()};
10794         mService.getBinderService().cancelNotificationsFromListener(null, keys);
10795         waitForIdle();
10796 
10797         // Bubble notif active and suppressed
10798         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10799         assertEquals(1, notifs.length);
10800         assertEquals(1, mService.getNotificationRecordCount());
10801         assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed());
10802     }
10803 
10804     @Test
testCancelAllNotificationsFromStatusBar_ignoresBubble()10805     public void testCancelAllNotificationsFromStatusBar_ignoresBubble() throws Exception {
10806         // GIVEN a notification bubble
10807         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10808         nr.getSbn().getNotification().flags |= FLAG_BUBBLE;
10809         mService.addNotification(nr);
10810 
10811         // WHEN the status bar clears all notifications
10812         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
10813                 nr.getSbn().getUserId());
10814         waitForIdle();
10815 
10816         // THEN the bubble notification does not get removed
10817         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10818         assertEquals(1, notifs.length);
10819         assertEquals(1, mService.getNotificationRecordCount());
10820     }
10821 
10822 
10823     @Test
testGetAllowedAssistantAdjustments()10824     public void testGetAllowedAssistantAdjustments() throws Exception {
10825         List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null);
10826         assertNotNull(adjustments);
10827     }
10828 
10829     @Test
testAdjustRestrictedKey()10830     public void testAdjustRestrictedKey() throws Exception {
10831         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10832         mService.addNotification(r);
10833         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
10834 
10835         when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true);
10836         when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false);
10837 
10838         Bundle signals = new Bundle();
10839         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
10840         signals.putInt(KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
10841         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
10842                "", r.getUser().getIdentifier());
10843 
10844         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
10845         r.applyAdjustments();
10846 
10847         assertEquals(IMPORTANCE_LOW, r.getAssistantImportance());
10848         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
10849     }
10850 
10851     @Test
testAutomaticZenRuleValidation_policyFilterAgreement()10852     public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception {
10853         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10854                 .thenReturn(true);
10855         mService.setZenHelper(mock(ZenModeHelper.class));
10856         ComponentName owner = new ComponentName(mContext, this.getClass());
10857         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10858         boolean isEnabled = true;
10859         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10860                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
10861 
10862         try {
10863             mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
10864             fail("Zen policy only applies to priority only mode");
10865         } catch (IllegalArgumentException e) {
10866             // yay
10867         }
10868 
10869         rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10870                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10871         mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
10872 
10873         rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10874                 null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
10875         mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
10876     }
10877 
10878     @Test
testAddAutomaticZenRule_systemCallTakesPackageFromOwner()10879     public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
10880         mService.isSystemUid = true;
10881         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
10882         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10883                 .thenReturn(true);
10884         mService.setZenHelper(mockZenModeHelper);
10885         ComponentName owner = new ComponentName("android", "ProviderName");
10886         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10887         boolean isEnabled = true;
10888         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10889                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10890         mBinderService.addAutomaticZenRule(rule, "com.android.settings", false);
10891 
10892         // verify that zen mode helper gets passed in a package name of "android"
10893         verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule),
10894                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt());
10895     }
10896 
10897     @Test
testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner()10898     public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception {
10899         // The multi-user case: where the calling uid doesn't match the system uid, but the calling
10900         // *appid* is the system.
10901         mService.isSystemUid = false;
10902         mService.isSystemAppId = true;
10903         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
10904         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10905                 .thenReturn(true);
10906         mService.setZenHelper(mockZenModeHelper);
10907         ComponentName owner = new ComponentName("android", "ProviderName");
10908         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10909         boolean isEnabled = true;
10910         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10911                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10912         mBinderService.addAutomaticZenRule(rule, "com.android.settings", false);
10913 
10914         // verify that zen mode helper gets passed in a package name of "android"
10915         verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule),
10916                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt());
10917     }
10918 
10919     @Test
testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg()10920     public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
10921         mService.isSystemUid = false;
10922         mService.isSystemAppId = false;
10923         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
10924         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10925                 .thenReturn(true);
10926         mService.setZenHelper(mockZenModeHelper);
10927         ComponentName owner = new ComponentName("android", "ProviderName");
10928         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10929         boolean isEnabled = true;
10930         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10931                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10932         mBinderService.addAutomaticZenRule(rule, "another.package", false);
10933 
10934         // verify that zen mode helper gets passed in the package name from the arg, not the owner
10935         verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("another.package"), eq(rule),
10936                 eq(ZenModeConfig.ORIGIN_APP), anyString(),
10937                 anyInt());  // doesn't count as a system/systemui call
10938     }
10939 
10940     @Test
10941     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners()10942     public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception {
10943         ZenModeHelper zenModeHelper = setUpMockZenTest();
10944         mService.setCallerIsNormalPackage();
10945 
10946         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
10947                 .setType(AutomaticZenRule.TYPE_MANAGED)
10948                 .setOwner(new ComponentName(mPkg, "cls"))
10949                 .build();
10950         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
10951 
10952         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
10953 
10954         verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(),
10955                 anyInt());
10956     }
10957 
10958     @Test
10959     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeManagedCanBeUsedBySystem()10960     public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception {
10961         addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED);
10962     }
10963 
10964     @Test
10965     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps()10966     public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception {
10967         addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
10968                 AutomaticZenRule.TYPE_MANAGED);
10969     }
10970 
10971     @Test
10972     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing()10973     public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception {
10974         ZenModeHelper zenModeHelper = setUpMockZenTest();
10975         mService.setCallerIsNormalPackage();
10976         reset(mPackageManagerInternal);
10977         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
10978         when(mResources
10979                 .getString(com.android.internal.R.string.config_systemWellbeing))
10980                 .thenReturn(mPkg);
10981         when(mContext.getResources()).thenReturn(mResources);
10982 
10983         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
10984                 .setType(AutomaticZenRule.TYPE_BEDTIME)
10985                 .setOwner(new ComponentName(mPkg, "cls"))
10986                 .build();
10987 
10988         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
10989 
10990         verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(),
10991                 anyInt());
10992     }
10993 
10994     @Test
10995     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem()10996     public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception {
10997         reset(mPackageManagerInternal);
10998         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
10999         addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME);
11000     }
11001 
11002     @Test
11003     @EnableFlags(android.app.Flags.FLAG_MODES_API)
testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps()11004     public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception {
11005         reset(mPackageManagerInternal);
11006         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
11007         addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
11008                 AutomaticZenRule.TYPE_BEDTIME);
11009     }
11010 
addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( @utomaticZenRule.Type int ruleType)11011     private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(
11012             @AutomaticZenRule.Type int ruleType) throws Exception {
11013         ZenModeHelper zenModeHelper = setUpMockZenTest();
11014         mService.isSystemUid = true;
11015 
11016         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
11017                 .setType(ruleType)
11018                 .setOwner(new ComponentName(mPkg, "cls"))
11019                 .build();
11020         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
11021 
11022         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
11023 
11024         verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(),
11025                 anyInt());
11026     }
11027 
addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( @utomaticZenRule.Type int ruleType)11028     private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
11029             @AutomaticZenRule.Type int ruleType) {
11030         mService.setCallerIsNormalPackage();
11031         mService.setZenHelper(mock(ZenModeHelper.class));
11032         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
11033                 .thenReturn(true);
11034 
11035         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
11036                 .setType(ruleType)
11037                 .setOwner(new ComponentName(mPkg, "cls"))
11038                 .build();
11039         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false);
11040 
11041         assertThrows(IllegalArgumentException.class,
11042                 () -> mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false));
11043     }
11044 
11045     @Test
11046     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromUser_mappedToOriginUser()11047     public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception {
11048         ZenModeHelper zenModeHelper = setUpMockZenTest();
11049         mService.isSystemUid = true;
11050 
11051         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true);
11052 
11053         verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE),
11054                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt());
11055     }
11056 
11057     @Test
11058     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem()11059     public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception {
11060         ZenModeHelper zenModeHelper = setUpMockZenTest();
11061         mService.isSystemUid = true;
11062 
11063         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false);
11064 
11065         verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE),
11066                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt());
11067     }
11068 
11069     @Test
11070     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromApp_mappedToOriginApp()11071     public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception {
11072         ZenModeHelper zenModeHelper = setUpMockZenTest();
11073         mService.setCallerIsNormalPackage();
11074 
11075         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false);
11076 
11077         verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE),
11078                 eq(ZenModeConfig.ORIGIN_APP), anyString(), anyInt());
11079     }
11080 
11081     @Test
11082     @EnableFlags(android.app.Flags.FLAG_MODES_API)
addAutomaticZenRule_fromAppFromUser_blocked()11083     public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception {
11084         setUpMockZenTest();
11085         mService.setCallerIsNormalPackage();
11086 
11087         assertThrows(SecurityException.class, () ->
11088                 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true));
11089     }
11090 
11091     @Test
11092     @EnableFlags(android.app.Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromUserFromSystem_allowed()11093     public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
11094         ZenModeHelper zenModeHelper = setUpMockZenTest();
11095         mService.isSystemUid = true;
11096 
11097         mBinderService.updateAutomaticZenRule("id", SOME_ZEN_RULE, /* fromUser= */ true);
11098 
11099         verify(zenModeHelper).updateAutomaticZenRule(any(), eq("id"), eq(SOME_ZEN_RULE),
11100                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt());
11101     }
11102 
11103     @Test
11104     @EnableFlags(android.app.Flags.FLAG_MODES_API)
updateAutomaticZenRule_fromUserFromApp_blocked()11105     public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
11106         setUpMockZenTest();
11107         mService.setCallerIsNormalPackage();
11108 
11109         assertThrows(SecurityException.class, () ->
11110                 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true));
11111     }
11112 
11113     @Test
11114     @EnableFlags(android.app.Flags.FLAG_MODES_API)
removeAutomaticZenRule_fromUserFromSystem_allowed()11115     public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
11116         ZenModeHelper zenModeHelper = setUpMockZenTest();
11117         mService.isSystemUid = true;
11118 
11119         mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true);
11120 
11121         verify(zenModeHelper).removeAutomaticZenRule(any(), eq("id"),
11122                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt());
11123     }
11124 
11125     @Test
11126     @EnableFlags(android.app.Flags.FLAG_MODES_API)
removeAutomaticZenRule_fromUserFromApp_blocked()11127     public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
11128         setUpMockZenTest();
11129         mService.setCallerIsNormalPackage();
11130 
11131         assertThrows(SecurityException.class, () ->
11132                 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true));
11133     }
11134 
11135     @Test
11136     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()11137     public void setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()
11138             throws Exception {
11139         ZenModeHelper zenModeHelper = setUpMockZenTest();
11140         mService.setCallerIsNormalPackage();
11141 
11142         Condition withSourceUser = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11143                 SOURCE_USER_ACTION);
11144         mBinderService.setAutomaticZenRuleState("id", withSourceUser);
11145 
11146         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceUser),
11147                 eq(ZenModeConfig.ORIGIN_USER_IN_APP), anyInt());
11148     }
11149 
11150     @Test
11151     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()11152     public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()
11153             throws Exception {
11154         ZenModeHelper zenModeHelper = setUpMockZenTest();
11155         mService.setCallerIsNormalPackage();
11156 
11157         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11158                 SOURCE_CONTEXT);
11159         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
11160 
11161         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext),
11162                 eq(ZenModeConfig.ORIGIN_APP), anyInt());
11163     }
11164 
11165     @Test
11166     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()11167     public void setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()
11168             throws Exception {
11169         ZenModeHelper zenModeHelper = setUpMockZenTest();
11170         mService.isSystemUid = true;
11171 
11172         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11173                 SOURCE_USER_ACTION);
11174         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
11175 
11176         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext),
11177                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyInt());
11178     }
11179     @Test
11180     @EnableFlags(android.app.Flags.FLAG_MODES_API)
setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()11181     public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()
11182             throws Exception {
11183         ZenModeHelper zenModeHelper = setUpMockZenTest();
11184         mService.isSystemUid = true;
11185 
11186         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11187                 SOURCE_CONTEXT);
11188         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
11189 
11190         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext),
11191                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyInt());
11192     }
11193 
11194 
11195     @Test
11196     @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER)
getAutomaticZenRules_fromSystem_readsWithCurrentUser()11197     public void getAutomaticZenRules_fromSystem_readsWithCurrentUser() throws Exception {
11198         ZenModeHelper zenModeHelper = setUpMockZenTest();
11199         mService.isSystemUid = true;
11200 
11201         // Representative used to verify getCallingZenUser().
11202         mBinderService.getAutomaticZenRules();
11203 
11204         verify(zenModeHelper).getAutomaticZenRules(eq(UserHandle.CURRENT));
11205     }
11206 
11207     @Test
11208     @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER)
getAutomaticZenRules_fromNormalPackage_readsWithBinderUser()11209     public void getAutomaticZenRules_fromNormalPackage_readsWithBinderUser() throws Exception {
11210         ZenModeHelper zenModeHelper = setUpMockZenTest();
11211         mService.setCallerIsNormalPackage();
11212 
11213         // Representative used to verify getCallingZenUser().
11214         mBinderService.getAutomaticZenRules();
11215 
11216         verify(zenModeHelper).getAutomaticZenRules(eq(Binder.getCallingUserHandle()));
11217     }
11218 
11219     /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */
setUpMockZenTest()11220     private ZenModeHelper setUpMockZenTest() {
11221         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
11222         mService.setZenHelper(zenModeHelper);
11223         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
11224                 .thenReturn(true);
11225         return zenModeHelper;
11226     }
11227 
11228     @Test
onZenModeChanged_sendsBroadcasts()11229     public void onZenModeChanged_sendsBroadcasts() throws Exception {
11230         when(mAmi.getCurrentUserId()).thenReturn(100);
11231         when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
11232         when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
11233             @Override
11234             public List<String> answer(InvocationOnMock invocation) {
11235                 int userId = invocation.getArgument(0);
11236                 switch (userId) {
11237                     case 100:
11238                         return Lists.newArrayList("a", "b", "c");
11239                     case 101:
11240                         return Lists.newArrayList();
11241                     case 102:
11242                         return Lists.newArrayList("b");
11243                     default:
11244                         throw new IllegalArgumentException(
11245                                 "Why would you ask for packages of userId " + userId + "?");
11246                 }
11247             }
11248         });
11249 
11250         mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
11251                 "testing!", false);
11252         waitForIdle();
11253 
11254         InOrder inOrder = inOrder(mContext);
11255         // Verify broadcasts for registered receivers
11256         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
11257                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
11258                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null));
11259         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
11260                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
11261                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null));
11262         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
11263                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
11264                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null));
11265 
11266         // Verify broadcast for packages that manage DND.
11267         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11268                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags(
11269                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
11270         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11271                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
11272                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
11273         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11274                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags(
11275                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
11276         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11277                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
11278                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102)));
11279     }
11280 
11281     @Test
11282     @EnableFlags(android.app.Flags.FLAG_MODES_API)
onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner()11283     public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception {
11284         mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged(
11285                 mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED));
11286 
11287         Intent expected = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED)
11288                 .setPackage("rule.owner.pkg")
11289                 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, "rule_id")
11290                 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, AUTOMATIC_RULE_STATUS_ACTIVATED)
11291                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
11292 
11293         verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId)));
11294     }
11295 
eqIntent(Intent wanted)11296     private static Intent eqIntent(Intent wanted) {
11297         return ArgumentMatchers.argThat(
11298                 new ArgumentMatcher<Intent>() {
11299                     @Override
11300                     public boolean matches(Intent argument) {
11301                         return wanted.filterEquals(argument)
11302                                 && wanted.getFlags() == argument.getFlags()
11303                                 && equalBundles(wanted.getExtras(), argument.getExtras());
11304                     }
11305 
11306                     @Override
11307                     public String toString() {
11308                         return wanted.toString();
11309                     }
11310 
11311                     private boolean equalBundles(Bundle one, Bundle two) {
11312                         if (one == null && two == null) {
11313                             return true;
11314                         }
11315                         if ((one == null) != (two == null)) {
11316                             return false;
11317                         }
11318                         if (one.size() != two.size()) {
11319                             return false;
11320                         }
11321 
11322                         HashSet<String> setOne = new HashSet<>(one.keySet());
11323                         setOne.addAll(two.keySet());
11324 
11325                         for (String key : setOne) {
11326                             if (!one.containsKey(key) || !two.containsKey(key)) {
11327                                 return false;
11328                             }
11329 
11330                             Object valueOne = one.get(key);
11331                             Object valueTwo = two.get(key);
11332                             if (valueOne instanceof Bundle
11333                                     && valueTwo instanceof Bundle
11334                                     && !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) {
11335                                 return false;
11336                             } else if (valueOne == null) {
11337                                 if (valueTwo != null) {
11338                                     return false;
11339                                 }
11340                             } else if (!valueOne.equals(valueTwo)) {
11341                                 return false;
11342                             }
11343                         }
11344                         return true;
11345                     }
11346                 });
11347     }
11348 
11349     @Test
11350     public void testAreNotificationsEnabledForPackage() throws Exception {
11351         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
11352                 mUid);
11353 
11354         verify(mPermissionHelper).hasPermission(mUid);
11355     }
11356 
11357     @Test
11358     public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
11359         try {
11360             mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
11361                     mUid + UserHandle.PER_USER_RANGE);
11362             fail("Cannot call cross user without permission");
11363         } catch (SecurityException e) {
11364             // pass
11365         }
11366         verify(mPermissionHelper, never()).hasPermission(anyInt());
11367 
11368         // cross user, with permission, no problem
11369         enableInteractAcrossUsers();
11370         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
11371                 mUid + UserHandle.PER_USER_RANGE);
11372 
11373         verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
11374     }
11375 
11376     @Test
11377     public void testAreNotificationsEnabledForPackage_viaInternalService() {
11378         mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
11379         verify(mPermissionHelper).hasPermission(mUid);
11380     }
11381 
11382     @Test
11383     public void testGetPackageImportance() throws Exception {
11384         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
11385         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
11386                 .isEqualTo(IMPORTANCE_DEFAULT);
11387 
11388         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
11389         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
11390                 .isEqualTo(IMPORTANCE_NONE);
11391     }
11392 
11393     @Test
11394     public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
11395         try {
11396             mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
11397                     mUid + UserHandle.PER_USER_RANGE);
11398             fail("Cannot call cross user without permission");
11399         } catch (SecurityException e) {
11400             // pass
11401         }
11402 
11403         // cross user, with permission, no problem
11404         enableInteractAcrossUsers();
11405         mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
11406                 mUid + UserHandle.PER_USER_RANGE);
11407     }
11408 
11409     private void enableInteractAcrossUsers() {
11410         TestablePermissions perms = mContext.getTestablePermissions();
11411         perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
11412     }
11413 
11414     @Test
11415     public void testNotificationBubbleChanged_false() throws Exception {
11416         setUpPrefsForBubbles(mPkg, mUid,
11417                 true /* global */,
11418                 BUBBLE_PREFERENCE_ALL /* app */,
11419                 true /* channel */);
11420 
11421         // Notif with bubble metadata
11422         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11423                 "testNotificationBubbleChanged_false");
11424 
11425         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11426                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11427         waitForIdle();
11428 
11429         // Reset as this is called when the notif is first sent
11430         reset(mListeners);
11431 
11432         // First we were a bubble
11433         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11434         assertEquals(1, notifsBefore.length);
11435         assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0);
11436 
11437         // Notify we're not a bubble
11438         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
11439         waitForIdle();
11440 
11441         // Make sure we are not a bubble
11442         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11443         assertEquals(1, notifsAfter.length);
11444         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
11445     }
11446 
11447     @Test
11448     public void testNotificationBubbleChanged_true() throws Exception {
11449         setUpPrefsForBubbles(mPkg, mUid,
11450                 true /* global */,
11451                 BUBBLE_PREFERENCE_ALL /* app */,
11452                 true /* channel */);
11453 
11454         // Notif that is not a bubble
11455         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
11456                 1, null, false);
11457         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11458                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11459         waitForIdle();
11460 
11461         // Would be a normal notification because wouldn't have met requirements to bubble
11462         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11463         assertEquals(1, notifsBefore.length);
11464         assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
11465 
11466         // Update the notification to be message style / meet bubble requirements
11467         NotificationRecord nr2 = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11468                 nr.getSbn().getTag());
11469         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr2.getSbn().getTag(),
11470                 nr2.getSbn().getId(), nr2.getSbn().getNotification(), nr2.getSbn().getUserId());
11471         waitForIdle();
11472 
11473         // Reset as this is called when the notif is first sent
11474         reset(mListeners);
11475 
11476         // Notify we are now a bubble
11477         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
11478         waitForIdle();
11479 
11480         // Make sure we are a bubble
11481         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11482         assertEquals(1, notifsAfter.length);
11483         assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
11484     }
11485 
11486     @Test
11487     public void testNotificationBubbleChanged_true_notAllowed() throws Exception {
11488         setUpPrefsForBubbles(mPkg, mUid,
11489                 true /* global */,
11490                 BUBBLE_PREFERENCE_ALL /* app */,
11491                 true /* channel */);
11492 
11493         // Notif that is not a bubble
11494         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
11495         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11496                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11497         waitForIdle();
11498 
11499         // Reset as this is called when the notif is first sent
11500         reset(mListeners);
11501 
11502         // Would be a normal notification because wouldn't have met requirements to bubble
11503         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11504         assertEquals(1, notifsBefore.length);
11505         assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
11506 
11507         // Notify we are now a bubble
11508         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
11509         waitForIdle();
11510 
11511         // We still wouldn't be a bubble because the notification didn't meet requirements
11512         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11513         assertEquals(1, notifsAfter.length);
11514         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
11515     }
11516 
11517     @Test
11518     public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception {
11519         setUpPrefsForBubbles(mPkg, mUid,
11520                 true /* global */,
11521                 BUBBLE_PREFERENCE_ALL /* app */,
11522                 true /* channel */);
11523 
11524         // Notif with bubble metadata
11525         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11526                 "testNotificationBubbleIsFlagRemoved_resetOnUpdate");
11527 
11528         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11529                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11530         waitForIdle();
11531         // Flag shouldn't be modified
11532         NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11533         assertFalse(recordToCheck.isFlagBubbleRemoved());
11534 
11535         // Notify we're not a bubble
11536         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
11537         waitForIdle();
11538         // Flag should be modified
11539         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11540         assertTrue(recordToCheck.isFlagBubbleRemoved());
11541 
11542 
11543         // Update the notif
11544         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11545                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11546         waitForIdle();
11547         // And the flag is reset
11548         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11549         assertFalse(recordToCheck.isFlagBubbleRemoved());
11550     }
11551 
11552     @Test
11553     public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception {
11554         setUpPrefsForBubbles(mPkg, mUid,
11555                 true /* global */,
11556                 BUBBLE_PREFERENCE_ALL /* app */,
11557                 true /* channel */);
11558 
11559         // Notif with bubble metadata
11560         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11561                 "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue");
11562 
11563         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11564                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11565         waitForIdle();
11566         // Flag shouldn't be modified
11567         NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11568         assertFalse(recordToCheck.isFlagBubbleRemoved());
11569 
11570         // Notify we're not a bubble
11571         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
11572         waitForIdle();
11573         // Flag should be modified
11574         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11575         assertTrue(recordToCheck.isFlagBubbleRemoved());
11576 
11577         // Notify we are a bubble
11578         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
11579         waitForIdle();
11580         // And the flag is reset
11581         assertFalse(recordToCheck.isFlagBubbleRemoved());
11582     }
11583 
11584     @Test
11585     public void testOnBubbleMetadataFlagChanged() throws Exception {
11586         setUpPrefsForBubbles(mPkg, mUid,
11587                 true /* global */,
11588                 BUBBLE_PREFERENCE_ALL /* app */,
11589                 true /* channel */);
11590 
11591         // Post a bubble notification
11592         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
11593         // Set this so that the bubble can be suppressed
11594         nr.getNotification().getBubbleMetadata().setFlags(
11595                 Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE);
11596         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11597                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11598         waitForIdle();
11599 
11600         // Check the flags
11601         Notification n =  mBinderService.getActiveNotifications(mPkg)[0].getNotification();
11602         assertFalse(n.getBubbleMetadata().isNotificationSuppressed());
11603         assertFalse(n.getBubbleMetadata().getAutoExpandBubble());
11604         assertFalse(n.getBubbleMetadata().isBubbleSuppressed());
11605         assertTrue(n.getBubbleMetadata().isBubbleSuppressable());
11606 
11607         // Reset as this is called when the notif is first sent
11608         reset(mListeners);
11609 
11610         // Test: change the flags
11611         int flags = Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE;
11612         flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
11613         flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
11614         flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
11615         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), flags);
11616         waitForIdle();
11617 
11618         // Check
11619         n =  mBinderService.getActiveNotifications(mPkg)[0].getNotification();
11620         assertEquals(flags, n.getBubbleMetadata().getFlags());
11621 
11622         // Reset to check again
11623         reset(mListeners);
11624 
11625         // Test: clear flags
11626         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 0);
11627         waitForIdle();
11628 
11629         // Check
11630         n = mBinderService.getActiveNotifications(mPkg)[0].getNotification();
11631         assertEquals(0, n.getBubbleMetadata().getFlags());
11632     }
11633 
11634     @Test
11635     public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped()
11636             throws RemoteException {
11637 
11638         setUpPrefsForBubbles(mPkg, mUid,
11639                 true /* global */,
11640                 BUBBLE_PREFERENCE_ALL /* app */,
11641                 true /* channel */);
11642 
11643         // Post a bubble notification
11644         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
11645         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11646                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11647         waitForIdle();
11648 
11649         // Test: suppress notification via bubble metadata update
11650         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(),
11651                 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
11652         waitForIdle();
11653 
11654         // Check audio is stopped
11655         verify(mAttentionHelper).clearEffectsLocked(nr.getKey());
11656     }
11657 
11658     @Test
11659     public void testGrantInlineReplyUriPermission_recordExists() throws Exception {
11660         int userId = UserManager.isHeadlessSystemUserMode()
11661                 ? UserHandle.getUserId(UID_HEADLESS)
11662                 : USER_SYSTEM;
11663 
11664         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
11665         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
11666                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11667         waitForIdle();
11668 
11669         // A notification exists for the given record
11670         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11671         assertEquals(1, notifsBefore.length);
11672 
11673         reset(mPackageManager);
11674 
11675         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11676 
11677         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11678                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11679                 nr.getSbn().getUid());
11680 
11681         // Grant permission called for the UID of SystemUI under the target user ID
11682         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11683                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
11684                 anyInt(), eq(nr.getSbn().getUserId()));
11685     }
11686 
11687     @Test
11688     public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception {
11689         int userId = UserManager.isHeadlessSystemUserMode()
11690                 ? UserHandle.getUserId(UID_HEADLESS)
11691                 : USER_SYSTEM;
11692 
11693         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
11694         waitForIdle();
11695 
11696         // No notifications exist for the given record
11697         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11698         assertEquals(0, notifsBefore.length);
11699 
11700         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11701 
11702         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11703                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11704                 nr.getSbn().getUid());
11705 
11706         // Grant permission still called if no NotificationRecord exists for the given key
11707         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11708                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
11709                 anyInt(), eq(nr.getSbn().getUserId()));
11710     }
11711 
11712     @Test
11713     public void testGrantInlineReplyUriPermission_userAll() throws Exception {
11714         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
11715         NotificationRecord nr =
11716                 generateNotificationRecord(mTestNotificationChannel, UserHandle.USER_ALL);
11717         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
11718                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11719         waitForIdle();
11720 
11721         // A notification exists for the given record
11722         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11723         assertEquals(1, notifsBefore.length);
11724 
11725         reset(mPackageManager);
11726 
11727         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11728 
11729         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11730                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11731                 nr.getSbn().getUid());
11732 
11733         // Target user for the grant is USER_ALL instead of USER_SYSTEM
11734         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11735                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
11736                 anyInt(), UserManager.isHeadlessSystemUserMode()
11737                         ? eq(UserHandle.getUserId(UID_HEADLESS))
11738                         : eq(USER_SYSTEM));
11739     }
11740 
11741     @Test
11742     public void testGrantInlineReplyUriPermission_acrossUsers() throws Exception {
11743         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
11744         int otherUserId = 11;
11745         NotificationRecord nr =
11746                 generateNotificationRecord(mTestNotificationChannel, otherUserId);
11747         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
11748                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11749         waitForIdle();
11750 
11751         // A notification exists for the given record
11752         List<StatusBarNotification> notifsBefore =
11753                 mBinderService.getAppActiveNotifications(mPkg, nr.getSbn().getUserId()).getList();
11754         assertEquals(1, notifsBefore.size());
11755 
11756         reset(mPackageManager);
11757 
11758         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11759 
11760         int uid = 0; // sysui on primary user
11761         int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user
11762         String sysuiPackage = "sysui";
11763         final String[] sysuiPackages = new String[] { sysuiPackage };
11764         when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages);
11765 
11766         // Make sure to mock call for USER_SYSTEM and not USER_ALL, since it's been replaced by the
11767         // time this is called
11768         when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId))
11769                 .thenReturn(otherUserUid);
11770 
11771         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11772                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), uid);
11773 
11774         // Target user for the grant is USER_ALL instead of USER_SYSTEM
11775         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11776                 eq(otherUserUid), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), anyInt(),
11777                 eq(otherUserId));
11778     }
11779 
11780     @Test
11781     public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception {
11782         int userId = UserManager.isHeadlessSystemUserMode()
11783                 ? UserHandle.getUserId(UID_HEADLESS)
11784                 : USER_SYSTEM;
11785 
11786         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
11787         reset(mPackageManager);
11788 
11789         Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11790         Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2);
11791 
11792         // create an inline record with two uris in it
11793         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11794                 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11795                 nr.getSbn().getUid());
11796         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11797                 nr.getKey(), uri2, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11798                 nr.getSbn().getUid());
11799 
11800         InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
11801         assertNotNull(record); // record exists
11802         assertEquals(record.getUris().size(), 2); // record has two uris in it
11803 
11804         mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(),
11805                 nr.getSbn().getUid());
11806 
11807         // permissionOwner destroyed
11808         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
11809                 eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId()));
11810     }
11811 
11812 
11813     @Test
11814     public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception {
11815         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0);
11816         reset(mPackageManager);
11817 
11818         mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(),
11819                 nr.getSbn().getUid());
11820 
11821         // no permissionOwner destroyed
11822         verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner(
11823                 any(), eq(null), eq(~0), eq(nr.getUserId()));
11824     }
11825 
11826     @Test
11827     public void testClearInlineReplyUriPermission_userAll() throws Exception {
11828         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
11829                 UserHandle.USER_ALL);
11830         reset(mPackageManager);
11831 
11832         Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11833 
11834         // create an inline record a uri in it
11835         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11836                 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11837                 nr.getSbn().getUid());
11838 
11839         InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
11840         assertNotNull(record); // record exists
11841 
11842         mService.mNotificationDelegate.clearInlineReplyUriPermissions(
11843                 nr.getKey(), nr.getSbn().getUid());
11844 
11845         // permissionOwner destroyed for USER_SYSTEM, not USER_ALL
11846         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
11847                 eq(record.getPermissionOwner()), eq(null), eq(~0),
11848                 UserManager.isHeadlessSystemUserMode()
11849                         ? eq(UserHandle.getUserId(UID_HEADLESS))
11850                         : eq(USER_SYSTEM));
11851     }
11852 
11853     @Test
11854     public void testNotificationBubbles_disabled_lowRamDevice() throws Exception {
11855         setUpPrefsForBubbles(mPkg, mUid,
11856                 true /* global */,
11857                 BUBBLE_PREFERENCE_ALL /* app */,
11858                 true /* channel */);
11859 
11860         // And we are low ram
11861         when(mActivityManager.isLowRamDevice()).thenReturn(true);
11862 
11863         // Notification that would typically bubble
11864         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11865                 "testNotificationBubbles_disabled_lowRamDevice");
11866         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11867                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11868         waitForIdle();
11869 
11870         // But we wouldn't be a bubble because the device is low ram & all bubbles are disabled.
11871         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11872         assertEquals(1, notifsAfter.length);
11873         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
11874     }
11875 
11876     @Test
11877     @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
11878     public void testRemoveLargeRemoteViews() throws Exception {
11879         int removeSize = mContext.getResources().getInteger(
11880                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
11881 
11882         RemoteViews rv = mock(RemoteViews.class);
11883         when(rv.estimateMemoryUsage()).thenReturn(removeSize);
11884         when(rv.clone()).thenReturn(rv);
11885         RemoteViews rv1 = mock(RemoteViews.class);
11886         when(rv1.estimateMemoryUsage()).thenReturn(removeSize);
11887         when(rv1.clone()).thenReturn(rv1);
11888         RemoteViews rv2 = mock(RemoteViews.class);
11889         when(rv2.estimateMemoryUsage()).thenReturn(removeSize);
11890         when(rv2.clone()).thenReturn(rv2);
11891         RemoteViews rv3 = mock(RemoteViews.class);
11892         when(rv3.estimateMemoryUsage()).thenReturn(removeSize);
11893         when(rv3.clone()).thenReturn(rv3);
11894         RemoteViews rv4 = mock(RemoteViews.class);
11895         when(rv4.estimateMemoryUsage()).thenReturn(removeSize);
11896         when(rv4.clone()).thenReturn(rv4);
11897         // note: different!
11898         RemoteViews rv5 = mock(RemoteViews.class);
11899         when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1);
11900         when(rv5.clone()).thenReturn(rv5);
11901 
11902         Notification np = new Notification.Builder(mContext, "test")
11903                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
11904                 .setContentText("test")
11905                 .setCustomContentView(rv)
11906                 .setCustomBigContentView(rv1)
11907                 .setCustomHeadsUpContentView(rv2)
11908                 .build();
11909         Notification n = new Notification.Builder(mContext, "test")
11910                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
11911                 .setContentText("test")
11912                 .setCustomContentView(rv3)
11913                 .setCustomBigContentView(rv4)
11914                 .setCustomHeadsUpContentView(rv5)
11915                 .setPublicVersion(np)
11916                 .build();
11917 
11918         assertNotNull(np.contentView);
11919         assertNotNull(np.bigContentView);
11920         assertNotNull(np.headsUpContentView);
11921 
11922         assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
11923         assertNotNull(n.publicVersion.contentView);
11924         assertNotNull(n.publicVersion.bigContentView);
11925         assertNotNull(n.publicVersion.headsUpContentView);
11926 
11927         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
11928 
11929         assertNull(n.contentView);
11930         assertNull(n.bigContentView);
11931         assertNotNull(n.headsUpContentView);
11932         assertNull(n.publicVersion.contentView);
11933         assertNull(n.publicVersion.bigContentView);
11934         assertNull(n.publicVersion.headsUpContentView);
11935 
11936         verify(mUsageStats, times(5)).registerImageRemoved(mPkg);
11937     }
11938 
11939     @Test
11940     @EnableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
11941     public void testRemoveRemoteViews() throws Exception {
11942         Notification np = new Notification.Builder(mContext, "test")
11943                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
11944                 .setContentText("test")
11945                 .setCustomContentView(mock(RemoteViews.class))
11946                 .setCustomBigContentView(mock(RemoteViews.class))
11947                 .setCustomHeadsUpContentView(mock(RemoteViews.class))
11948                 .build();
11949         Notification n = new Notification.Builder(mContext, "test")
11950                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
11951                 .setContentText("test")
11952                 .setCustomContentView(mock(RemoteViews.class))
11953                 .setCustomBigContentView(mock(RemoteViews.class))
11954                 .setCustomHeadsUpContentView(mock(RemoteViews.class))
11955                 .setPublicVersion(np)
11956                 .build();
11957 
11958         assertNotNull(n.contentView);
11959         assertNotNull(n.bigContentView);
11960         assertNotNull(n.headsUpContentView);
11961 
11962         assertTrue(np.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
11963         assertNotNull(np.contentView);
11964         assertNotNull(np.bigContentView);
11965         assertNotNull(np.headsUpContentView);
11966 
11967         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
11968 
11969         assertNull(n.contentView);
11970         assertNull(n.bigContentView);
11971         assertNull(n.headsUpContentView);
11972         assertNull(n.publicVersion.contentView);
11973         assertNull(n.publicVersion.bigContentView);
11974         assertNull(n.publicVersion.headsUpContentView);
11975 
11976         verify(mUsageStats, times(1)).registerImageRemoved(mPkg);
11977     }
11978 
11979     @Test
11980     public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground()
11981             throws Exception {
11982         setUpPrefsForBubbles(mPkg, mUid,
11983                 true /* global */,
11984                 BUBBLE_PREFERENCE_ALL /* app */,
11985                 true /* channel */);
11986 
11987         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11988                 "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground");
11989         // Modify metadata flags
11990         nr.getSbn().getNotification().getBubbleMetadata().setFlags(
11991                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
11992                         | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
11993 
11994         // Ensure we're not foreground
11995         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
11996                 IMPORTANCE_VISIBLE);
11997 
11998         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11999                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12000         waitForIdle();
12001 
12002         // yes allowed, yes messaging, yes bubble
12003         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12004         assertTrue(notif.isBubbleNotification());
12005 
12006         // The flag should have failed since we're not foreground
12007         assertFalse(notif.getBubbleMetadata().getAutoExpandBubble());
12008     }
12009 
12010     @Test
12011     public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground()
12012             throws RemoteException {
12013         setUpPrefsForBubbles(mPkg, mUid,
12014                 true /* global */,
12015                 BUBBLE_PREFERENCE_ALL /* app */,
12016                 true /* channel */);
12017 
12018         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12019                 "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground");
12020         // Modify metadata flags
12021         nr.getSbn().getNotification().getBubbleMetadata().setFlags(
12022                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
12023                         | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
12024 
12025         // Ensure we are in the foreground
12026         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
12027                 IMPORTANCE_FOREGROUND);
12028 
12029         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12030                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12031         waitForIdle();
12032 
12033         // yes allowed, yes messaging, yes bubble
12034         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12035         assertTrue(notif.isBubbleNotification());
12036 
12037         // Our flags should have passed since we are foreground
12038         assertTrue(notif.getBubbleMetadata().getAutoExpandBubble());
12039         assertTrue(notif.getBubbleMetadata().isNotificationSuppressed());
12040     }
12041 
12042     @Test
12043     public void testNotificationBubbles_flagRemoved_whenShortcutRemoved()
12044             throws RemoteException {
12045         setUpPrefsForBubbles(mPkg, mUid,
12046                 true /* global */,
12047                 BUBBLE_PREFERENCE_ALL /* app */,
12048                 true /* channel */);
12049 
12050         ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
12051                 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
12052 
12053         // Messaging notification with shortcut info
12054         Notification.BubbleMetadata metadata =
12055                 new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build();
12056         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12057                 null /* groupKey */, false /* isSummary */, true);
12058         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12059         nb.setBubbleMetadata(metadata);
12060         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12061                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12062         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12063 
12064         // Test: Send the bubble notification
12065         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12066                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12067         waitForIdle();
12068 
12069         // Verify:
12070 
12071         // Make sure we register the callback for shortcut changes
12072         verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
12073                 shortcutChangeCallback.capture());
12074 
12075         // yes allowed, yes messaging w/shortcut, yes bubble
12076         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12077         assertTrue(notif.isBubbleNotification());
12078 
12079         // Make sure the shortcut is cached.
12080         verify(mShortcutServiceInternal).cacheShortcuts(
12081                 anyInt(), any(), eq(mPkg), eq(singletonList(VALID_CONVO_SHORTCUT_ID)),
12082                 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
12083 
12084         // Test: Remove the shortcut
12085         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12086         ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>();
12087         removedShortcuts.add(createMockConvoShortcut());
12088         shortcutChangeCallback.getValue().onShortcutsRemoved(mPkg, removedShortcuts,
12089                 UserHandle.getUserHandleForUid(mUid));
12090         waitForIdle();
12091 
12092         // Verify:
12093 
12094         // Make sure callback is unregistered
12095         verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
12096                 shortcutChangeCallback.getValue());
12097 
12098         // We're no longer a bubble
12099         NotificationRecord notif2 = mService.getNotificationRecord(
12100                 nr.getSbn().getKey());
12101         assertNull(notif2.getShortcutInfo());
12102         assertFalse(notif2.getNotification().isBubbleNotification());
12103     }
12104 
12105     @Test
12106     public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved()
12107             throws RemoteException {
12108         final String shortcutId = "someshortcutId";
12109         setUpPrefsForBubbles(mPkg, mUid,
12110                 true /* global */,
12111                 BUBBLE_PREFERENCE_ALL /* app */,
12112                 true /* channel */);
12113 
12114         ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
12115                 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
12116 
12117         // Messaging notification with shortcut info
12118         Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
12119                 shortcutId).build();
12120         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12121                 null /* groupKey */, false /* isSummary */, true);
12122         nb.setShortcutId(shortcutId);
12123         nb.setBubbleMetadata(metadata);
12124         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12125                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12126         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12127 
12128         // Pretend the shortcut exists
12129         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
12130         ShortcutInfo info = mock(ShortcutInfo.class);
12131         when(info.getPackage()).thenReturn(mPkg);
12132         when(info.getId()).thenReturn(shortcutId);
12133         when(info.getUserId()).thenReturn(USER_SYSTEM);
12134         when(info.isLongLived()).thenReturn(true);
12135         when(info.isEnabled()).thenReturn(true);
12136         shortcutInfos.add(info);
12137         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
12138         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
12139                 anyString(), anyInt(), any())).thenReturn(true);
12140 
12141         // Test: Send the bubble notification
12142         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12143                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12144         waitForIdle();
12145 
12146         // Verify:
12147 
12148         // Make sure we register the callback for shortcut changes
12149         verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
12150                 shortcutChangeCallback.capture());
12151 
12152         // yes allowed, yes messaging w/shortcut, yes bubble
12153         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12154         assertTrue(notif.isBubbleNotification());
12155 
12156         // Make sure the shortcut is cached.
12157         verify(mShortcutServiceInternal).cacheShortcuts(
12158                 anyInt(), any(), eq(mPkg), eq(singletonList(shortcutId)),
12159                 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
12160 
12161         // Test: Remove the notification
12162         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12163                 nr.getSbn().getId(), nr.getSbn().getUserId());
12164         waitForIdle();
12165 
12166         // Verify:
12167 
12168         // Make sure callback is unregistered
12169         verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
12170                 shortcutChangeCallback.getValue());
12171     }
12172 
12173     @Test
12174     public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed()
12175             throws Exception {
12176         setUpPrefsForBubbles(mPkg, mUid,
12177                 true /* global */,
12178                 BUBBLE_PREFERENCE_ALL /* app */,
12179                 true /* channel */);
12180 
12181         NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
12182                 true /* summaryAutoCancel */);
12183 
12184         // Dismiss summary
12185         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
12186                 true);
12187         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg,
12188                 nrSummary.getUserId(), nrSummary.getKey(),
12189                 NotificationStats.DISMISSAL_SHADE,
12190                 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv);
12191         waitForIdle();
12192 
12193         // The bubble should still exist
12194         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12195         assertEquals(1, notifsAfter.length);
12196     }
12197 
12198     @Test
12199     public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked()
12200             throws Exception {
12201         setUpPrefsForBubbles(mPkg, mUid,
12202                 true /* global */,
12203                 BUBBLE_PREFERENCE_ALL /* app */,
12204                 true /* channel */);
12205 
12206         NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
12207                 true /* summaryAutoCancel */);
12208 
12209         // Click summary
12210         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
12211                 true);
12212         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
12213                 nrSummary.getKey(), nv);
12214         waitForIdle();
12215 
12216         // The bubble should still exist
12217         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12218         assertEquals(1, notifsAfter.length);
12219 
12220         // Check we got the click log and associated dismissal logs
12221         assertEquals(6, mNotificationRecordLogger.numCalls());
12222         // Skip the notification-creation logs
12223         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
12224                 mNotificationRecordLogger.event(3));
12225         assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK,
12226                 mNotificationRecordLogger.event(4));
12227         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
12228                         .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED,
12229                 mNotificationRecordLogger.event(5));
12230     }
12231 
12232     @Test
12233     public void testNotificationBubbles_bubbleStays_whenClicked()
12234             throws Exception {
12235         setUpPrefsForBubbles(mPkg, mUid,
12236                 true /* global */,
12237                 BUBBLE_PREFERENCE_ALL /* app */,
12238                 true /* channel */);
12239 
12240         // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble
12241         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
12242         nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL;
12243         mService.addNotification(nr);
12244 
12245         // WHEN we click the notification
12246         final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true);
12247         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
12248                 nr.getKey(), nv);
12249         waitForIdle();
12250 
12251         // THEN the bubble should still exist
12252         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12253         assertEquals(1, notifsAfter.length);
12254 
12255         // Check we got the click log
12256         assertEquals(1, mNotificationRecordLogger.numCalls());
12257         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
12258                 mNotificationRecordLogger.event(0));
12259     }
12260 
12261     /**
12262      * When something is bubble'd and the bubble is dismissed, but the notification is still
12263      * visible, clicking on the notification shouldn't auto-cancel it because clicking on
12264      * it will produce a bubble.
12265      */
12266     @Test
12267     public void testNotificationBubbles_bubbleStays_whenClicked_afterBubbleDismissed()
12268             throws Exception {
12269         setUpPrefsForBubbles(mPkg, mUid,
12270                 true /* global */,
12271                 BUBBLE_PREFERENCE_ALL /* app */,
12272                 true /* channel */);
12273 
12274         // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble
12275         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
12276         nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL;
12277         nr.setAllowBubble(true);
12278         mService.addNotification(nr);
12279 
12280         // And the bubble is dismissed
12281         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(),
12282                 false /* isBubble */, 0 /* bubbleFlags */);
12283         waitForIdle();
12284         assertTrue(nr.isFlagBubbleRemoved());
12285 
12286         // WHEN we click the notification
12287         final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true);
12288         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
12289                 nr.getKey(), nv);
12290         waitForIdle();
12291 
12292         // THEN the bubble should still exist
12293         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12294         assertEquals(1, notifsAfter.length);
12295 
12296         // Check we got the click log
12297         assertEquals(1, mNotificationRecordLogger.numCalls());
12298         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
12299                 mNotificationRecordLogger.event(0));
12300     }
12301 
12302     @Test
12303     public void testLoadDefaultApprovedServices_emptyResources() {
12304         TestableResources tr = mContext.getOrCreateTestableResources();
12305         tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, "");
12306         tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "");
12307         tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, "");
12308 
12309         mService.loadDefaultApprovedServices(USER_SYSTEM);
12310 
12311         verify(mListeners, never()).addDefaultComponentOrPackage(anyString());
12312         verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString());
12313         verify(mAssistants, never()).addDefaultComponentOrPackage(anyString());
12314     }
12315 
12316     @Test
12317     public void testLoadDefaultApprovedServices_dnd() {
12318         TestableResources tr = mContext.getOrCreateTestableResources();
12319         tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test");
12320         when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
12321                 .thenReturn(new ArraySet<>());
12322 
12323         mService.loadDefaultApprovedServices(USER_SYSTEM);
12324 
12325         verify(mConditionProviders, times(1)).loadDefaultsFromConfig();
12326     }
12327 
12328     // TODO: add tests for the rest of the non-empty cases
12329 
12330     @Test
12331     public void testOnUnlockUser() {
12332         UserInfo ui = new UserInfo();
12333         ui.id = 10;
12334         mService.onUserUnlocked(new TargetUser(ui));
12335         waitForIdle();
12336 
12337         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
12338     }
12339 
12340     @Test
12341     public void testOnStopUser() {
12342         UserInfo ui = new UserInfo();
12343         ui.id = 10;
12344         mService.onUserStopping(new TargetUser(ui));
12345         waitForIdle();
12346 
12347         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
12348     }
12349 
12350     @Test
12351     public void testHandleOnPackageChanged() {
12352         String[] pkgs = new String[] {mPkg, PKG_N_MR1};
12353         int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1};
12354 
12355         mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids);
12356 
12357         verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString());
12358 
12359         mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids);
12360 
12361         verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]);
12362         verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]);
12363     }
12364 
12365     @Test
12366     public void testHandleOnPackageRemoved_ClearsHistory() throws Exception {
12367         // Enables Notification History setting
12368         setUpPrefsForHistory(mUserId, true /* =enabled */);
12369 
12370         // Posts a notification to the mTestNotificationChannel.
12371         final NotificationRecord notif = generateNotificationRecord(
12372                 mTestNotificationChannel, 1, null, false);
12373         mService.addNotification(notif);
12374         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(
12375                 notif.getSbn().getPackageName());
12376         assertEquals(1, notifs.length);
12377 
12378         // Cancels all notifications.
12379         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
12380                 notif.getUserId(), REASON_CANCEL);
12381         waitForIdle();
12382         notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
12383         assertEquals(0, notifs.length);
12384 
12385         // Checks that notification history's recently canceled archive contains the notification.
12386         notifs = mBinderService.getHistoricalNotificationsWithAttribution(mPkg,
12387                         mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
12388         waitForIdle();
12389         assertEquals(1, notifs.length);
12390 
12391         // Remove sthe package that contained the channel
12392         simulatePackageRemovedBroadcast(mPkg, mUid);
12393         waitForIdle();
12394 
12395         // Checks that notification history no longer contains the notification.
12396         notifs = mBinderService.getHistoricalNotificationsWithAttribution(
12397                 mPkg, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
12398         waitForIdle();
12399         assertEquals(0, notifs.length);
12400     }
12401 
12402     @Test
12403     public void testNotificationHistory_addNoisyNotification() throws Exception {
12404         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
12405                 null /* tvExtender */);
12406         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12407                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12408         waitForIdle();
12409 
12410         verify(mHistoryManager, times(1)).addNotification(any());
12411     }
12412 
12413     @Test
12414     public void createConversationNotificationChannel() throws Exception {
12415         int userId = UserManager.isHeadlessSystemUserMode()
12416                 ? UserHandle.getUserId(UID_HEADLESS)
12417                 : USER_SYSTEM;
12418 
12419         NotificationChannel original = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
12420         original.setAllowBubbles(!original.canBubble());
12421         original.setShowBadge(!original.canShowBadge());
12422 
12423         Parcel parcel = Parcel.obtain();
12424         original.writeToParcel(parcel, 0);
12425         parcel.setDataPosition(0);
12426         NotificationChannel orig = NotificationChannel.CREATOR.createFromParcel(parcel);
12427         assertEquals(original, orig);
12428         assertFalse(TextUtils.isEmpty(orig.getName()));
12429 
12430         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(Arrays.asList(
12431                 orig)));
12432 
12433         mBinderService.createConversationNotificationChannelForPackage(
12434                 mPkg, mUid, orig, "friend");
12435 
12436         NotificationChannel friendChannel = mBinderService.getConversationNotificationChannel(
12437                 mPkg, userId, mPkg, original.getId(), false, "friend");
12438 
12439         assertEquals(original.getName(), friendChannel.getName());
12440         assertEquals(original.getId(), friendChannel.getParentChannelId());
12441         assertEquals("friend", friendChannel.getConversationId());
12442         assertEquals(null, original.getConversationId());
12443         assertEquals(original.canShowBadge(), friendChannel.canShowBadge());
12444         assertFalse(friendChannel.canBubble()); // can't be modified by app
12445         assertFalse(original.getId().equals(friendChannel.getId()));
12446         assertNotNull(friendChannel.getId());
12447     }
12448 
12449     @Test
12450     public void testCorrectCategory_systemOn_appCannotTurnOff() {
12451         int requested = 0;
12452         int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12453 
12454         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12455                 system);
12456 
12457         assertEquals(PRIORITY_CATEGORY_CONVERSATIONS, actual);
12458     }
12459 
12460     @Test
12461     public void testCorrectCategory_systemOff_appTurnOff_noChanges() {
12462         int requested = PRIORITY_CATEGORY_CALLS;
12463         int system = PRIORITY_CATEGORY_CALLS;
12464 
12465         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12466                 system);
12467 
12468         assertEquals(PRIORITY_CATEGORY_CALLS, actual);
12469     }
12470 
12471     @Test
12472     public void testCorrectCategory_systemOn_appTurnOn_noChanges() {
12473         int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12474         int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12475 
12476         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12477                 system);
12478 
12479         assertEquals(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS, actual);
12480     }
12481 
12482     @Test
12483     public void testCorrectCategory_systemOff_appCannotTurnOn() {
12484         int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12485         int system = PRIORITY_CATEGORY_CALLS;
12486 
12487         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12488                 system);
12489 
12490         assertEquals(PRIORITY_CATEGORY_CALLS, actual);
12491     }
12492 
12493     @Test
12494     public void testRestoreConversationChannel_deleted() throws Exception {
12495         // Create parent channel
12496         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12497         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12498                 IMPORTANCE_DEFAULT);
12499         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12500                 NotificationChannel.CREATOR);
12501         assertEquals(originalChannel, parentChannel);
12502         mBinderService.createNotificationChannels(mPkg,
12503                 new ParceledListSlice(Arrays.asList(parentChannel)));
12504 
12505         //Create deleted conversation channel
12506         mBinderService.createConversationNotificationChannelForPackage(
12507                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
12508         final NotificationChannel conversationChannel =
12509                 mBinderService.getConversationNotificationChannel(
12510                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
12511         conversationChannel.setDeleted(true);
12512 
12513         //Create notification record
12514         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12515                 null /* groupKey */, false /* isSummary */, true);
12516         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12517         nb.setChannelId(originalChannel.getId());
12518         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12519                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12520         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12521         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12522 
12523         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12524                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12525         waitForIdle();
12526 
12527         // Verify that the channel was changed to the conversation channel and restored
12528         assertThat(mService.getNotificationRecord(nr.getKey()).isConversation()).isTrue();
12529         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
12530                 conversationChannel);
12531         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().isDeleted()).isFalse();
12532         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().getDeletedTimeMs())
12533                 .isEqualTo(-1);
12534     }
12535 
12536     @Test
12537     public void testDoNotRestoreParentChannel_deleted() throws Exception {
12538         // Create parent channel and set as deleted
12539         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12540         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12541                 IMPORTANCE_DEFAULT);
12542         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12543                 NotificationChannel.CREATOR);
12544         assertEquals(originalChannel, parentChannel);
12545         mBinderService.createNotificationChannels(mPkg,
12546                 new ParceledListSlice(Arrays.asList(parentChannel)));
12547         parentChannel.setDeleted(true);
12548 
12549         //Create notification record
12550         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12551                 null /* groupKey */, false /* isSummary */, true);
12552         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12553         nb.setChannelId(originalChannel.getId());
12554         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12555                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12556         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12557         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12558 
12559         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
12560 
12561         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12562                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12563         waitForIdle();
12564 
12565         // Verify that the channel was not restored and the notification was not posted
12566         assertThat(mService.mChannelToastsSent).contains(mUid);
12567         assertThat(mService.getNotificationRecord(nr.getKey())).isNull();
12568         assertThat(parentChannel.isDeleted()).isTrue();
12569     }
12570 
12571     @Test
12572     public void testEnqueueToConversationChannel_notDeleted_doesNotRestore() throws Exception {
12573         TestableNotificationManagerService service = spy(mService);
12574         PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper);
12575         service.setPreferencesHelper(preferencesHelper);
12576         // Create parent channel
12577         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12578         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12579                 IMPORTANCE_DEFAULT);
12580         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12581                 NotificationChannel.CREATOR);
12582         assertEquals(originalChannel, parentChannel);
12583         mBinderService.createNotificationChannels(mPkg,
12584                 new ParceledListSlice(Arrays.asList(parentChannel)));
12585 
12586         //Create conversation channel
12587         mBinderService.createConversationNotificationChannelForPackage(
12588                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
12589         final NotificationChannel conversationChannel =
12590                 mBinderService.getConversationNotificationChannel(
12591                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
12592 
12593         //Create notification record
12594         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12595                 null /* groupKey */, false /* isSummary */, true);
12596         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12597         nb.setChannelId(originalChannel.getId());
12598         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12599                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12600         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12601         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12602 
12603         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12604                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12605         waitForIdle();
12606 
12607         // Verify that the channel was changed to the conversation channel and not restored
12608         assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isTrue();
12609         assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
12610                 conversationChannel);
12611         verify(service, never()).handleSavePolicyFile();
12612         verify(preferencesHelper, never()).createNotificationChannel(anyString(),
12613                 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean());
12614     }
12615 
12616     @Test
12617     public void testEnqueueToParentChannel_notDeleted_doesNotRestore() throws Exception {
12618         TestableNotificationManagerService service = spy(mService);
12619         PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper);
12620         service.setPreferencesHelper(preferencesHelper);
12621         // Create parent channel
12622         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12623         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12624                 IMPORTANCE_DEFAULT);
12625         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12626                 NotificationChannel.CREATOR);
12627         assertEquals(originalChannel, parentChannel);
12628         mBinderService.createNotificationChannels(mPkg,
12629                 new ParceledListSlice(Arrays.asList(parentChannel)));
12630 
12631         //Create deleted conversation channel
12632         mBinderService.createConversationNotificationChannelForPackage(
12633                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
12634         final NotificationChannel conversationChannel =
12635                 mBinderService.getConversationNotificationChannel(
12636                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
12637 
12638         //Create notification record without a shortcutId
12639         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12640                 null /* groupKey */, false /* isSummary */, true);
12641         nb.setShortcutId(null);
12642         nb.setChannelId(originalChannel.getId());
12643         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12644                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12645         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12646         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12647 
12648         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12649                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12650         waitForIdle();
12651 
12652         // Verify that the channel is the parent channel and no channel was restored
12653         //assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isFalse();
12654         assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
12655                 parentChannel);
12656         verify(service, never()).handleSavePolicyFile();
12657         verify(preferencesHelper, never()).createNotificationChannel(anyString(),
12658                 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean());
12659     }
12660 
12661     @Test
12662     public void testGetConversationsForPackage_hasShortcut() throws Exception {
12663         mService.setPreferencesHelper(mPreferencesHelper);
12664         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
12665         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
12666         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
12667         channel1.setConversationId("parent1", "convo 1");
12668         convo1.setNotificationChannel(channel1);
12669         convos.add(convo1);
12670 
12671         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
12672         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
12673         channel2.setConversationId("parent1", "convo 2");
12674         convo2.setNotificationChannel(channel2);
12675         convos.add(convo2);
12676         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
12677 
12678         ShortcutInfo si = mock(ShortcutInfo.class);
12679         when(si.getPackage()).thenReturn(PKG_P);
12680         when(si.getId()).thenReturn("convo");
12681         when(si.getUserId()).thenReturn(USER_SYSTEM);
12682         when(si.getLabel()).thenReturn("Hello");
12683         when(si.isLongLived()).thenReturn(true);
12684         when(si.isEnabled()).thenReturn(true);
12685         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
12686         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
12687                 anyString(), anyInt(), any())).thenReturn(true);
12688 
12689         List<ConversationChannelWrapper> conversations =
12690                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12691         assertEquals(si, conversations.get(0).getShortcutInfo());
12692         assertEquals(si, conversations.get(1).getShortcutInfo());
12693 
12694         // Returns null shortcuts when locked.
12695         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(false);
12696         conversations =
12697                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12698         assertThat(conversations.get(0).getShortcutInfo()).isNull();
12699         assertThat(conversations.get(1).getShortcutInfo()).isNull();
12700     }
12701 
12702     @Test
12703     public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception {
12704         mService.setPreferencesHelper(mPreferencesHelper);
12705         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
12706         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
12707         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
12708         channel1.setConversationId("parent1", "convo 1");
12709         convo1.setNotificationChannel(channel1);
12710         convos.add(convo1);
12711 
12712         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
12713         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
12714         channel2.setConversationId("parent1", "convo 2");
12715         convo2.setNotificationChannel(channel2);
12716         convos.add(convo2);
12717         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
12718 
12719         ShortcutInfo si = mock(ShortcutInfo.class);
12720         when(si.getPackage()).thenReturn(PKG_P);
12721         when(si.getId()).thenReturn("convo");
12722         when(si.getUserId()).thenReturn(USER_SYSTEM);
12723         when(si.getLabel()).thenReturn("Hello");
12724         when(si.isLongLived()).thenReturn(false);
12725         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
12726 
12727         List<ConversationChannelWrapper> conversations =
12728                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12729         assertNull(conversations.get(0).getShortcutInfo());
12730         assertNull(conversations.get(1).getShortcutInfo());
12731     }
12732 
12733     @Test
12734     public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception {
12735         mService.setPreferencesHelper(mPreferencesHelper);
12736         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
12737         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
12738         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
12739         channel1.setConversationId("parent1", "convo 1");
12740         convo1.setNotificationChannel(channel1);
12741         convos.add(convo1);
12742 
12743         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
12744         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
12745         channel2.setConversationId("parent1", "convo 2");
12746         convo2.setNotificationChannel(channel2);
12747         convos.add(convo2);
12748         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
12749         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12750 
12751         List<ConversationChannelWrapper> conversations =
12752                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12753         assertNull(conversations.get(0).getShortcutInfo());
12754         assertNull(conversations.get(1).getShortcutInfo());
12755     }
12756 
12757     @Test
12758     public void testShortcutHelperNull_doesntCrashEnqueue() throws RemoteException {
12759         mService.setShortcutHelper(null);
12760         NotificationRecord nr =
12761                 generateMessageBubbleNotifRecord(mTestNotificationChannel,
12762                         "testShortcutHelperNull_doesntCrashEnqueue");
12763         try {
12764             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12765                     nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12766             waitForIdle();
12767         } catch (Exception e) {
12768             fail(e.getMessage());
12769         }
12770     }
12771 
12772     @Test
12773     public void testRecordMessages_invalidMsg() throws RemoteException {
12774         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12775                 null /* groupKey */, false /* isSummary */, true);
12776         nb.setShortcutId(null);
12777         StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
12778                 "testRecordMessages_invalidMsg", mUid, 0, nb.build(),
12779                 UserHandle.getUserHandleForUid(mUid), null, 0);
12780         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12781 
12782         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12783         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
12784                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12785         waitForIdle();
12786 
12787         assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
12788     }
12789 
12790     @Test
12791     public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException {
12792         Notification.Builder nb = new Notification.Builder(mContext,
12793                 mTestNotificationChannel.getId())
12794                 .setContentTitle("foo")
12795                 .setShortcutId(null)
12796                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12797                 .setCategory(Notification.CATEGORY_MESSAGE);
12798         StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1,
12799                 "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(),
12800                 UserHandle.getUserHandleForUid(mUid), null, 0);
12801         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12802 
12803         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12804         mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(),
12805                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12806         waitForIdle();
12807 
12808         // PKG_O is allowed to be in conversation space b/c of override in
12809         // TestableNotificationManagerService
12810         assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid));
12811     }
12812 
12813     @Test
12814     public void testRecordMessages_validMsg() throws RemoteException {
12815         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12816                 null /* groupKey */, false /* isSummary */, true);
12817         nb.setShortcutId(null);
12818         StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
12819                 "testRecordMessages_validMsg", mUid, 0, nb.build(),
12820                 UserHandle.getUserHandleForUid(mUid), null, 0);
12821         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12822 
12823         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
12824                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12825         waitForIdle();
12826 
12827         assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
12828 
12829         nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12830                 "testRecordMessages_validMsg");
12831 
12832         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
12833                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12834         waitForIdle();
12835 
12836         assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid));
12837     }
12838 
12839     @Test
12840     public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException {
12841         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12842                 "testRecordMessages_invalidMsg_afterValidMsg_1");
12843         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12844                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12845         waitForIdle();
12846         assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation());
12847 
12848         mBinderService.cancelAllNotifications(mPkg, mUid);
12849         waitForIdle();
12850 
12851         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12852                 null /* groupKey */, false /* isSummary */, true);
12853         nb.setShortcutId(null);
12854         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12855                 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
12856                 UserHandle.getUserHandleForUid(mUid), null, 0);
12857          nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12858 
12859         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12860                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12861         waitForIdle();
12862 
12863         assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation());
12864     }
12865 
12866     @Test
12867     public void testCanPostFgsWhenOverLimit() throws RemoteException {
12868         when(mAmi.applyForegroundServiceNotification(
12869                 any(), anyString(), anyInt(), anyString(), anyInt()))
12870                 .thenReturn(SHOW_IMMEDIATELY);
12871         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
12872             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
12873                     i, null, false).getSbn();
12874             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12875                     "testCanPostFgsWhenOverLimit",
12876                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
12877         }
12878 
12879         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
12880         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
12881         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12882                 "testCanPostFgsWhenOverLimit - fgs over limit!",
12883                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
12884 
12885         waitForIdle();
12886 
12887         StatusBarNotification[] notifs =
12888                 mBinderService.getActiveNotifications(sbn.getPackageName());
12889         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
12890         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
12891                 mService.getNotificationRecordCount());
12892     }
12893 
12894     @Test
12895     public void testCannotPostNonFgsWhenOverLimit() throws RemoteException {
12896         when(mAmi.applyForegroundServiceNotification(
12897                 any(), anyString(), anyInt(), anyString(), anyInt()))
12898                 .thenReturn(SHOW_IMMEDIATELY);
12899         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
12900             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
12901                     i, null, false).getSbn();
12902             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12903                     "testCanPostFgsWhenOverLimit",
12904                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
12905             waitForIdle();
12906         }
12907 
12908         final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
12909                 100, null, false).getSbn();
12910         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
12911         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12912                 "testCanPostFgsWhenOverLimit - fgs over limit!",
12913                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
12914 
12915         final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
12916                 101, null, false).getSbn();
12917         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12918                 "testCanPostFgsWhenOverLimit - non fgs over limit!",
12919                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
12920 
12921 
12922         when(mAmi.applyForegroundServiceNotification(
12923                 any(), anyString(), anyInt(), anyString(), anyInt()))
12924                 .thenReturn(NOT_FOREGROUND_SERVICE);
12925         final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
12926                 101, null, false).getSbn();
12927         sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
12928         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12929                 "testCanPostFgsWhenOverLimit - fake fgs over limit!",
12930                 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
12931 
12932         waitForIdle();
12933 
12934         StatusBarNotification[] notifs =
12935                 mBinderService.getActiveNotifications(sbn.getPackageName());
12936         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
12937         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
12938                 mService.getNotificationRecordCount());
12939     }
12940 
12941     @Test
12942     public void testIsVisibleToListener_notEnabled() {
12943         StatusBarNotification sbn = mock(StatusBarNotification.class);
12944         when(sbn.getUserId()).thenReturn(10);
12945         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12946         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
12947         info.userid = 10;
12948         when(info.isSameUser(anyInt())).thenReturn(true);
12949         when(assistant.isSameUser(anyInt())).thenReturn(true);
12950         when(info.enabledAndUserMatches(info.userid)).thenReturn(false);
12951         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
12952 
12953         assertFalse(mService.isVisibleToListener(sbn, 0, info));
12954     }
12955 
12956     @Test
12957     public void testIsVisibleToListener_noAssistant() {
12958         StatusBarNotification sbn = mock(StatusBarNotification.class);
12959         when(sbn.getUserId()).thenReturn(10);
12960         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12961         info.userid = 10;
12962         when(info.isSameUser(anyInt())).thenReturn(true);
12963         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
12964         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null);
12965 
12966         assertTrue(mService.isVisibleToListener(sbn, 0, info));
12967     }
12968 
12969     @Test
12970     public void testIsVisibleToListener_assistant_differentUser() {
12971         StatusBarNotification sbn = mock(StatusBarNotification.class);
12972         when(sbn.getUserId()).thenReturn(10);
12973         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12974         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
12975         info.userid = 0;
12976         when(info.isSameUser(anyInt())).thenReturn(true);
12977         when(assistant.isSameUser(anyInt())).thenReturn(true);
12978         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
12979         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
12980 
12981         assertFalse(mService.isVisibleToListener(sbn, 0, info));
12982     }
12983 
12984     @Test
12985     public void testIsVisibleToListener_assistant_sameUser() {
12986         StatusBarNotification sbn = mock(StatusBarNotification.class);
12987         when(sbn.getUserId()).thenReturn(10);
12988         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
12989         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
12990         info.userid = 10;
12991         when(info.isSameUser(anyInt())).thenReturn(true);
12992         when(assistant.isSameUser(anyInt())).thenReturn(true);
12993         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
12994         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
12995 
12996         assertTrue(mService.isVisibleToListener(sbn, 0, info));
12997     }
12998 
12999     @Test
13000     public void testIsVisibleToListener_mismatchedType() {
13001         when(mNlf.isTypeAllowed(anyInt())).thenReturn(false);
13002 
13003         StatusBarNotification sbn = mock(StatusBarNotification.class);
13004         when(sbn.getUserId()).thenReturn(10);
13005         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13006         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
13007         info.userid = 10;
13008         when(info.isSameUser(anyInt())).thenReturn(true);
13009         when(assistant.isSameUser(anyInt())).thenReturn(true);
13010         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13011         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13012 
13013         assertFalse(mService.isVisibleToListener(sbn, 0, info));
13014     }
13015 
13016     @Test
13017     public void testIsVisibleToListener_disallowedPackage() {
13018         when(mNlf.isPackageAllowed(any())).thenReturn(false);
13019 
13020         StatusBarNotification sbn = mock(StatusBarNotification.class);
13021         when(sbn.getUserId()).thenReturn(10);
13022         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13023         ManagedServices.ManagedServiceInfo assistant =
13024                 mock(ManagedServices.ManagedServiceInfo.class);
13025         info.userid = 10;
13026         when(info.isSameUser(anyInt())).thenReturn(true);
13027         when(assistant.isSameUser(anyInt())).thenReturn(true);
13028         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13029         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13030 
13031         assertFalse(mService.isVisibleToListener(sbn, 0, info));
13032     }
13033 
13034     @Test
13035     public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() {
13036         final NotificationRecord parent = spy(generateNotificationRecord(
13037                 mTestNotificationChannel, 1, "group", true));
13038         final NotificationRecord child = spy(generateNotificationRecord(
13039                 mTestNotificationChannel, 2, "group", false));
13040         mService.addNotification(parent);
13041         mService.addNotification(child);
13042 
13043         InOrder inOrder = inOrder(parent, child);
13044 
13045         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
13046                 parent.getUserId());
13047         waitForIdle();
13048         inOrder.verify(parent).recordDismissalSentiment(anyInt());
13049         inOrder.verify(child).recordDismissalSentiment(anyInt());
13050     }
13051 
13052     @Test
13053     public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() {
13054         final NotificationRecord parent = spy(generateNotificationRecord(
13055                 mTestNotificationChannel, 1, "group", true));
13056         final NotificationRecord child = spy(generateNotificationRecord(
13057                 mTestNotificationChannel, 2, "group", false));
13058         mService.addNotification(child);
13059         mService.addNotification(parent);
13060 
13061         InOrder inOrder = inOrder(parent, child);
13062 
13063         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
13064                 parent.getUserId());
13065         waitForIdle();
13066         inOrder.verify(parent).recordDismissalSentiment(anyInt());
13067         inOrder.verify(child).recordDismissalSentiment(anyInt());
13068     }
13069 
13070     @Test
13071     public void testImmutableBubbleIntent() throws Exception {
13072         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13073         NotificationRecord r = generateMessageBubbleNotifRecord(true,
13074                 mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false, false);
13075         try {
13076             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13077                     r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13078 
13079             waitForIdle();
13080             fail("Allowed a bubble with an immutable intent to be posted");
13081         } catch (IllegalArgumentException e) {
13082             // good
13083         }
13084     }
13085 
13086     @Test
13087     public void testMutableBubbleIntent() throws Exception {
13088         NotificationRecord r = generateMessageBubbleNotifRecord(true,
13089                 mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false, true);
13090 
13091         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13092                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13093 
13094         waitForIdle();
13095         StatusBarNotification[] notifs =
13096                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
13097         assertEquals(1, notifs.length);
13098     }
13099 
13100     @Test
13101     public void testImmutableDirectReplyActionIntent() throws Exception {
13102         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13103         NotificationRecord r = generateMessageBubbleNotifRecord(false,
13104                 mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false,
13105                 false);
13106         try {
13107             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13108                     r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13109 
13110             waitForIdle();
13111             fail("Allowed a direct reply with an immutable intent to be posted");
13112         } catch (IllegalArgumentException e) {
13113             // good
13114         }
13115     }
13116 
13117     @Test
13118     public void testMutableDirectReplyActionIntent() throws Exception {
13119         NotificationRecord r = generateMessageBubbleNotifRecord(false,
13120                 mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false,
13121                 true);
13122         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13123                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13124 
13125         waitForIdle();
13126         StatusBarNotification[] notifs =
13127                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
13128         assertEquals(1, notifs.length);
13129     }
13130 
13131     @Test
13132     public void testImmutableDirectReplyContextualActionIntent() throws Exception {
13133         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13134         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13135 
13136         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13137         ArrayList<Notification.Action> extraAction = new ArrayList<>();
13138         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
13139         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
13140         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
13141                 mActivityIntentImmutable).addRemoteInput(remoteInput)
13142                 .build();
13143         extraAction.add(replyAction);
13144         Bundle signals = new Bundle();
13145         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
13146         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
13147                 r.getUser());
13148         r.addAdjustment(adjustment);
13149         r.applyAdjustments();
13150 
13151         try {
13152             mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
13153                     r.getSbn().getTag(), r, false, false);
13154             fail("Allowed a contextual direct reply with an immutable intent to be posted");
13155         } catch (IllegalArgumentException e) {
13156             // good
13157         }
13158     }
13159 
13160     @Test
13161     public void testMutableDirectReplyContextualActionIntent() throws Exception {
13162         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13163         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13164         ArrayList<Notification.Action> extraAction = new ArrayList<>();
13165         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
13166         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
13167         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
13168                 mActivityIntent).addRemoteInput(remoteInput)
13169                 .build();
13170         extraAction.add(replyAction);
13171         Bundle signals = new Bundle();
13172         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
13173         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
13174                 r.getUser());
13175         r.addAdjustment(adjustment);
13176         r.applyAdjustments();
13177 
13178         mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
13179                 r.getSbn().getTag(), r, false, false);
13180     }
13181 
13182     @Test
13183     public void testImmutableActionIntent() throws Exception {
13184         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13185         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13186         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13187                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13188 
13189         waitForIdle();
13190         StatusBarNotification[] notifs =
13191                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
13192         assertEquals(1, notifs.length);
13193     }
13194 
13195     @Test
13196     public void testImmutableContextualActionIntent() throws Exception {
13197         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13198         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13199         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13200         ArrayList<Notification.Action> extraAction = new ArrayList<>();
13201         extraAction.add(new Notification.Action(0, "hello", mActivityIntentImmutable));
13202         Bundle signals = new Bundle();
13203         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
13204         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
13205                 r.getUser());
13206         r.addAdjustment(adjustment);
13207         r.applyAdjustments();
13208 
13209         mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
13210                     r.getSbn().getTag(), r, false, false);
13211     }
13212 
13213     @Test
13214     public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception {
13215         int uid = 9000;
13216         int[] userIds = new int[] {mUserId, 1000};
13217         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13218         List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
13219         for (int userId : userIds) {
13220             for (String pkg : disallowedApps) {
13221                 when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++);
13222             }
13223         }
13224 
13225         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
13226                 new NotificationListenerFilter());
13227 
13228         mBinderService.migrateNotificationFilter(null,
13229                 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13230                 disallowedApps);
13231 
13232         ArgumentCaptor<NotificationListenerFilter> captor =
13233                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13234         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13235 
13236         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13237                 captor.getValue().getTypes());
13238         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000)));
13239         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002)));
13240         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003)));
13241 
13242         // hypothetical other user untouched
13243         assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000)));
13244     }
13245 
13246     @Test
13247     public void testMigrateNotificationFilter_invalidPackage() throws Exception {
13248         int[] userIds = new int[] {mUserId, 1000};
13249         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13250         List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
13251         for (int userId : userIds) {
13252             when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow(
13253                     new RemoteException(""));
13254             when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000);
13255             when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001);
13256         }
13257 
13258         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
13259                 new NotificationListenerFilter());
13260 
13261         mBinderService.migrateNotificationFilter(null,
13262                 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13263                 disallowedApps);
13264 
13265         ArgumentCaptor<NotificationListenerFilter> captor =
13266                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13267         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13268 
13269         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13270                 captor.getValue().getTypes());
13271         // valid values stay
13272         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000)));
13273         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001)));
13274         // don't store invalid values
13275         for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) {
13276             assertNotEquals("apples", vp.getPackageName());
13277         }
13278     }
13279 
13280     @Test
13281     public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception {
13282         int[] userIds = new int[] {mUserId};
13283         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13284         List<String> disallowedApps = ImmutableList.of("apples");
13285         when(mPackageManager.getPackageUid("apples", 0, mUserId))
13286                 .thenReturn(1001);
13287 
13288         when(mListeners.getNotificationListenerFilter(any())).thenReturn(null);
13289 
13290         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
13291                 disallowedApps);
13292 
13293         ArgumentCaptor<NotificationListenerFilter> captor =
13294                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13295         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13296 
13297         assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
13298         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
13299     }
13300 
13301     @Test
13302     public void testMigrateNotificationFilter_existingTypeFilter() throws Exception {
13303         int[] userIds = new int[] {mUserId};
13304         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13305         List<String> disallowedApps = ImmutableList.of("apples");
13306         when(mPackageManager.getPackageUid("apples", 0, mUserId))
13307                 .thenReturn(1001);
13308 
13309         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
13310                 new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>()));
13311 
13312         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
13313                 disallowedApps);
13314 
13315         ArgumentCaptor<NotificationListenerFilter> captor =
13316                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13317         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13318 
13319         // type isn't saved but pkg list is
13320         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes());
13321         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
13322     }
13323 
13324     @Test
13325     public void testMigrateNotificationFilter_existingPkgFilter() throws Exception {
13326         int[] userIds = new int[] {mUserId};
13327         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13328         List<String> disallowedApps = ImmutableList.of("apples");
13329         when(mPackageManager.getPackageUid("apples", 0, mUserId))
13330                 .thenReturn(1001);
13331 
13332         NotificationListenerFilter preexisting = new NotificationListenerFilter();
13333         preexisting.addPackage(new VersionedPackage("test", 1002));
13334         when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting);
13335 
13336         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
13337                 disallowedApps);
13338 
13339         ArgumentCaptor<NotificationListenerFilter> captor =
13340                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13341         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13342 
13343         // type is saved but pkg list isn't
13344         assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
13345         assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
13346         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002)));
13347     }
13348 
13349     @Test
13350     public void getPackagesBypassingDnd_blocked()
13351             throws RemoteException, PackageManager.NameNotFoundException {
13352 
13353         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
13354                 NotificationManager.IMPORTANCE_MAX);
13355         NotificationChannel channel2 = new NotificationChannel("id3", "name3",
13356                 NotificationManager.IMPORTANCE_MAX);
13357         NotificationChannel channel3 = new NotificationChannel("id4", "name3",
13358                 NotificationManager.IMPORTANCE_MAX);
13359         channel1.setBypassDnd(true);
13360         channel2.setBypassDnd(true);
13361         channel3.setBypassDnd(false);
13362         // has DND access, so can set bypassDnd attribute
13363         mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
13364                 /*has DND access*/ true, UID_N_MR1, false);
13365         mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true,
13366                 UID_P, false);
13367         mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
13368                 UID_P, false);
13369 
13370         when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P);
13371         when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt()))
13372                 .thenReturn(UID_N_MR1);
13373         when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false);
13374         when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true);
13375 
13376         enableInteractAcrossUsers();
13377         assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList())
13378                 .containsExactly(new ZenBypassingApp(PKG_P, false));
13379     }
13380 
13381     @Test
13382     public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
13383         mService.setPreferencesHelper(mPreferencesHelper);
13384 
13385         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13386 
13387         assertThat(mBinderService.getNotificationChannelsBypassingDnd(mPkg, mUid).getList())
13388                 .isEmpty();
13389         verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid);
13390     }
13391 
13392     @Test
13393     public void testGetPackagesBypassingDnd_empty() throws RemoteException {
13394         mService.setPreferencesHelper(mPreferencesHelper);
13395         List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList();
13396         assertThat(result).isEmpty();
13397     }
13398 
13399     @Test
13400     public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception {
13401         // set the testable NMS to not system uid/appid
13402         mService.isSystemUid = false;
13403         mService.isSystemAppId = false;
13404 
13405         // make sure a caller without listener access or read_contacts permission can't call
13406         // matchesCallFilter.
13407         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
13408         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
13409                 eq("android.permission.READ_CONTACTS"), anyString());
13410 
13411         try {
13412             // shouldn't matter what we're passing in, if we get past this line fail immediately
13413             ((INotificationManager) mService.mService).matchesCallFilter(null);
13414             fail("call to matchesCallFilter with no permissions should fail");
13415         } catch (SecurityException e) {
13416             // pass
13417         }
13418     }
13419 
13420     @Test
13421     public void testMatchesCallFilter_hasSystemPermission() throws Exception {
13422         // set the testable NMS to system uid
13423         mService.isSystemUid = true;
13424 
13425         // make sure caller doesn't have listener access or read_contacts permission
13426         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
13427         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
13428                 eq("android.permission.READ_CONTACTS"), anyString());
13429 
13430         try {
13431             ((INotificationManager) mService.mService).matchesCallFilter(null);
13432             // pass, but check that we actually checked for system permissions
13433             assertTrue(mService.countSystemChecks > 0);
13434         } catch (SecurityException e) {
13435             fail("call to matchesCallFilter with just system permissions should work");
13436         }
13437     }
13438 
13439     @Test
13440     public void testMatchesCallFilter_hasListenerPermission() throws Exception {
13441         mService.isSystemUid = false;
13442         mService.isSystemAppId = false;
13443 
13444         // make sure a caller with only listener access and not read_contacts permission can call
13445         // matchesCallFilter.
13446         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(true);
13447         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
13448                 eq("android.permission.READ_CONTACTS"), anyString());
13449 
13450         try {
13451             ((INotificationManager) mService.mService).matchesCallFilter(null);
13452             // pass, this is not a functionality test
13453         } catch (SecurityException e) {
13454             fail("call to matchesCallFilter with listener permissions should work");
13455         }
13456     }
13457 
13458     @Test
13459     public void testMatchesCallFilter_hasContactsPermission() throws Exception {
13460         mService.isSystemUid = false;
13461         mService.isSystemAppId = false;
13462 
13463         // make sure a caller with only read_contacts permission and not listener access can call
13464         // matchesCallFilter.
13465         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
13466         doNothing().when(mContext).enforceCallingPermission(
13467                 eq("android.permission.READ_CONTACTS"), anyString());
13468 
13469         try {
13470             ((INotificationManager) mService.mService).matchesCallFilter(null);
13471             // pass, this is not a functionality test
13472         } catch (SecurityException e) {
13473             fail("call to matchesCallFilter with listener permissions should work");
13474         }
13475     }
13476 
13477     @Test
13478     public void testMediaNotificationsBypassBlock() throws Exception {
13479         when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
13480                 .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
13481         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13482 
13483         Notification.Builder nb = new Notification.Builder(
13484                 mContext, mTestNotificationChannel.getId())
13485                 .setContentTitle("foo")
13486                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13487                 .addAction(new Notification.Action.Builder(null, "test", null).build());
13488         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13489                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13490         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13491 
13492         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13493 
13494         // normal blocked notifications - blocked
13495         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13496                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13497 
13498         // just using the style - blocked
13499         nb.setStyle(new Notification.MediaStyle());
13500         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13501                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13502         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13503 
13504         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13505                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13506 
13507         // using the style, but incorrect type in session - blocked
13508         nb.setStyle(new Notification.MediaStyle());
13509         Bundle extras = new Bundle();
13510         extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
13511         nb.addExtras(extras);
13512         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13513                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13514         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13515 
13516         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13517                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13518 
13519         // style + media session - bypasses block
13520         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
13521         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13522                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13523         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13524 
13525         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13526                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13527     }
13528 
13529     @Test
13530     public void testMediaNotificationsBypassBlock_atPost() throws Exception {
13531         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
13532         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13533 
13534         Notification.Builder nb = new Notification.Builder(
13535                 mContext, mTestNotificationChannel.getId())
13536                 .setContentTitle("foo")
13537                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13538                 .addAction(new Notification.Action.Builder(null, "test", null).build());
13539         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13540                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13541         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13542 
13543         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
13544 
13545         mService.addEnqueuedNotification(r);
13546         NotificationManagerService.PostNotificationRunnable runnable =
13547                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
13548                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
13549         runnable.run();
13550         waitForIdle();
13551 
13552         verify(mUsageStats).registerBlocked(any());
13553         verify(mUsageStats, never()).registerPostedByApp(any());
13554 
13555         // just using the style - blocked
13556         mService.clearNotifications();
13557         reset(mUsageStats);
13558         nb.setStyle(new Notification.MediaStyle());
13559         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13560                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13561         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13562 
13563         mService.addEnqueuedNotification(r);
13564         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
13565                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
13566         runnable.run();
13567         waitForIdle();
13568 
13569         verify(mUsageStats).registerBlocked(any());
13570         verify(mUsageStats, never()).registerPostedByApp(any());
13571 
13572         // style + media session - bypasses block
13573         mService.clearNotifications();
13574         reset(mUsageStats);
13575         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
13576         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13577                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13578         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13579 
13580         mService.addEnqueuedNotification(r);
13581         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
13582                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
13583         runnable.run();
13584         waitForIdle();
13585 
13586         verify(mUsageStats, never()).registerBlocked(any());
13587         verify(mUsageStats).registerPostedByApp(any());
13588     }
13589 
13590     @Test
13591     public void testCallNotificationsBypassBlock() throws Exception {
13592         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13593 
13594         Notification.Builder nb = new Notification.Builder(
13595                 mContext, mTestNotificationChannel.getId())
13596                 .setContentTitle("foo")
13597                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13598                 .addAction(new Notification.Action.Builder(null, "test", null).build());
13599         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13600                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13601         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13602 
13603         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13604 
13605         // normal blocked notifications - blocked
13606         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13607                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13608 
13609         // just using the style - blocked
13610         Person person = new Person.Builder()
13611                 .setName("caller")
13612                 .build();
13613         nb.setStyle(Notification.CallStyle.forOngoingCall(
13614                 person, mActivityIntent));
13615         nb.setFullScreenIntent(mActivityIntent, true);
13616         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13617                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13618         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13619 
13620         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13621                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13622 
13623         // style + managed call - bypasses block
13624         when(mTelecomManager.isInManagedCall()).thenReturn(true);
13625         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13626                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13627 
13628         // style + self managed call - bypasses block
13629         when(mTelecomManager.isInSelfManagedCall(
13630                 r.getSbn().getPackageName(), UserHandle.ALL)).thenReturn(true);
13631         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13632                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13633 
13634         // set telecom manager to null - blocked
13635         mService.setTelecomManager(null);
13636         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13637                            r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
13638                 .isFalse();
13639 
13640         // set telecom feature to false - blocked
13641         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
13642         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13643                            r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
13644                 .isFalse();
13645 
13646         // telecom manager is not ready - blocked
13647         mService.setTelecomManager(mTelecomManager);
13648         when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
13649         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13650                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
13651                 .isFalse();
13652     }
13653 
13654     @Test
13655     public void testCallNotificationsBypassBlock_atPost() throws Exception {
13656         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
13657         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13658 
13659         Notification.Builder nb =
13660                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
13661                         .setContentTitle("foo")
13662                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
13663                         .addAction(new Notification.Action.Builder(null, "test", null).build());
13664         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13665                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13666         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13667 
13668         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13669 
13670         // normal blocked notifications - blocked
13671         mService.addEnqueuedNotification(r);
13672         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13673                 mPostNotificationTrackerFactory.newTracker(null)).run();
13674         waitForIdle();
13675 
13676         verify(mUsageStats).registerBlocked(any());
13677         verify(mUsageStats, never()).registerPostedByApp(any());
13678 
13679         // just using the style - blocked
13680         mService.clearNotifications();
13681         reset(mUsageStats);
13682         Person person = new Person.Builder().setName("caller").build();
13683         nb.setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent));
13684         nb.setFullScreenIntent(mActivityIntent, true);
13685         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, nb.build(),
13686                 UserHandle.getUserHandleForUid(mUid), null, 0);
13687         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13688 
13689         mService.addEnqueuedNotification(r);
13690         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13691                 mPostNotificationTrackerFactory.newTracker(null)).run();
13692         waitForIdle();
13693 
13694         verify(mUsageStats).registerBlocked(any());
13695         verify(mUsageStats, never()).registerPostedByApp(any());
13696 
13697         // style + managed call - bypasses block
13698         mService.clearNotifications();
13699         reset(mUsageStats);
13700         when(mTelecomManager.isInManagedCall()).thenReturn(true);
13701 
13702         mService.addEnqueuedNotification(r);
13703         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13704                 mPostNotificationTrackerFactory.newTracker(null)).run();
13705         waitForIdle();
13706 
13707         verify(mUsageStats, never()).registerBlocked(any());
13708         verify(mUsageStats).registerPostedByApp(any());
13709 
13710         // style + self managed call - bypasses block
13711         mService.clearNotifications();
13712         reset(mUsageStats);
13713         when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), UserHandle.ALL))
13714                 .thenReturn(true);
13715 
13716         mService.addEnqueuedNotification(r);
13717         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13718                 mPostNotificationTrackerFactory.newTracker(null)).run();
13719         waitForIdle();
13720 
13721         verify(mUsageStats, never()).registerBlocked(any());
13722         verify(mUsageStats).registerPostedByApp(any());
13723 
13724         // set telecom manager to null - notifications should be blocked
13725         // but post notifications runnable should not crash
13726         mService.clearNotifications();
13727         reset(mUsageStats);
13728         mService.setTelecomManager(null);
13729 
13730         mService.addEnqueuedNotification(r);
13731         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13732                 mPostNotificationTrackerFactory.newTracker(null)).run();
13733         waitForIdle();
13734 
13735         verify(mUsageStats).registerBlocked(any());
13736         verify(mUsageStats, never()).registerPostedByApp(any());
13737 
13738         // set FEATURE_TELECOM to false - notifications should be blocked
13739         // but post notifications runnable should not crash
13740         mService.setTelecomManager(mTelecomManager);
13741         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
13742         reset(mUsageStats);
13743         mService.setTelecomManager(null);
13744 
13745         mService.addEnqueuedNotification(r);
13746         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13747                 mPostNotificationTrackerFactory.newTracker(null)).run();
13748         waitForIdle();
13749 
13750         verify(mUsageStats).registerBlocked(any());
13751         verify(mUsageStats, never()).registerPostedByApp(any());
13752 
13753         // telecom is not ready - notifications should be blocked but no crashes
13754         mService.setTelecomManager(mTelecomManager);
13755         when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
13756         reset(mUsageStats);
13757 
13758         mService.addEnqueuedNotification(r);
13759         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13760                 mPostNotificationTrackerFactory.newTracker(null)).run();
13761         waitForIdle();
13762 
13763         verify(mUsageStats).registerBlocked(any());
13764         verify(mUsageStats, never()).registerPostedByApp(any());
13765     }
13766 
13767     @Test
13768     public void testGetAllUsersNotificationPermissions() {
13769         // In this case, there are multiple users each with notification permissions (and also,
13770         // for good measure, some without).
13771         // make sure the collection returned contains info for all of them
13772         final List<UserInfo> userInfos = new ArrayList<>();
13773         userInfos.add(new UserInfo(0, "user0", 0));
13774         userInfos.add(new UserInfo(1, "user1", 0));
13775         userInfos.add(new UserInfo(2, "user2", 0));
13776         when(mUm.getUsers()).thenReturn(userInfos);
13777 
13778         // construct the permissions for each of them
13779         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
13780                 permissions1 = new ArrayMap<>();
13781         permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
13782         permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
13783         permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
13784         permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
13785         when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
13786         when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
13787         when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
13788 
13789         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
13790                 mService.getAllUsersNotificationPermissions();
13791         assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
13792         assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
13793         assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
13794         assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
13795         assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
13796         assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
13797         assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
13798         assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
13799     }
13800 
13801     @Test
13802     public void testGetActiveNotification_filtersUsers() throws Exception {
13803         when(mUm.getProfileIds(mUserId, false)).thenReturn(new int[]{mUserId, 10});
13804 
13805         NotificationRecord nr0 =
13806                 generateNotificationRecord(mTestNotificationChannel, mUserId);
13807         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
13808                 nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());
13809 
13810         NotificationRecord nr10 =
13811                 generateNotificationRecord(mTestNotificationChannel, 10);
13812         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag10",
13813                 nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());
13814 
13815         NotificationRecord nr11 =
13816                 generateNotificationRecord(mTestNotificationChannel, 11);
13817         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag11",
13818                 nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
13819         waitForIdle();
13820 
13821         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
13822         assertEquals(2, notifs.length);
13823         for (StatusBarNotification sbn : notifs) {
13824             if (sbn.getUserId() == 11) {
13825                 fail("leaked data across users");
13826             }
13827         }
13828     }
13829 
13830     @Test
13831     public void testGetActiveNotificationsFromListener_redactNotification() throws Exception {
13832         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
13833         NotificationRecord r =
13834                 generateNotificationRecord(mTestNotificationChannel, 0, 0);
13835         mService.addNotification(r);
13836         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
13837         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
13838         StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
13839         when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted);
13840         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13841         info.userid = 0;
13842         when(info.isSameUser(anyInt())).thenReturn(true);
13843         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
13844         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
13845         List<StatusBarNotification> notifications = mBinderService
13846                 .getActiveNotificationsFromListener(mock(INotificationListener.class), null, -1)
13847                 .getList();
13848 
13849         boolean foundRedactedSbn = false;
13850         for (StatusBarNotification sbn: notifications) {
13851             String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString();
13852             if (REDACTED_TEXT.equals(text)) {
13853                 foundRedactedSbn = true;
13854                 break;
13855             }
13856         }
13857         assertTrue("expect to find a redacted notification", foundRedactedSbn);
13858     }
13859 
13860     @Test
13861     public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception {
13862         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
13863         NotificationRecord r =
13864                 generateNotificationRecord(mTestNotificationChannel, 0, 0);
13865         when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r));
13866         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
13867         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
13868         StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
13869         when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted);
13870         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13871         info.userid = 0;
13872         when(info.isSameUser(anyInt())).thenReturn(true);
13873         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
13874         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
13875         List<StatusBarNotification> notifications = mBinderService
13876                 .getSnoozedNotificationsFromListener(mock(INotificationListener.class), -1)
13877                 .getList();
13878 
13879         boolean foundRedactedSbn = false;
13880         for (StatusBarNotification sbn: notifications) {
13881             String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString();
13882             if (REDACTED_TEXT.equals(text)) {
13883                 foundRedactedSbn = true;
13884                 break;
13885             }
13886         }
13887         assertTrue("expect to find a redacted notification", foundRedactedSbn);
13888     }
13889 
13890     @Test
13891     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
13892     public void testCancelAutogroupSummary_cancelsAllChildren() throws Exception {
13893         final String originalGroupName = "originalGroup";
13894         final String aggregateGroupName = "Aggregate_Test";
13895         final int summaryId = Integer.MAX_VALUE;
13896         // Add 2 group notifications without a summary
13897         NotificationRecord nr0 =
13898                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
13899         NotificationRecord nr1 =
13900                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
13901         mService.addNotification(nr0);
13902         mService.addNotification(nr1);
13903         mService.mSummaryByGroupKey.remove(nr0.getGroupKey());
13904 
13905         // GroupHelper is a mock, so make the calls it would make
13906         // Add aggregate group summary
13907         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
13908                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
13909                 nr0.getChannel().getId());
13910         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
13911                 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
13912         mService.addNotification(aggregateSummary);
13913         nr0.setOverrideGroupKey(aggregateGroupName);
13914         nr1.setOverrideGroupKey(aggregateGroupName);
13915         final String fullAggregateGroupKey = nr0.getGroupKey();
13916 
13917         // Check that the aggregate group summary was created
13918         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
13919         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
13920                 nr0.getChannel().getId());
13921         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
13922 
13923         // Cancel aggregate group summary
13924         mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(),
13925                 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId());
13926         waitForIdle();
13927 
13928         // Check that child notifications are also removed
13929         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary));
13930         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0));
13931         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1));
13932 
13933         // Make sure the summary was removed and not re-posted
13934         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
13935     }
13936 
13937     @Test
13938     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
13939     public void testCancelAutogroupSummary_forceGrouping_cancelsAllChildren() throws Exception {
13940         final String originalGroupName = "originalGroup";
13941         final String aggregateGroupName = "Aggregate_Test";
13942         final int summaryId = Integer.MAX_VALUE;
13943         // Add 2 group notifications without a summary
13944         NotificationRecord nr0 =
13945                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
13946         NotificationRecord nr1 =
13947                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
13948         mService.addNotification(nr0);
13949         mService.addNotification(nr1);
13950         mService.mSummaryByGroupKey.remove(nr0.getGroupKey());
13951 
13952         // GroupHelper is a mock, so make the calls it would make
13953         // Add aggregate group summary
13954         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
13955                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
13956                 nr0.getChannel().getId());
13957         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
13958                 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
13959         mService.addNotification(aggregateSummary);
13960         nr0.setOverrideGroupKey(aggregateGroupName);
13961         nr1.setOverrideGroupKey(aggregateGroupName);
13962         final String fullAggregateGroupKey = nr0.getGroupKey();
13963 
13964         // Check that the aggregate group summary was created
13965         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
13966         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
13967                 nr0.getChannel().getId());
13968         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
13969 
13970         // Cancel aggregate group summary
13971         mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(),
13972                 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId());
13973         waitForIdle();
13974 
13975         // Check that child notifications are also removed
13976         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary), any());
13977         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any());
13978         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any());
13979 
13980         // Make sure the summary was removed and not re-posted
13981         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
13982     }
13983 
13984     @Test
13985     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
13986     public void testUngroupingOngoingAutoSummary() throws Exception {
13987         NotificationRecord nr0 =
13988                 generateNotificationRecord(mTestNotificationChannel, 0);
13989         NotificationRecord nr1 =
13990                 generateNotificationRecord(mTestNotificationChannel, 0);
13991         nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT;
13992 
13993         mService.addNotification(nr0);
13994         mService.addNotification(nr1);
13995 
13996         // grouphelper is a mock here, so make the calls it would make
13997 
13998         // add summary
13999         NotificationAttributes attr = new NotificationAttributes(
14000                 GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
14001                 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14002         mService.addNotification(
14003                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14004                     nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14005 
14006         // cancel both children
14007         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
14008                 nr0.getSbn().getId(), nr0.getSbn().getUserId());
14009         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
14010                 nr1.getSbn().getId(), nr1.getSbn().getUserId());
14011         waitForIdle();
14012 
14013         // group helper would send 'remove summary' event
14014         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(),
14015                 AUTOGROUP_KEY);
14016         waitForIdle();
14017 
14018         // make sure the summary was removed and not re-posted
14019         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
14020     }
14021 
14022     @Test
14023     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14024     public void testUngroupingOngoingAutoSummary_forceGrouping() throws Exception {
14025         NotificationRecord nr0 =
14026             generateNotificationRecord(mTestNotificationChannel, 0);
14027         NotificationRecord nr1 =
14028             generateNotificationRecord(mTestNotificationChannel, 0);
14029         nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT;
14030 
14031         mService.addNotification(nr0);
14032         mService.addNotification(nr1);
14033 
14034         // grouphelper is a mock here, so make the calls it would make
14035 
14036         // add summary
14037         NotificationAttributes attr = new NotificationAttributes(
14038             GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
14039             VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14040         mService.addNotification(
14041             mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14042                 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14043 
14044         // cancel both children
14045         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
14046             nr0.getSbn().getId(), nr0.getSbn().getUserId());
14047         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
14048             nr1.getSbn().getId(), nr1.getSbn().getUserId());
14049         waitForIdle();
14050 
14051         // group helper would send 'remove summary' event
14052         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(),
14053             AUTOGROUP_KEY);
14054         waitForIdle();
14055 
14056         // make sure the summary was removed and not re-posted
14057         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
14058     }
14059 
14060     @Test
14061     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14062     public void testUngroupingAutoSummary_differentUsers() throws Exception {
14063         NotificationRecord nr0 =
14064                 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM);
14065         NotificationRecord nr1 =
14066                 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM);
14067 
14068         // add notifications + summary for USER_SYSTEM
14069         NotificationAttributes attr = new NotificationAttributes(
14070             GroupHelper.BASE_FLAGS, mock(Icon.class), 0,
14071             VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14072         mService.addNotification(nr0);
14073         mService.addNotification(nr1);
14074         mService.addNotification(
14075                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14076                 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14077 
14078         // add notifications + summary for USER_ALL
14079         NotificationRecord nr0_all =
14080                 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL);
14081         NotificationRecord nr1_all =
14082                 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL);
14083 
14084         mService.addNotification(nr0_all);
14085         mService.addNotification(nr1_all);
14086         mService.addNotification(
14087                 mService.createAutoGroupSummary(nr0_all.getUserId(),
14088                 nr0_all.getSbn().getPackageName(),
14089                 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14090 
14091         // cancel both children for USER_ALL
14092         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(),
14093                 nr0_all.getSbn().getId(), UserHandle.USER_ALL);
14094         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(),
14095                 nr1_all.getSbn().getId(), UserHandle.USER_ALL);
14096         waitForIdle();
14097 
14098         // group helper would send 'remove summary' event
14099         mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL,
14100                 nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY);
14101         waitForIdle();
14102 
14103         // make sure the right summary was removed
14104         assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(),
14105                 UserHandle.USER_ALL, 0, null)).isEqualTo(0);
14106 
14107         // the USER_SYSTEM notifications + summary were not removed
14108         assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(),
14109                 USER_SYSTEM, 0, null)).isEqualTo(3);
14110     }
14111 
14112     @Test
14113     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14114     public void testUngroupingAutoSummary_differentUsers_forceGrouping() throws Exception {
14115         NotificationRecord nr0 =
14116             generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM);
14117         NotificationRecord nr1 =
14118             generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM);
14119 
14120         // add notifications + summary for USER_SYSTEM
14121         NotificationAttributes attr = new NotificationAttributes(
14122             GroupHelper.BASE_FLAGS, mock(Icon.class), 0,
14123             VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14124         mService.addNotification(nr0);
14125         mService.addNotification(nr1);
14126         mService.addNotification(
14127             mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14128                 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14129 
14130         // add notifications + summary for USER_ALL
14131         NotificationRecord nr0_all =
14132             generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL);
14133         NotificationRecord nr1_all =
14134             generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL);
14135 
14136         mService.addNotification(nr0_all);
14137         mService.addNotification(nr1_all);
14138         mService.addNotification(
14139             mService.createAutoGroupSummary(nr0_all.getUserId(),
14140                 nr0_all.getSbn().getPackageName(),
14141                 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14142 
14143         // cancel both children for USER_ALL
14144         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(),
14145             nr0_all.getSbn().getId(), UserHandle.USER_ALL);
14146         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(),
14147             nr1_all.getSbn().getId(), UserHandle.USER_ALL);
14148         waitForIdle();
14149 
14150         // group helper would send 'remove summary' event
14151         mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL,
14152             nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY);
14153         waitForIdle();
14154 
14155         // make sure the right summary was removed
14156         assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(),
14157             UserHandle.USER_ALL, 0, null)).isEqualTo(0);
14158 
14159         // the USER_SYSTEM notifications + summary were not removed
14160         assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(),
14161             USER_SYSTEM, 0, null)).isEqualTo(3);
14162     }
14163 
14164     @Test
14165     public void testStrongAuthTracker_isInLockDownMode() {
14166         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
14167                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
14168         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
14169         assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
14170         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId());
14171         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
14172         assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
14173     }
14174 
14175     @Test
14176     public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() {
14177         // post 2 notifications from 2 packages
14178         NotificationRecord pkgA = new NotificationRecord(mContext,
14179                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14180         mService.addNotification(pkgA);
14181         NotificationRecord pkgB = new NotificationRecord(mContext,
14182                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
14183         mService.addNotification(pkgB);
14184 
14185         // when entering the lockdown mode, cancel the 2 notifications.
14186         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
14187                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
14188         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14189         assertTrue(mStrongAuthTracker.isInLockDownMode(0));
14190 
14191         // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
14192         ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
14193         verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
14194         assertEquals(REASON_LOCKDOWN, captor.getValue().intValue());
14195 
14196         // exit lockdown mode.
14197         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
14198         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14199         assertFalse(mStrongAuthTracker.isInLockDownMode(0));
14200 
14201         // the notifyPostedLocked function is called twice.
14202         verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong());
14203     }
14204 
14205     @Test
14206     public void testMakeRankingUpdateLockedInLockDownMode() {
14207         // post 2 notifications from a same package
14208         NotificationRecord pkgA = new NotificationRecord(mContext,
14209                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14210         mService.addNotification(pkgA);
14211         NotificationRecord pkgB = new NotificationRecord(mContext,
14212                 generateSbn("a", 1000, 9, 1), mTestNotificationChannel);
14213         mService.addNotification(pkgB);
14214 
14215         mService.setIsVisibleToListenerReturnValue(true);
14216         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null);
14217         assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
14218 
14219         // when only user 0 entering the lockdown mode, its notification will be suppressed.
14220         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
14221                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
14222         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14223         assertTrue(mStrongAuthTracker.isInLockDownMode(0));
14224         assertFalse(mStrongAuthTracker.isInLockDownMode(1));
14225 
14226         nru = mService.makeRankingUpdateLocked(null);
14227         assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
14228 
14229         // User 0 exits lockdown mode. Its notification will be resumed.
14230         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
14231         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14232         assertFalse(mStrongAuthTracker.isInLockDownMode(0));
14233         assertFalse(mStrongAuthTracker.isInLockDownMode(1));
14234 
14235         nru = mService.makeRankingUpdateLocked(null);
14236         assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
14237     }
14238 
14239     @Test
14240     public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() {
14241         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
14242         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
14243         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
14244         NotificationRecord pkgA = new NotificationRecord(mContext,
14245                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14246         addSmartActionsAndReplies(pkgA);
14247         mService.addNotification(pkgA);
14248         NotificationRecord pkgB = new NotificationRecord(mContext,
14249                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
14250         addSmartActionsAndReplies(pkgB);
14251         mService.addNotification(pkgB);
14252 
14253         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14254         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
14255         when(info.isSameUser(anyInt())).thenReturn(true);
14256         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14257         NotificationListenerService.Ranking ranking =
14258                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14259         assertEquals(0, ranking.getSmartActions().size());
14260         assertEquals(0, ranking.getSmartReplies().size());
14261         NotificationListenerService.Ranking ranking2 =
14262                 nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey());
14263         assertEquals(0, ranking2.getSmartActions().size());
14264         assertEquals(0, ranking2.getSmartReplies().size());
14265     }
14266 
14267     @Test
14268     public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() {
14269         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
14270         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
14271         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
14272         NotificationRecord pkgA = new NotificationRecord(mContext,
14273                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14274         addSmartActionsAndReplies(pkgA);
14275 
14276         mService.addNotification(pkgA);
14277         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14278         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
14279         when(info.isSameUser(anyInt())).thenReturn(true);
14280         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14281         NotificationListenerService.Ranking ranking =
14282                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14283         assertEquals(1, ranking.getSmartActions().size());
14284         assertEquals(1, ranking.getSmartReplies().size());
14285     }
14286 
14287     @Test
14288     public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() {
14289         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
14290         NotificationRecord pkgA = new NotificationRecord(mContext,
14291                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14292         addSmartActionsAndReplies(pkgA);
14293 
14294         mService.addNotification(pkgA);
14295         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14296         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
14297         when(info.isSameUser(anyInt())).thenReturn(true);
14298 
14299         // No sensitive content, no redaction
14300         when(mListeners.isUidTrusted(eq(1000))).thenReturn(false);
14301         when(mListeners.hasSensitiveContent(any())).thenReturn(false);
14302         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14303         NotificationListenerService.Ranking ranking =
14304                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14305         assertEquals(1, ranking.getSmartActions().size());
14306         assertEquals(1, ranking.getSmartReplies().size());
14307 
14308         // trusted listener, no redaction
14309         when(mListeners.isUidTrusted(eq(1000))).thenReturn(true);
14310         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
14311         nru = mService.makeRankingUpdateLocked(info);
14312         ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14313         assertEquals(1, ranking.getSmartActions().size());
14314         assertEquals(1, ranking.getSmartReplies().size());
14315     }
14316 
14317     private void addSmartActionsAndReplies(NotificationRecord record) {
14318         Bundle b = new Bundle();
14319         ArrayList<Notification.Action> actions = new ArrayList<>();
14320         actions.add(new Notification.Action(0, "", null));
14321         b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions);
14322         ArrayList<CharSequence> replies = new ArrayList<>(List.of("test"));
14323         b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies);
14324         Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(),
14325                 b, "", record.getUserId());
14326         record.addAdjustment(a);
14327         record.applyAdjustments();
14328     }
14329 
14330     @Test
14331     public void testMaybeShowReviewPermissionsNotification_flagOff() {
14332         mService.setShowReviewPermissionsNotification(false);
14333         reset(mMockNm);
14334 
14335         // If state is SHOULD_SHOW, it would show, but not if the flag is off!
14336         Settings.Global.putInt(mContext.getContentResolver(),
14337                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14338                 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW);
14339         mService.maybeShowInitialReviewPermissionsNotification();
14340         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14341     }
14342 
14343     @Test
14344     public void testMaybeShowReviewPermissionsNotification_unknown() {
14345         mService.setShowReviewPermissionsNotification(true);
14346         reset(mMockNm);
14347 
14348         // Set up various possible states of the settings int and confirm whether or not the
14349         // notification is shown as expected
14350 
14351         // Initial state: default/unknown setting, make sure nothing happens
14352         Settings.Global.putInt(mContext.getContentResolver(),
14353                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14354                 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN);
14355         mService.maybeShowInitialReviewPermissionsNotification();
14356         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14357     }
14358 
14359     @Test
14360     public void testMaybeShowReviewPermissionsNotification_shouldShow() {
14361         mService.setShowReviewPermissionsNotification(true);
14362         reset(mMockNm);
14363 
14364         // If state is SHOULD_SHOW, it ... should show
14365         Settings.Global.putInt(mContext.getContentResolver(),
14366                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14367                 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW);
14368         mService.maybeShowInitialReviewPermissionsNotification();
14369         verify(mMockNm, times(1)).notify(eq(TAG),
14370                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
14371                 any(Notification.class));
14372     }
14373 
14374     @Test
14375     public void testMaybeShowReviewPermissionsNotification_alreadyShown() {
14376         mService.setShowReviewPermissionsNotification(true);
14377         reset(mMockNm);
14378 
14379         // If state is either USER_INTERACTED or DISMISSED, we should not show this on boot
14380         Settings.Global.putInt(mContext.getContentResolver(),
14381                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14382                 NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED);
14383         mService.maybeShowInitialReviewPermissionsNotification();
14384 
14385         Settings.Global.putInt(mContext.getContentResolver(),
14386                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14387                 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED);
14388         mService.maybeShowInitialReviewPermissionsNotification();
14389 
14390         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14391     }
14392 
14393     @Test
14394     public void testMaybeShowReviewPermissionsNotification_reshown() {
14395         mService.setShowReviewPermissionsNotification(true);
14396         reset(mMockNm);
14397 
14398         // If we have re-shown the notification and the user did not subsequently interacted with
14399         // it, then make sure we show when trying on boot
14400         Settings.Global.putInt(mContext.getContentResolver(),
14401                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14402                 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN);
14403         mService.maybeShowInitialReviewPermissionsNotification();
14404         verify(mMockNm, times(1)).notify(eq(TAG),
14405                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
14406                 any(Notification.class));
14407     }
14408 
14409     @Test
14410     public void testRescheduledReviewPermissionsNotification() {
14411         mService.setShowReviewPermissionsNotification(true);
14412         reset(mMockNm);
14413 
14414         // when rescheduled, the notification goes through the NotificationManagerInternal service
14415         // this call doesn't need to know anything about previously scheduled state -- if called,
14416         // it should send the notification & write the appropriate int to Settings
14417         mInternalService.sendReviewPermissionsNotification();
14418 
14419         // Notification should be sent
14420         verify(mMockNm, times(1)).notify(eq(TAG),
14421                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
14422                 any(Notification.class));
14423 
14424         // write STATE_RESHOWN to settings
14425         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN,
14426                 Settings.Global.getInt(mContext.getContentResolver(),
14427                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14428                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
14429     }
14430 
14431     @Test
14432     public void testRescheduledReviewPermissionsNotification_flagOff() {
14433         mService.setShowReviewPermissionsNotification(false);
14434         reset(mMockNm);
14435 
14436         // no notification should be sent if the flag is off
14437         mInternalService.sendReviewPermissionsNotification();
14438         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14439     }
14440 
14441     private void verifyStickyHun(int permissionState, boolean appRequested,
14442             boolean isSticky) throws Exception {
14443 
14444         when(mPermissionHelper.hasRequestedPermission(Manifest.permission.USE_FULL_SCREEN_INTENT,
14445                 mPkg, mUserId)).thenReturn(appRequested);
14446 
14447         when(mPermissionManager.checkPermissionForDataDelivery(
14448                 eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any()))
14449                 .thenReturn(permissionState);
14450 
14451         Notification n = new Notification.Builder(mContext, "test")
14452                 .setFullScreenIntent(mActivityIntent, true)
14453                 .build();
14454 
14455         mService.fixNotification(n, mPkg, "tag", 9, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
14456 
14457         final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
14458 
14459         if (isSticky) {
14460             assertNotSame(0, stickyFlag);
14461         } else {
14462             assertSame(0, stickyFlag);
14463         }
14464     }
14465 
14466     @Test
14467     public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun()
14468             throws Exception {
14469 
14470         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_HARD_DENIED, true,
14471                 /* isSticky= */ true);
14472     }
14473 
14474     @Test
14475     public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun()
14476             throws Exception {
14477 
14478         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, true,
14479                 /* isSticky= */ true);
14480     }
14481 
14482     @Test
14483     public void testFixNotification_fsiPermissionSoftDenied_appNotRequest_noShowStickyHun()
14484             throws Exception {
14485         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, false,
14486                 /* isSticky= */ false);
14487     }
14488 
14489 
14490     @Test
14491     public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi()
14492             throws Exception {
14493 
14494         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_GRANTED, true,
14495                 /* isSticky= */ false);
14496     }
14497 
14498     @Test
14499     public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception {
14500         final ApplicationInfo applicationInfo = new ApplicationInfo();
14501         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14502                 .thenReturn(applicationInfo);
14503 
14504         Notification n = new Notification.Builder(mContext, "test")
14505                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
14506                 .setFlag(FLAG_CAN_COLORIZE, true)
14507                 .build();
14508 
14509         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14510 
14511         assertFalse(n.isForegroundService());
14512         assertFalse(n.hasColorizedPermission());
14513     }
14514 
14515     @Test
14516     public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception {
14517         Person person = new Person.Builder().setName("caller").build();
14518         Notification n = new Notification.Builder(mContext, "test")
14519                 .setStyle(Notification.CallStyle.forOngoingCall(
14520                         person, mActivityIntent))
14521                 .build();
14522         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14523                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14524         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14525 
14526         try {
14527             mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14528                     r.getSbn().getId(), r.getSbn().getTag(), r, false, false);
14529             assertFalse("CallStyle should not be allowed without a valid use case", true);
14530         } catch (IllegalArgumentException error) {
14531             assertThat(error.getMessage()).contains("CallStyle");
14532         }
14533     }
14534 
14535     @Test
14536     public void checkCallStyleNotification_allowedForFgs() throws Exception {
14537         Person person = new Person.Builder().setName("caller").build();
14538         Notification n = new Notification.Builder(mContext, "test")
14539                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
14540                 .setStyle(Notification.CallStyle.forOngoingCall(
14541                         person, mActivityIntent))
14542                 .build();
14543         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14544                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14545         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14546 
14547         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14548                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14549     }
14550 
14551     private Notification createBigPictureNotification(boolean isBigPictureStyle, boolean hasImage,
14552             boolean isImageBitmap) {
14553         Notification.Builder builder = new Notification.Builder(mContext)
14554                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
14555         Notification.BigPictureStyle style = new Notification.BigPictureStyle();
14556 
14557         if (isBigPictureStyle && hasImage) {
14558             if (isImageBitmap) {
14559                 style = style.bigPicture(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888));
14560             } else {
14561                 style = style.bigPicture(Icon.createWithResource(mContext, R.drawable.btn_plus));
14562             }
14563         }
14564         if (isBigPictureStyle) {
14565             builder.setStyle(style);
14566         }
14567 
14568         Notification notification = builder.setChannelId(TEST_CHANNEL_ID).build();
14569 
14570         return notification;
14571     }
14572 
14573     private NotificationRecord createBigPictureRecord(boolean isBigPictureStyle, boolean hasImage,
14574             boolean isImageBitmap, boolean isExpired) {
14575         long timePostedMs = System.currentTimeMillis();
14576         if (isExpired) {
14577             timePostedMs -= BITMAP_DURATION.toMillis();
14578         }
14579         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14580                 createBigPictureNotification(isBigPictureStyle, hasImage, isImageBitmap),
14581                 UserHandle.getUserHandleForUid(mUid), null, timePostedMs);
14582 
14583         return new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14584     }
14585 
14586     private void addRecordAndRemoveBitmaps(NotificationRecord record) {
14587         mService.addNotification(record);
14588         mInternalService.removeBitmaps();
14589         waitForIdle();
14590     }
14591 
14592     @Test
14593     public void testRemoveBitmaps_canRemoveRevokedDelegate() throws Exception {
14594         Notification n = createBigPictureNotification(true, true, true);
14595         long timePostedMs = System.currentTimeMillis();
14596         timePostedMs -= BITMAP_DURATION.toMillis();
14597 
14598         when(mPermissionHelper.hasPermission(UID_O)).thenReturn(true);
14599         when(mPackageManagerInternal.isSameApp(PKG_O, UID_O, UserHandle.getUserId(UID_O)))
14600                 .thenReturn(true);
14601         mService.mPreferencesHelper.createNotificationChannel(PKG_O, UID_O,
14602                 mTestNotificationChannel, true /* fromTargetApp */, false, UID_O,
14603                 false);
14604         mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
14605                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
14606 
14607         StatusBarNotification sbn = new StatusBarNotification(PKG_O, "old.delegate", 8, "tag",
14608                 UID_O, 0, n, UserHandle.getUserHandleForUid(UID_O), null, timePostedMs);
14609 
14610         mService.addNotification(new NotificationRecord(mContext, sbn, mTestNotificationChannel));
14611         mInternalService.removeBitmaps();
14612 
14613         waitForIdle();
14614 
14615         verify(mWorkerHandler, times(1))
14616                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14617     }
14618 
14619     @Test
14620     public void testRemoveBitmaps_notBigPicture_noRepost() {
14621         addRecordAndRemoveBitmaps(
14622                 createBigPictureRecord(
14623                         /* isBigPictureStyle= */ false,
14624                         /* hasImage= */ false,
14625                         /* isImageBitmap= */ false,
14626                         /* isExpired= */ false));
14627         verify(mWorkerHandler, never())
14628                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14629     }
14630 
14631     @Test
14632     public void testRemoveBitmaps_bigPictureNoImage_noRepost() {
14633         addRecordAndRemoveBitmaps(
14634                 createBigPictureRecord(
14635                         /* isBigPictureStyle= */ true,
14636                         /* hasImage= */ false,
14637                         /* isImageBitmap= */ false,
14638                         /* isExpired= */ false));
14639         verify(mWorkerHandler, never())
14640                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14641     }
14642 
14643     @Test
14644     public void testRemoveBitmaps_notExpired_noRepost() {
14645         addRecordAndRemoveBitmaps(
14646                 createBigPictureRecord(
14647                         /* isBigPictureStyle= */ true,
14648                         /* hasImage= */ true,
14649                         /* isImageBitmap= */ true,
14650                         /* isExpired= */ false));
14651         verify(mWorkerHandler, never())
14652                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14653     }
14654 
14655     @Test
14656     public void testRemoveBitmaps_bitmapExpired_repost() {
14657         addRecordAndRemoveBitmaps(
14658                 createBigPictureRecord(
14659                         /* isBigPictureStyle= */ true,
14660                         /* hasImage= */ true,
14661                         /* isImageBitmap= */ true,
14662                         /* isExpired= */ true));
14663         verify(mWorkerHandler, times(1))
14664                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14665     }
14666 
14667     @Test
14668     public void testRemoveBitmaps_bitmapExpired_bitmapGone() {
14669         NotificationRecord record = createBigPictureRecord(
14670                 /* isBigPictureStyle= */ true,
14671                 /* hasImage= */ true,
14672                 /* isImageBitmap= */ true,
14673                 /* isExpired= */ true);
14674         addRecordAndRemoveBitmaps(record);
14675         assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE)).isTrue();
14676         final Parcelable picture = record.getNotification().extras.getParcelable(EXTRA_PICTURE);
14677         assertThat(picture).isNull();
14678     }
14679 
14680     @Test
14681     public void testRemoveBitmaps_bitmapExpired_silent() {
14682         NotificationRecord record = createBigPictureRecord(
14683                 /* isBigPictureStyle= */ true,
14684                 /* hasImage= */ true,
14685                 /* isImageBitmap= */ true,
14686                 /* isExpired= */ true);
14687         addRecordAndRemoveBitmaps(record);
14688         assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
14689     }
14690 
14691     @Test
14692     public void testRemoveBitmaps_iconExpired_repost() {
14693         addRecordAndRemoveBitmaps(
14694                 createBigPictureRecord(
14695                         /* isBigPictureStyle= */ true,
14696                         /* hasImage= */ true,
14697                         /* isImageBitmap= */ false,
14698                         /* isExpired= */ true));
14699         verify(mWorkerHandler, times(1))
14700                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14701     }
14702 
14703     @Test
14704     public void testRemoveBitmaps_iconExpired_iconGone() {
14705         NotificationRecord record = createBigPictureRecord(
14706                 /* isBigPictureStyle= */ true,
14707                 /* hasImage= */ true,
14708                 /* isImageBitmap= */ false,
14709                 /* isExpired= */ true);
14710         addRecordAndRemoveBitmaps(record);
14711         assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE_ICON)).isTrue();
14712         final Parcelable pictureIcon =
14713                 record.getNotification().extras.getParcelable(EXTRA_PICTURE_ICON);
14714         assertThat(pictureIcon).isNull();
14715     }
14716 
14717     @Test
14718     public void testRemoveBitmaps_iconExpired_silent() {
14719         NotificationRecord record = createBigPictureRecord(
14720                 /* isBigPictureStyle= */ true,
14721                 /* hasImage= */ true,
14722                 /* isImageBitmap= */ false,
14723                 /* isExpired= */ true);
14724         addRecordAndRemoveBitmaps(record);
14725         assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
14726     }
14727 
14728     @Test
14729     public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
14730         Person person = new Person.Builder().setName("caller").build();
14731         Notification n = new Notification.Builder(mContext, "test")
14732                 // Without FLAG_FOREGROUND_SERVICE.
14733                 //.setFlag(FLAG_FOREGROUND_SERVICE, true)
14734                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14735                 .build();
14736         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14737                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14738         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14739 
14740         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14741                 r.getSbn().getId(), r.getSbn().getTag(), r, false,
14742                 true /* byForegroundService */)).isTrue();
14743     }
14744 
14745     @Test
14746     public void checkCallStyleNotification_allowedForUij() throws Exception {
14747         Person person = new Person.Builder().setName("caller").build();
14748         Notification n = new Notification.Builder(mContext, "test")
14749                 .setFlag(FLAG_USER_INITIATED_JOB, true)
14750                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14751                 .build();
14752         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14753                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14754         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14755 
14756         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14757                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14758     }
14759 
14760     @Test
14761     public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception {
14762         Person person = new Person.Builder().setName("caller").build();
14763         Notification n = new Notification.Builder(mContext, "test")
14764                 .setFullScreenIntent(mActivityIntent, true)
14765                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14766                 .build();
14767         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14768                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14769         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14770 
14771         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14772                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14773     }
14774 
14775     @Test
14776     public void checkCallStyleNotification_allowedForFsiDenied() throws Exception {
14777         Person person = new Person.Builder().setName("caller").build();
14778         Notification n = new Notification.Builder(mContext, "test")
14779                 .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true)
14780                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14781                 .build();
14782         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14783                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14784         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14785 
14786         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14787                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14788     }
14789 
14790     @Test
14791     public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible()
14792             throws Exception {
14793         final ApplicationInfo ai = new ApplicationInfo();
14794         ai.packageName = "pkg";
14795         ai.uid = mUid;
14796         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
14797 
14798         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14799                 .thenReturn(ai);
14800         when(mAppOpsManager.checkOpNoThrow(
14801                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
14802                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
14803         // Given: a notification from an app on the system partition has the flag
14804         // FLAG_ONGOING_EVENT set
14805         Notification n = new Notification.Builder(mContext, "test")
14806                 .setOngoing(true)
14807                 .build();
14808 
14809         // When: fix the notification with NotificationManagerService
14810         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14811 
14812         // Then: the notification's flag FLAG_NO_DISMISS should not be set
14813         assertSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14814     }
14815 
14816     @Test
14817     public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible()
14818             throws Exception {
14819         // Given: a media notification has the flag FLAG_ONGOING_EVENT set
14820         Notification n = new Notification.Builder(mContext, "test")
14821                 .setOngoing(true)
14822                 .setStyle(new Notification.MediaStyle()
14823                         .setMediaSession(mock(MediaSession.Token.class)))
14824                 .build();
14825 
14826         // When: fix the notification with NotificationManagerService
14827         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14828 
14829         // Then: the notification's flag FLAG_NO_DISMISS should be set
14830         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14831     }
14832 
14833     @Test
14834     public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible()
14835             throws Exception {
14836         final ApplicationInfo ai = new ApplicationInfo();
14837         ai.packageName = SEARCH_SELECTOR_PKG;
14838         ai.uid = mUid;
14839         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
14840 
14841         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14842                 .thenReturn(ai);
14843         when(mAppOpsManager.checkOpNoThrow(
14844                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
14845                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
14846         // Given: a notification from an app on the system partition has the flag
14847         // FLAG_ONGOING_EVENT set
14848         Notification n = new Notification.Builder(mContext, "test")
14849                 .setOngoing(true)
14850                 .build();
14851 
14852         // When: fix the notification with NotificationManagerService
14853         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14854 
14855         // Then: the notification's flag FLAG_NO_DISMISS should be set
14856         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14857     }
14858 
14859     @Test
14860     public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible()
14861             throws Exception {
14862         final ApplicationInfo ai = new ApplicationInfo();
14863         ai.packageName = ADSERVICES_APK_PKG;
14864         ai.uid = mUid;
14865         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
14866 
14867         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14868                 .thenReturn(ai);
14869         when(mAppOpsManager.checkOpNoThrow(
14870                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
14871                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
14872         // Given: a notification from an app on the system partition has the flag
14873         // FLAG_ONGOING_EVENT set
14874         Notification n = new Notification.Builder(mContext, "test")
14875                 .setOngoing(true)
14876                 .build();
14877 
14878         // When: fix the notification with NotificationManagerService
14879         mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE,
14880                  true);
14881 
14882         // Then: the notification's flag FLAG_NO_DISMISS should be set
14883         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14884     }
14885 
14886     @Test
14887     public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible()
14888             throws Exception {
14889         // Given: a call notification has the flag FLAG_ONGOING_EVENT set
14890         Person person = new Person.Builder()
14891                 .setName("caller")
14892                 .build();
14893         Notification n = new Notification.Builder(mContext, "test")
14894                 .setOngoing(true)
14895                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14896                 .build();
14897 
14898         // When: fix the notification with NotificationManagerService
14899         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14900 
14901         // Then: the notification's flag FLAG_NO_DISMISS should be set
14902         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14903     }
14904 
14905 
14906     @Test
14907     public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception {
14908         // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
14909         Notification n = new Notification.Builder(mContext, "test")
14910                 .setOngoing(true)
14911                 .build();
14912 
14913         // When: fix the notification with NotificationManagerService
14914         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14915 
14916         // Then: the notification's flag FLAG_NO_DISMISS should not be set
14917         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
14918     }
14919 
14920     @Test
14921     public void fixNonExemptNotification_withNoDismissFlag_shouldBeDismissible()
14922             throws Exception {
14923         // Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is
14924         // not allowed)
14925         Notification n = new Notification.Builder(mContext, "test")
14926                 .build();
14927         n.flags |= Notification.FLAG_NO_DISMISS;
14928 
14929         // When: fix the notification with NotificationManagerService
14930         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14931 
14932         // Then: the notification's flag FLAG_NO_DISMISS should be cleared
14933         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
14934     }
14935 
14936     @Test
14937     public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception {
14938         // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set
14939         Notification n = new Notification.Builder(mContext, "test")
14940                 .setOngoing(false)
14941                 .setStyle(new Notification.MediaStyle()
14942                         .setMediaSession(mock(MediaSession.Token.class)))
14943                 .build();
14944 
14945         // When: fix the notification with NotificationManagerService
14946         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14947 
14948         // Then: the notification's flag FLAG_NO_DISMISS should not be set
14949         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
14950     }
14951 
14952     @Test
14953     public void fixMediaNotification_withoutOnGoingFlag_withNoDismissFlag_shouldBeDismissible()
14954             throws Exception {
14955         // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set,
14956         // but has the flag FLAG_NO_DISMISS set
14957         Notification n = new Notification.Builder(mContext, "test")
14958                 .setOngoing(false)
14959                 .setStyle(new Notification.MediaStyle()
14960                         .setMediaSession(mock(MediaSession.Token.class)))
14961                 .build();
14962         n.flags |= Notification.FLAG_NO_DISMISS;
14963 
14964         // When: fix the notification with NotificationManagerService
14965         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14966 
14967         // Then: the notification's flag FLAG_NO_DISMISS should be cleared
14968         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
14969     }
14970 
14971     @Test
14972     public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible()
14973             throws Exception {
14974         // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
14975         Notification n = new Notification.Builder(mContext, "test")
14976                 .setOngoing(false)
14977                 .build();
14978 
14979         // When: fix the notification with NotificationManagerService
14980         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14981 
14982         // Then: the notification's flag FLAG_NO_DISMISS should not be set
14983         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
14984     }
14985 
14986     @Test
14987     public void fixOrganizationAdminNotification_withOnGoingFlag_shouldBeNonDismissible()
14988             throws Exception {
14989         when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true);
14990         // Given: a notification has the flag FLAG_ONGOING_EVENT set
14991         Notification n = new Notification.Builder(mContext, "test")
14992                 .setOngoing(true)
14993                 .build();
14994 
14995         // When: fix the notification with NotificationManagerService
14996         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14997 
14998         // Then: the notification's flag FLAG_NO_DISMISS should be set
14999         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15000     }
15001 
15002     @Test
15003     public void fixExemptAppOpNotification_withFlag_shouldBeNonDismissible()
15004             throws Exception {
15005         final ApplicationInfo ai = new ApplicationInfo();
15006         ai.packageName = mPkg;
15007         ai.uid = mUid;
15008         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
15009 
15010         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
15011                 .thenReturn(ai);
15012         when(mAppOpsManager.checkOpNoThrow(
15013                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
15014                 mPkg)).thenReturn(AppOpsManager.MODE_ALLOWED);
15015         // Given: a notification has the flag FLAG_ONGOING_EVENT set
15016         Notification n = new Notification.Builder(mContext, "test")
15017                 .setOngoing(true)
15018                 .build();
15019 
15020         // When: fix the notification with NotificationManagerService
15021         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15022 
15023         // Then: the notification's flag FLAG_NO_DISMISS should be set
15024         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15025     }
15026 
15027     @Test
15028     public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible()
15029             throws Exception {
15030         when(mAppOpsManager.checkOpNoThrow(
15031                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
15032                 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED);
15033         // Given: a notification has the flag FLAG_ONGOING_EVENT set
15034         Notification n = new Notification.Builder(mContext, "test")
15035                 .setOngoing(true)
15036                 .build();
15037 
15038         // When: fix the notification with NotificationManagerService
15039         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15040 
15041         // Then: the notification's flag FLAG_NO_DISMISS should not be set
15042         assertSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15043     }
15044 
15045     @Test
15046     public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception {
15047         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15048                 .thenReturn(true);
15049         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15050         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15051         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15052                 "testCancelAllNotifications_IgnoreUserInitiatedJob",
15053                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15054         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
15055         waitForIdle();
15056         StatusBarNotification[] notifs =
15057                 mBinderService.getActiveNotifications(sbn.getPackageName());
15058         assertEquals(1, notifs.length);
15059         assertEquals(1, mService.getNotificationRecordCount());
15060     }
15061 
15062     @Test
15063     public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception {
15064         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15065                 .thenReturn(false);
15066         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15067         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15068         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15069                 "testCancelAllNotifications_UijFlag_NoUij_Allowed",
15070                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15071         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
15072         waitForIdle();
15073         StatusBarNotification[] notifs =
15074                 mBinderService.getActiveNotifications(sbn.getPackageName());
15075         assertEquals(0, notifs.length);
15076     }
15077 
15078     @Test
15079     public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception {
15080         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15081                 .thenReturn(true);
15082         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15083         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15084         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15085                 "testCancelAllNotifications_IgnoreOtherPackages",
15086                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15087         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
15088         waitForIdle();
15089         StatusBarNotification[] notifs =
15090                 mBinderService.getActiveNotifications(sbn.getPackageName());
15091         assertEquals(1, notifs.length);
15092         assertEquals(1, mService.getNotificationRecordCount());
15093     }
15094 
15095     @Test
15096     public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception {
15097         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15098                 .thenReturn(true);
15099         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15100                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15101                 .build();
15102         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
15103                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15104         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15105         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null,
15106                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15107         mInternalService.removeUserInitiatedJobFlagFromNotification(mPkg, sbn.getId(),
15108                 sbn.getUserId());
15109         waitForIdle();
15110         StatusBarNotification[] notifs =
15111                 mBinderService.getActiveNotifications(sbn.getPackageName());
15112         assertFalse(notifs[0].getNotification().isUserInitiatedJob());
15113     }
15114 
15115     @Test
15116     public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception {
15117         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15118         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB;
15119         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
15120                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15121         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
15122         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
15123                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15124         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
15125                 sbn.getUserId());
15126         waitForIdle();
15127         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
15128         assertEquals(0, mService.getNotificationRecordCount());
15129     }
15130 
15131     @Test
15132     public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception {
15133         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15134                 .thenReturn(true);
15135         mService.isSystemUid = false;
15136         mService.isSystemAppId = false;
15137         final NotificationRecord parent = generateNotificationRecord(
15138                 mTestNotificationChannel, 1, "group", true);
15139         final NotificationRecord child = generateNotificationRecord(
15140                 mTestNotificationChannel, 2, "group", false);
15141         final NotificationRecord child2 = generateNotificationRecord(
15142                 mTestNotificationChannel, 3, "group", false);
15143         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15144         mService.addNotification(parent);
15145         mService.addNotification(child);
15146         mService.addNotification(child2);
15147         mService.getBinderService().cancelNotificationWithTag(
15148                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
15149                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
15150         waitForIdle();
15151         StatusBarNotification[] notifs =
15152                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15153         assertEquals(1, notifs.length);
15154     }
15155 
15156     @Test
15157     public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception {
15158         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15159                 .thenReturn(true);
15160         mService.isSystemUid = false;
15161         mService.isSystemAppId = false;
15162         final NotificationRecord parent = generateNotificationRecord(
15163                 mTestNotificationChannel, 1, "group", true);
15164         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15165         final NotificationRecord child = generateNotificationRecord(
15166                 mTestNotificationChannel, 2, "group", false);
15167         final NotificationRecord child2 = generateNotificationRecord(
15168                 mTestNotificationChannel, 3, "group", false);
15169         mService.addNotification(parent);
15170         mService.addNotification(child);
15171         mService.addNotification(child2);
15172         mService.getBinderService().cancelNotificationWithTag(
15173                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
15174                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
15175         waitForIdle();
15176         StatusBarNotification[] notifs =
15177                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15178         assertEquals(3, notifs.length);
15179     }
15180 
15181     @Test
15182     public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception {
15183         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15184                 .thenReturn(true);
15185         mService.isSystemUid = false;
15186         mService.isSystemAppId = false;
15187         final NotificationRecord parent = generateNotificationRecord(
15188                 mTestNotificationChannel, 1, "group", true);
15189         final NotificationRecord child = generateNotificationRecord(
15190                 mTestNotificationChannel, 2, "group", false);
15191         final NotificationRecord child2 = generateNotificationRecord(
15192                 mTestNotificationChannel, 3, "group", false);
15193         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15194         final NotificationRecord newGroup = generateNotificationRecord(
15195                 mTestNotificationChannel, 4, "group2", false);
15196         mService.addNotification(parent);
15197         mService.addNotification(child);
15198         mService.addNotification(child2);
15199         mService.addNotification(newGroup);
15200         mService.getBinderService().cancelAllNotifications(
15201                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
15202         waitForIdle();
15203         StatusBarNotification[] notifs =
15204                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15205         assertEquals(1, notifs.length);
15206     }
15207 
15208     @Test
15209     public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception {
15210         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15211                 .thenReturn(true);
15212         mService.isSystemUid = false;
15213         mService.isSystemAppId = false;
15214         final NotificationRecord parent = generateNotificationRecord(
15215                 mTestNotificationChannel, 1, "group", true);
15216         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15217         final NotificationRecord child = generateNotificationRecord(
15218                 mTestNotificationChannel, 2, "group", false);
15219         final NotificationRecord child2 = generateNotificationRecord(
15220                 mTestNotificationChannel, 3, "group", false);
15221         final NotificationRecord newGroup = generateNotificationRecord(
15222                 mTestNotificationChannel, 4, "group2", false);
15223         mService.addNotification(parent);
15224         mService.addNotification(child);
15225         mService.addNotification(child2);
15226         mService.addNotification(newGroup);
15227         mService.getBinderService().cancelAllNotifications(
15228                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
15229         waitForIdle();
15230         StatusBarNotification[] notifs =
15231                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15232         assertEquals(1, notifs.length);
15233     }
15234 
15235     @Test
15236     public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception {
15237         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15238                 .thenReturn(true);
15239         final NotificationRecord parent = generateNotificationRecord(
15240                 mTestNotificationChannel, 1, "group", true);
15241         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15242         final NotificationRecord child = generateNotificationRecord(
15243                 mTestNotificationChannel, 2, "group", false);
15244         final NotificationRecord child2 = generateNotificationRecord(
15245                 mTestNotificationChannel, 3, "group", false);
15246         final NotificationRecord newGroup = generateNotificationRecord(
15247                 mTestNotificationChannel, 4, "group2", false);
15248         mService.addNotification(parent);
15249         mService.addNotification(child);
15250         mService.addNotification(child2);
15251         mService.addNotification(newGroup);
15252         mService.getBinderService().cancelNotificationsFromListener(null, null);
15253         waitForIdle();
15254         StatusBarNotification[] notifs =
15255                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15256         assertEquals(0, notifs.length);
15257     }
15258 
15259     @Test
15260     public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception {
15261         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15262                 .thenReturn(true);
15263         final NotificationRecord parent = generateNotificationRecord(
15264                 mTestNotificationChannel, 1, "group", true);
15265         final NotificationRecord child = generateNotificationRecord(
15266                 mTestNotificationChannel, 2, "group", false);
15267         final NotificationRecord child2 = generateNotificationRecord(
15268                 mTestNotificationChannel, 3, "group", false);
15269         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15270         final NotificationRecord newGroup = generateNotificationRecord(
15271                 mTestNotificationChannel, 4, "group2", false);
15272         mService.addNotification(parent);
15273         mService.addNotification(child);
15274         mService.addNotification(child2);
15275         mService.addNotification(newGroup);
15276         mService.getBinderService().cancelNotificationsFromListener(null, null);
15277         waitForIdle();
15278         StatusBarNotification[] notifs =
15279                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15280         assertEquals(0, notifs.length);
15281     }
15282 
15283     @Test
15284     public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception {
15285         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15286                 .thenReturn(true);
15287         final NotificationRecord child2 = generateNotificationRecord(
15288                 mTestNotificationChannel, 3, null, false);
15289         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15290         mService.addNotification(child2);
15291         mService.getBinderService().cancelNotificationsFromListener(null, null);
15292         waitForIdle();
15293         StatusBarNotification[] notifs =
15294                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
15295         assertEquals(0, notifs.length);
15296     }
15297 
15298     @Test
15299     public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception {
15300         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15301                 .thenReturn(true);
15302         final NotificationRecord parent = generateNotificationRecord(
15303                 mTestNotificationChannel, 1, "group", true);
15304         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15305         final NotificationRecord child = generateNotificationRecord(
15306                 mTestNotificationChannel, 2, "group", false);
15307         final NotificationRecord child2 = generateNotificationRecord(
15308                 mTestNotificationChannel, 3, "group", false);
15309         final NotificationRecord newGroup = generateNotificationRecord(
15310                 mTestNotificationChannel, 4, "group2", false);
15311         mService.addNotification(parent);
15312         mService.addNotification(child);
15313         mService.addNotification(child2);
15314         mService.addNotification(newGroup);
15315         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
15316                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
15317         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15318         waitForIdle();
15319         StatusBarNotification[] notifs =
15320                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15321         assertEquals(0, notifs.length);
15322     }
15323 
15324     @Test
15325     public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception {
15326         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15327                 .thenReturn(true);
15328         final NotificationRecord parent = generateNotificationRecord(
15329                 mTestNotificationChannel, 1, "group", true);
15330         final NotificationRecord child = generateNotificationRecord(
15331                 mTestNotificationChannel, 2, "group", false);
15332         final NotificationRecord child2 = generateNotificationRecord(
15333                 mTestNotificationChannel, 3, "group", false);
15334         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15335         final NotificationRecord newGroup = generateNotificationRecord(
15336                 mTestNotificationChannel, 4, "group2", false);
15337         mService.addNotification(parent);
15338         mService.addNotification(child);
15339         mService.addNotification(child2);
15340         mService.addNotification(newGroup);
15341         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
15342                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
15343         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15344         waitForIdle();
15345         StatusBarNotification[] notifs =
15346                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15347         assertEquals(0, notifs.length);
15348     }
15349 
15350     @Test
15351     public void testCancelNotificationsFromListener_byKey_Uij() throws Exception {
15352         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15353                 .thenReturn(true);
15354         final NotificationRecord child = generateNotificationRecord(
15355                 mTestNotificationChannel, 3, null, false);
15356         child.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15357         mService.addNotification(child);
15358         String[] keys = {child.getSbn().getKey()};
15359         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15360         waitForIdle();
15361         StatusBarNotification[] notifs =
15362                 mBinderService.getActiveNotifications(child.getSbn().getPackageName());
15363         assertEquals(0, notifs.length);
15364     }
15365 
15366     @Test
15367     public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception {
15368         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15369                 .thenReturn(true);
15370         final NotificationRecord parent = generateNotificationRecord(
15371                 mTestNotificationChannel, 1, "group", true);
15372         final NotificationRecord child = generateNotificationRecord(
15373                 mTestNotificationChannel, 2, "group", false);
15374         final NotificationRecord child2 = generateNotificationRecord(
15375                 mTestNotificationChannel, 3, "group", false);
15376         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15377         final NotificationRecord newGroup = generateNotificationRecord(
15378                 mTestNotificationChannel, 4, "group2", false);
15379         mService.addNotification(parent);
15380         mService.addNotification(child);
15381         mService.addNotification(child2);
15382         mService.addNotification(newGroup);
15383         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId());
15384         waitForIdle();
15385         StatusBarNotification[] notifs =
15386                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15387         assertEquals(0, notifs.length);
15388     }
15389 
15390     @Test
15391     public void testDeleteChannelGroupChecksForUijs() throws Exception {
15392         when(mCompanionMgr.getAssociations(mPkg, UserHandle.getUserId(mUid)))
15393                 .thenReturn(singletonList(mock(AssociationInfo.class)));
15394         CountDownLatch latch = new CountDownLatch(2);
15395         mService.createNotificationChannelGroup(mPkg, mUid,
15396                 new NotificationChannelGroup("group", "group"), true, false);
15397         new Thread(() -> {
15398             NotificationChannel notificationChannel = new NotificationChannel("id", "id",
15399                     NotificationManager.IMPORTANCE_HIGH);
15400             notificationChannel.setGroup("group");
15401             ParceledListSlice<NotificationChannel> pls =
15402                     new ParceledListSlice(ImmutableList.of(notificationChannel));
15403             try {
15404                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
15405             } catch (RemoteException e) {
15406                 throw new RuntimeException(e);
15407             }
15408             latch.countDown();
15409         }).start();
15410         new Thread(() -> {
15411             try {
15412                 synchronized (this) {
15413                     wait(5000);
15414                 }
15415                 mService.createNotificationChannelGroup(mPkg, mUid,
15416                         new NotificationChannelGroup("new", "new group"), true, false);
15417                 NotificationChannel notificationChannel =
15418                         new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
15419                 notificationChannel.setGroup("new");
15420                 ParceledListSlice<NotificationChannel> pls =
15421                         new ParceledListSlice(ImmutableList.of(notificationChannel));
15422                 try {
15423                     mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
15424                     mBinderService.deleteNotificationChannelGroup(mPkg, "group");
15425                 } catch (RemoteException e) {
15426                     throw new RuntimeException(e);
15427                 }
15428             } catch (Exception e) {
15429                 e.printStackTrace();
15430             }
15431             latch.countDown();
15432         }).start();
15433 
15434         latch.await();
15435         verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs(
15436                 anyString(), anyInt(), anyString());
15437     }
15438 
15439     @Test
15440     public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() {
15441         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15442                 .thenReturn(true);
15443         Notification n = new Notification.Builder(mContext, "").build();
15444         n.flags |= FLAG_USER_INITIATED_JOB;
15445 
15446         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
15447                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15448         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15449 
15450         mService.addEnqueuedNotification(r);
15451 
15452         mInternalService.removeUserInitiatedJobFlagFromNotification(
15453                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15454 
15455         waitForIdle();
15456 
15457         verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
15458     }
15459 
15460     @Test
15461     public void testRemoveUserInitiatedJobFlagFromNotification_posted() {
15462         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15463                 .thenReturn(true);
15464         Notification n = new Notification.Builder(mContext, "").build();
15465         n.flags |= FLAG_USER_INITIATED_JOB;
15466 
15467         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
15468                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15469         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15470 
15471         mService.addNotification(r);
15472 
15473         mInternalService.removeUserInitiatedJobFlagFromNotification(
15474                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15475 
15476         waitForIdle();
15477 
15478         ArgumentCaptor<NotificationRecord> captor =
15479                 ArgumentCaptor.forClass(NotificationRecord.class);
15480         verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
15481 
15482         assertEquals(0, captor.getValue().getNotification().flags);
15483     }
15484 
15485     @Test
15486     public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() {
15487         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15488             Notification n = new Notification.Builder(mContext, "").build();
15489             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
15490                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
15491             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15492             mService.addEnqueuedNotification(r);
15493         }
15494         Notification n = new Notification.Builder(mContext, "").build();
15495         n.flags |= FLAG_USER_INITIATED_JOB;
15496 
15497         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
15498                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
15499                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15500         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15501 
15502         mService.addEnqueuedNotification(r);
15503 
15504         mInternalService.removeUserInitiatedJobFlagFromNotification(
15505                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15506 
15507         waitForIdle();
15508 
15509         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
15510                 mService.getNotificationRecordCount());
15511     }
15512 
15513     @Test
15514     public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() {
15515         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15516                 .thenReturn(true);
15517         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15518             Notification n = new Notification.Builder(mContext, "").build();
15519             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
15520                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
15521             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15522             mService.addNotification(r);
15523         }
15524         Notification n = new Notification.Builder(mContext, "").build();
15525         n.flags |= FLAG_USER_INITIATED_JOB;
15526 
15527         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
15528                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
15529                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15530         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15531 
15532         mService.addNotification(r);
15533 
15534         mInternalService.removeUserInitiatedJobFlagFromNotification(
15535                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15536 
15537         waitForIdle();
15538 
15539         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
15540                 mService.getNotificationRecordCount());
15541     }
15542 
15543     @Test
15544     public void testCanPostUijWhenOverLimit() throws RemoteException {
15545         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15546                 .thenReturn(true);
15547         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15548             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
15549                     i, null, false).getSbn();
15550             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCanPostUijWhenOverLimit",
15551                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
15552         }
15553 
15554         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15555         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15556         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15557                 "testCanPostUijWhenOverLimit - uij over limit!",
15558                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15559 
15560         waitForIdle();
15561 
15562         StatusBarNotification[] notifs =
15563                 mBinderService.getActiveNotifications(sbn.getPackageName());
15564         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
15565         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
15566                 mService.getNotificationRecordCount());
15567     }
15568 
15569     @Test
15570     public void testCannotPostNonUijWhenOverLimit() throws RemoteException {
15571         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15572                 .thenReturn(true);
15573         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15574             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
15575                     i, null, false).getSbn();
15576             mBinderService.enqueueNotificationWithTag(
15577                     mPkg,
15578                     mPkg,
15579                     "testCannotPostNonUijWhenOverLimit",
15580                     sbn.getId(),
15581                     sbn.getNotification(),
15582                     sbn.getUserId());
15583             waitForIdle();
15584         }
15585 
15586         final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
15587                 100, null, false).getSbn();
15588         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15589         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15590                 "testCannotPostNonUijWhenOverLimit - uij over limit!",
15591                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15592 
15593         final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
15594                 101, null, false).getSbn();
15595         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15596                 "testCannotPostNonUijWhenOverLimit - non uij over limit!",
15597                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
15598 
15599         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15600                 .thenReturn(false);
15601         final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
15602                 101, null, false).getSbn();
15603         sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15604         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15605                 "testCannotPostNonUijWhenOverLimit - fake uij over limit!",
15606                 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
15607 
15608         waitForIdle();
15609 
15610         StatusBarNotification[] notifs =
15611                 mBinderService.getActiveNotifications(sbn.getPackageName());
15612         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
15613         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
15614                 mService.getNotificationRecordCount());
15615     }
15616 
15617     @Test
15618     public void fixNotification_withUijFlag_butIsNotUij() throws Exception {
15619         final ApplicationInfo applicationInfo = new ApplicationInfo();
15620         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
15621                 .thenReturn(applicationInfo);
15622 
15623         Notification n = new Notification.Builder(mContext, "test")
15624                 .setFlag(FLAG_USER_INITIATED_JOB, true)
15625                 .build();
15626 
15627         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15628         assertFalse(n.isUserInitiatedJob());
15629     }
15630 
15631     @Test
15632     public void enqueue_updatesEnqueueRate() throws Exception {
15633         Notification n = generateNotificationRecord(null).getNotification();
15634 
15635         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
15636         // Don't waitForIdle() here. We want to verify the "intermediate" state.
15637 
15638         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15639         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15640         verify(mUsageStats, never()).registerPostedByApp(any());
15641 
15642         waitForIdle();
15643     }
15644 
15645     @Test
15646     public void enqueue_withPost_updatesEnqueueRateAndPost() throws Exception {
15647         Notification n = generateNotificationRecord(null).getNotification();
15648 
15649         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
15650         waitForIdle();
15651 
15652         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15653         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15654         verify(mUsageStats).registerPostedByApp(any());
15655     }
15656 
15657     @Test
15658     public void enqueueNew_whenOverEnqueueRate_accepts() throws Exception {
15659         Notification n = generateNotificationRecord(null).getNotification();
15660         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
15661                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f);
15662 
15663         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
15664         waitForIdle();
15665 
15666         assertThat(mService.mNotificationsByKey).hasSize(1);
15667         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15668         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15669         verify(mUsageStats).registerPostedByApp(any());
15670     }
15671 
15672     @Test
15673     public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception {
15674         // Post the first version.
15675         Notification original = generateNotificationRecord(null).getNotification();
15676         original.when = System.currentTimeMillis();
15677         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
15678         waitForIdle();
15679         assertThat(mService.mNotificationList).hasSize(1);
15680         assertThat(mService.mNotificationList.get(0).getNotification().when)
15681                 .isEqualTo(original.when);
15682 
15683         reset(mUsageStats);
15684         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
15685                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE - 1f);
15686 
15687         // Post the update.
15688         Notification update = generateNotificationRecord(null).getNotification();
15689         update.when = System.currentTimeMillis() + 111;
15690         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
15691         waitForIdle();
15692 
15693         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15694         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15695         verify(mUsageStats, never()).registerPostedByApp(any());
15696         verify(mUsageStats).registerUpdatedByApp(any(), any());
15697         assertThat(mService.mNotificationList).hasSize(1);
15698         assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when);
15699     }
15700 
15701     @Test
15702     public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception {
15703         // Post the first version.
15704         Notification original = generateNotificationRecord(null).getNotification();
15705         original.when = System.currentTimeMillis();
15706         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
15707         waitForIdle();
15708         assertThat(mService.mNotificationList).hasSize(1);
15709         assertThat(mService.mNotificationList.get(0).getNotification().when)
15710                 .isEqualTo(original.when);
15711 
15712         reset(mUsageStats);
15713         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
15714                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f);
15715 
15716         // Post the update.
15717         Notification update = generateNotificationRecord(null).getNotification();
15718         update.when = System.currentTimeMillis() + 111;
15719         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
15720         waitForIdle();
15721 
15722         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15723         verify(mUsageStats, never()).registerEnqueuedByAppAndAccepted(any());
15724         verify(mUsageStats, never()).registerPostedByApp(any());
15725         verify(mUsageStats, never()).registerUpdatedByApp(any(), any());
15726         assertThat(mService.mNotificationList).hasSize(1);
15727         assertThat(mService.mNotificationList.get(0).getNotification().when)
15728                 .isEqualTo(original.when); // old
15729     }
15730 
15731     @Test
15732     public void enqueueNotification_acceptsCorrectToken() throws RemoteException {
15733         Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15734                 .setContentIntent(createPendingIntent("content"))
15735                 .build();
15736         Notification received = parcelAndUnparcel(sent, Notification.CREATOR);
15737         assertThat(received.getAllowlistToken()).isEqualTo(
15738                 NotificationManagerService.ALLOWLIST_TOKEN);
15739 
15740         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
15741                 parcelAndUnparcel(received, Notification.CREATOR), mUserId);
15742         waitForIdle();
15743 
15744         assertThat(mService.mNotificationList).hasSize(1);
15745         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
15746                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
15747     }
15748 
15749     @Test
15750     public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException {
15751         Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15752                 .setContentIntent(createPendingIntent("content"))
15753                 .build();
15754         assertThat(receivedWithoutParceling.getAllowlistToken()).isNull();
15755 
15756         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
15757                 parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId);
15758         waitForIdle();
15759 
15760         assertThat(mService.mNotificationList).hasSize(1);
15761         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
15762                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
15763     }
15764 
15765     @Test
15766     public void enqueueNotification_directlyThroughRunnable_populatesAllowlistToken() {
15767         Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15768                 .setContentIntent(createPendingIntent("content"))
15769                 .build();
15770         NotificationRecord record = new NotificationRecord(
15771                 mContext,
15772                 new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 44, receivedWithoutParceling,
15773                         mUser, "groupKey", 0),
15774                 mTestNotificationChannel);
15775         assertThat(record.getNotification().getAllowlistToken()).isNull();
15776 
15777         mWorkerHandler.post(
15778                 mService.new EnqueueNotificationRunnable(mUserId, record, false, false,
15779                 mPostNotificationTrackerFactory.newTracker(null)));
15780         waitForIdle();
15781 
15782         assertThat(mService.mNotificationList).hasSize(1);
15783         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
15784                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
15785     }
15786 
15787     @Test
15788     public void enqueueNotification_rejectsOtherToken() throws RemoteException {
15789         Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15790                 .setContentIntent(createPendingIntent("content"))
15791                 .build();
15792         sent.overrideAllowlistToken(new Binder());
15793         Notification received = parcelAndUnparcel(sent, Notification.CREATOR);
15794         assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken());
15795 
15796         assertThrows(SecurityException.class, () ->
15797                 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
15798                         parcelAndUnparcel(received, Notification.CREATOR), mUserId));
15799         waitForIdle();
15800 
15801         assertThat(mService.mNotificationList).isEmpty();
15802     }
15803 
15804     @Test
15805     public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents()
15806             throws RemoteException {
15807         Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15808                 .setContentIntent(createPendingIntent("content"))
15809                 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID)
15810                         .setContentIntent(createPendingIntent("public"))
15811                         .build())
15812                 .build();
15813         sentFromApp.publicVersion.overrideAllowlistToken(new Binder());
15814 
15815         // Instead of using the normal parceling, assume the caller parcels it by hand, including a
15816         // null token in the outer notification (as would be expected, and as is verified by
15817         // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets
15818         // propagated to the PendingIntents.
15819         Parcel parcelSentFromApp = Parcel.obtain();
15820         writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>(
15821                 Lists.newArrayList(sentFromApp.contentIntent,
15822                         sentFromApp.publicVersion.contentIntent)));
15823 
15824         // Use the unparceling as received in enqueueNotificationWithTag()
15825         parcelSentFromApp.setDataPosition(0);
15826         Notification receivedByNms = new Notification(parcelSentFromApp);
15827 
15828         // Verify that all the pendingIntents have the correct token.
15829         assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo(
15830                 NotificationManagerService.ALLOWLIST_TOKEN);
15831         assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo(
15832                 NotificationManagerService.ALLOWLIST_TOKEN);
15833     }
15834 
15835     /**
15836      * Replicates the behavior of {@link Notification#writeToParcel} but excluding the
15837      * "always use the same allowlist token as the root notification" parts.
15838      */
15839     private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif,
15840             ArraySet<PendingIntent> allPendingIntents) {
15841         int flags = 0;
15842         parcel.writeInt(1); // version?
15843 
15844         parcel.writeStrongBinder(notif.getAllowlistToken());
15845         parcel.writeLong(notif.when);
15846         parcel.writeLong(notif.creationTime);
15847         if (notif.getSmallIcon() != null) {
15848             parcel.writeInt(1);
15849             notif.getSmallIcon().writeToParcel(parcel, 0);
15850         } else {
15851             parcel.writeInt(0);
15852         }
15853         parcel.writeInt(notif.number);
15854         if (notif.contentIntent != null) {
15855             parcel.writeInt(1);
15856             notif.contentIntent.writeToParcel(parcel, 0);
15857         } else {
15858             parcel.writeInt(0);
15859         }
15860         if (notif.deleteIntent != null) {
15861             parcel.writeInt(1);
15862             notif.deleteIntent.writeToParcel(parcel, 0);
15863         } else {
15864             parcel.writeInt(0);
15865         }
15866         if (notif.tickerText != null) {
15867             parcel.writeInt(1);
15868             TextUtils.writeToParcel(notif.tickerText, parcel, flags);
15869         } else {
15870             parcel.writeInt(0);
15871         }
15872         if (notif.tickerView != null) {
15873             parcel.writeInt(1);
15874             notif.tickerView.writeToParcel(parcel, 0);
15875         } else {
15876             parcel.writeInt(0);
15877         }
15878         if (notif.contentView != null) {
15879             parcel.writeInt(1);
15880             notif.contentView.writeToParcel(parcel, 0);
15881         } else {
15882             parcel.writeInt(0);
15883         }
15884         if (notif.getLargeIcon() != null) {
15885             parcel.writeInt(1);
15886             notif.getLargeIcon().writeToParcel(parcel, 0);
15887         } else {
15888             parcel.writeInt(0);
15889         }
15890 
15891         parcel.writeInt(notif.defaults);
15892         parcel.writeInt(notif.flags);
15893 
15894         if (notif.sound != null) {
15895             parcel.writeInt(1);
15896             notif.sound.writeToParcel(parcel, 0);
15897         } else {
15898             parcel.writeInt(0);
15899         }
15900         parcel.writeInt(notif.audioStreamType);
15901 
15902         if (notif.audioAttributes != null) {
15903             parcel.writeInt(1);
15904             notif.audioAttributes.writeToParcel(parcel, 0);
15905         } else {
15906             parcel.writeInt(0);
15907         }
15908 
15909         parcel.writeLongArray(notif.vibrate);
15910         parcel.writeInt(notif.ledARGB);
15911         parcel.writeInt(notif.ledOnMS);
15912         parcel.writeInt(notif.ledOffMS);
15913         parcel.writeInt(notif.iconLevel);
15914 
15915         if (notif.fullScreenIntent != null) {
15916             parcel.writeInt(1);
15917             notif.fullScreenIntent.writeToParcel(parcel, 0);
15918         } else {
15919             parcel.writeInt(0);
15920         }
15921 
15922         parcel.writeInt(notif.priority);
15923 
15924         parcel.writeString8(notif.category);
15925 
15926         parcel.writeString8(notif.getGroup());
15927 
15928         parcel.writeString8(notif.getSortKey());
15929 
15930         parcel.writeBundle(notif.extras); // null ok
15931 
15932         parcel.writeTypedArray(notif.actions, 0); // null ok
15933 
15934         if (notif.bigContentView != null) {
15935             parcel.writeInt(1);
15936             notif.bigContentView.writeToParcel(parcel, 0);
15937         } else {
15938             parcel.writeInt(0);
15939         }
15940 
15941         if (notif.headsUpContentView != null) {
15942             parcel.writeInt(1);
15943             notif.headsUpContentView.writeToParcel(parcel, 0);
15944         } else {
15945             parcel.writeInt(0);
15946         }
15947 
15948         parcel.writeInt(notif.visibility);
15949 
15950         if (notif.publicVersion != null) {
15951             parcel.writeInt(1);
15952             writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>());
15953         } else {
15954             parcel.writeInt(0);
15955         }
15956 
15957         parcel.writeInt(notif.color);
15958 
15959         if (notif.getChannelId() != null) {
15960             parcel.writeInt(1);
15961             parcel.writeString8(notif.getChannelId());
15962         } else {
15963             parcel.writeInt(0);
15964         }
15965         parcel.writeLong(notif.getTimeoutAfter());
15966 
15967         if (notif.getShortcutId() != null) {
15968             parcel.writeInt(1);
15969             parcel.writeString8(notif.getShortcutId());
15970         } else {
15971             parcel.writeInt(0);
15972         }
15973 
15974         if (notif.getLocusId() != null) {
15975             parcel.writeInt(1);
15976             notif.getLocusId().writeToParcel(parcel, 0);
15977         } else {
15978             parcel.writeInt(0);
15979         }
15980 
15981         parcel.writeInt(notif.getBadgeIconType());
15982 
15983         if (notif.getSettingsText() != null) {
15984             parcel.writeInt(1);
15985             TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags);
15986         } else {
15987             parcel.writeInt(0);
15988         }
15989 
15990         parcel.writeInt(notif.getGroupAlertBehavior());
15991 
15992         if (notif.getBubbleMetadata() != null) {
15993             parcel.writeInt(1);
15994             notif.getBubbleMetadata().writeToParcel(parcel, 0);
15995         } else {
15996             parcel.writeInt(0);
15997         }
15998 
15999         parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions());
16000 
16001         parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior
16002 
16003         // mUsesStandardHeader is not written because it should be recomputed in listeners
16004 
16005         parcel.writeArraySet(allPendingIntents);
16006     }
16007 
16008     @Test
16009     @SuppressWarnings("unchecked")
16010     public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException {
16011         Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID)
16012                 .setContentIntent(createPendingIntent("content"))
16013                 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID)
16014                         .setContentIntent(createPendingIntent("public"))
16015                         .build())
16016                 .extend(new Notification.WearableExtender()
16017                         .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID)
16018                                 .setContentIntent(createPendingIntent("wearPage"))
16019                                 .build()))
16020                 .build();
16021         // Binder transition: app -> NMS
16022         Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR);
16023         assertThat(receivedByNms.getAllowlistToken()).isEqualTo(
16024                 NotificationManagerService.ALLOWLIST_TOKEN);
16025         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
16026                 parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId);
16027         waitForIdle();
16028         assertThat(mService.mNotificationList).hasSize(1);
16029         Notification posted = mService.mNotificationList.get(0).getNotification();
16030         assertThat(posted.getAllowlistToken()).isEqualTo(
16031                 NotificationManagerService.ALLOWLIST_TOKEN);
16032         assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo(
16033                 NotificationManagerService.ALLOWLIST_TOKEN);
16034 
16035         ParceledListSlice<StatusBarNotification> listSentFromNms =
16036                 mBinderService.getAppActiveNotifications(mPkg, mUserId);
16037         // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it
16038         // (having a different one would produce the same effect; the relevant thing is to not let
16039         // out ALLOWLIST_TOKEN).
16040         // Note: for other tests, this is restored by constructing TestableNMS in setup().
16041         Notification.processAllowlistToken = null;
16042         ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel(
16043                 listSentFromNms, ParceledListSlice.CREATOR);
16044         Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification();
16045 
16046         assertThat(gottenBackByApp.getAllowlistToken()).isNull();
16047         assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull();
16048         assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull();
16049         assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull();
16050         assertThat(new Notification.WearableExtender(gottenBackByApp).getPages()
16051                 .get(0).getAllowlistToken()).isNull();
16052         assertThat(new Notification.WearableExtender(gottenBackByApp).getPages()
16053                 .get(0).contentIntent.getWhitelistToken()).isNull();
16054     }
16055 
16056     @Test
16057     public void enqueueNotification_allowlistsPendingIntents() throws RemoteException {
16058         PendingIntent contentIntent = createPendingIntent("content");
16059         PendingIntent actionIntent1 = createPendingIntent("action1");
16060         PendingIntent actionIntent2 = createPendingIntent("action2");
16061         Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID)
16062                 .setContentIntent(contentIntent)
16063                 .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build())
16064                 .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build())
16065                 .build();
16066 
16067         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
16068                 parcelAndUnparcel(n, Notification.CREATOR), mUserId);
16069 
16070         verify(mAmi, times(3)).setPendingIntentAllowlistDuration(
16071                 any(), any(), anyLong(),
16072                 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
16073                 eq(REASON_NOTIFICATION_SERVICE), any());
16074         verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(),
16075                 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
16076         contentIntent.cancel();
16077         actionIntent2.cancel();
16078         actionIntent1.cancel();
16079     }
16080 
16081     @Test
16082     public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion()
16083             throws RemoteException {
16084         PendingIntent contentIntent = createPendingIntent("content");
16085         PendingIntent actionIntent = createPendingIntent("action");
16086         PendingIntent publicContentIntent = createPendingIntent("publicContent");
16087         PendingIntent publicActionIntent = createPendingIntent("publicAction");
16088         Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID)
16089                 .setContentIntent(contentIntent)
16090                 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
16091                 .setPublicVersion(new Notification.Builder(mContext, "channel")
16092                         .setContentIntent(publicContentIntent)
16093                         .addAction(new Notification.Action.Builder(
16094                                 null, "publicAction", publicActionIntent).build())
16095                         .build())
16096                 .build();
16097 
16098         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
16099                 parcelAndUnparcel(source, Notification.CREATOR), mUserId);
16100 
16101         verify(mAmi, times(4)).setPendingIntentAllowlistDuration(
16102                 any(), any(), anyLong(),
16103                 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
16104                 eq(REASON_NOTIFICATION_SERVICE), any());
16105         verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(),
16106                 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
16107         contentIntent.cancel();
16108         publicContentIntent.cancel();
16109         actionIntent.cancel();
16110         publicActionIntent.cancel();
16111     }
16112 
16113     @Test
16114     @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
16115     public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() {
16116         mService.mZenModeHelper = mock(ZenModeHelper.class);
16117         mService.setPreferencesHelper(mPreferencesHelper);
16118 
16119         UserInfo prevUser = new UserInfo();
16120         prevUser.id = 10;
16121         UserInfo newUser = new UserInfo();
16122         newUser.id = 20;
16123 
16124         mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser));
16125 
16126         InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
16127         inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
16128         inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
16129         inOrder.verifyNoMoreInteractions();
16130     }
16131 
16132     @Test
16133     @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
16134     public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() {
16135         Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
16136         intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
16137         mService.mZenModeHelper = mock(ZenModeHelper.class);
16138         mService.setPreferencesHelper(mPreferencesHelper);
16139 
16140         mUserIntentReceiver.onReceive(mContext, intent);
16141 
16142         InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
16143         inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
16144         inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
16145         inOrder.verifyNoMoreInteractions();
16146     }
16147 
16148     @Test
16149     public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception {
16150         final String notReal = "NOT REAL";
16151         final var checker = mService.permissionChecker;
16152 
16153         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
16154                 PackageManager.NameNotFoundException.class);
16155 
16156         assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse();
16157         verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt());
16158         verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean());
16159         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt());
16160         verify(mListeners, never()).isComponentEnabledForPackage(any());
16161         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16162     }
16163 
16164     @Test
16165     public void isNotificationPolicyAccessGranted_hasPermission() throws Exception {
16166         final String packageName = "target";
16167         final int uid = 123;
16168         final var checker = mService.permissionChecker;
16169 
16170         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16171         when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true))
16172                 .thenReturn(PackageManager.PERMISSION_GRANTED);
16173 
16174         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16175         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16176         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16177         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt());
16178         verify(mListeners, never()).isComponentEnabledForPackage(any());
16179         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16180     }
16181 
16182     @Test
16183     public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception {
16184         final String packageName = "target";
16185         final int uid = 123;
16186         final var checker = mService.permissionChecker;
16187 
16188         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16189         when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt()))
16190                 .thenReturn(true);
16191 
16192         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16193         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16194         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16195         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16196         verify(mListeners, never()).isComponentEnabledForPackage(any());
16197         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16198     }
16199 
16200     @Test
16201     public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception {
16202         final String packageName = "target";
16203         final int uid = 123;
16204         final var checker = mService.permissionChecker;
16205 
16206         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16207         when(mListeners.isComponentEnabledForPackage(packageName)).thenReturn(true);
16208 
16209         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16210         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16211         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16212         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16213         verify(mListeners).isComponentEnabledForPackage(packageName);
16214         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16215     }
16216 
16217     @Test
16218     public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception {
16219         final String packageName = "target";
16220         final int uid = 123;
16221         final var checker = mService.permissionChecker;
16222 
16223         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16224         when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true);
16225 
16226         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16227         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16228         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16229         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16230         verify(mListeners).isComponentEnabledForPackage(packageName);
16231         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16232     }
16233 
16234     /**
16235      * b/292163859
16236      */
16237     @Test
16238     public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception {
16239         final String packageName = "target";
16240         final int uid = 123;
16241         final int callingUid = Binder.getCallingUid();
16242         final var checker = mService.permissionChecker;
16243 
16244         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16245         when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true);
16246 
16247         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
16248         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16249         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16250         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16251         verify(mListeners).isComponentEnabledForPackage(packageName);
16252         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16253         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid);
16254     }
16255 
16256     @Test
16257     public void isNotificationPolicyAccessGranted_notGranted() throws Exception {
16258         final String packageName = "target";
16259         final int uid = 123;
16260         final var checker = mService.permissionChecker;
16261 
16262         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16263 
16264         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
16265         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16266         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16267         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16268         verify(mListeners).isComponentEnabledForPackage(packageName);
16269         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16270     }
16271 
16272     @Test
16273     public void testResetDefaultDnd() {
16274         TestableNotificationManagerService service = spy(mService);
16275         UserInfo user = new UserInfo(0, "owner", 0);
16276         when(mUm.getAliveUsers()).thenReturn(List.of(user));
16277         doReturn(false).when(service).isDNDMigrationDone(anyInt());
16278 
16279         service.resetDefaultDndIfNecessary();
16280 
16281         verify(mConditionProviders, times(1)).removeDefaultFromConfig(user.id);
16282         verify(mConditionProviders, times(1)).resetDefaultFromConfig();
16283         verify(service, times(1)).allowDndPackages(user.id);
16284         verify(service, times(1)).setDNDMigrationDone(user.id);
16285     }
16286 
16287     @Test
16288     public void testProfileUnavailableIntent() throws RemoteException {
16289         mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE,
16290                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
16291         simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE);
16292         verify(mWorkerHandler).post(any(Runnable.class));
16293         verify(mSnoozeHelper).clearData(anyInt());
16294     }
16295 
16296 
16297     @Test
16298     public void testManagedProfileUnavailableIntent() throws RemoteException {
16299         mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE,
16300                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
16301         simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
16302         verify(mWorkerHandler).post(any(Runnable.class));
16303         verify(mSnoozeHelper).clearData(anyInt());
16304     }
16305 
16306     @Test
16307     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16308     public void setDeviceEffectsApplier_succeeds() throws Exception {
16309         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
16310 
16311         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
16312 
16313         mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
16314         // No exception!
16315     }
16316 
16317     @Test
16318     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16319     public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
16320         initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
16321 
16322         assertThrows(IllegalStateException.class, () ->
16323                 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
16324     }
16325 
16326     @Test
16327     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16328     public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
16329         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
16330 
16331         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
16332         assertThrows(IllegalStateException.class, () ->
16333                 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
16334     }
16335 
16336     @Test
16337     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16338     public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
16339         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16340         mService.setCallerIsNormalPackage();
16341         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
16342         mService.mZenModeHelper = zenHelper;
16343         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16344                 .thenReturn(true);
16345 
16346         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16347         mBinderService.setNotificationPolicy("package", policy, false);
16348 
16349         verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(any(), eq("package"), anyInt(),
16350                 eq(policy));
16351     }
16352 
16353     @Test
16354     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16355     public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException {
16356         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16357         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16358         mService.mZenModeHelper = zenModeHelper;
16359         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16360                 .thenReturn(true);
16361         mService.isSystemUid = true;
16362 
16363         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16364         mBinderService.setNotificationPolicy("package", policy, false);
16365 
16366         verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt());
16367     }
16368 
16369     @Test
16370     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16371     public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy()
16372             throws RemoteException {
16373         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16374                 AssociationRequest.DEVICE_PROFILE_WATCH, true);
16375     }
16376 
16377     @Test
16378     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16379     public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy()
16380             throws RemoteException {
16381         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16382                 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
16383     }
16384 
16385     @Test
16386     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16387     public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy()
16388             throws RemoteException {
16389         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16390                 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
16391     }
16392 
16393     private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16394             @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
16395             throws RemoteException {
16396         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16397         mService.setCallerIsNormalPackage();
16398         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16399         mService.mZenModeHelper = zenModeHelper;
16400         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16401                 .thenReturn(true);
16402         when(mCompanionMgr.getAssociations(anyString(), anyInt()))
16403                 .thenReturn(ImmutableList.of(
16404                         new AssociationInfo.Builder(1, mUserId, "package")
16405                                 .setDisplayName("My connected device")
16406                                 .setDeviceProfile(deviceProfile)
16407                                 .build()));
16408 
16409         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16410         mBinderService.setNotificationPolicy("package", policy, false);
16411 
16412         if (canSetGlobalPolicy) {
16413             verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt());
16414         } else {
16415             verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(any(), anyString(), anyInt(),
16416                     eq(policy));
16417         }
16418     }
16419 
16420     @Test
16421     @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16422     public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException {
16423         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16424         mService.setCallerIsNormalPackage();
16425         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16426         mService.mZenModeHelper = zenModeHelper;
16427         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16428                 .thenReturn(true);
16429 
16430         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16431         mBinderService.setNotificationPolicy("package", policy, false);
16432 
16433         verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt());
16434     }
16435 
16436     @Test
16437     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16438     public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException {
16439         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16440         mService.setCallerIsNormalPackage();
16441         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
16442         mService.mZenModeHelper = zenHelper;
16443         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16444                 .thenReturn(true);
16445 
16446         mBinderService.getNotificationPolicy("package");
16447 
16448         verify(zenHelper).getNotificationPolicyFromImplicitZenRule(any(), eq("package"));
16449     }
16450 
16451     @Test
16452     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16453     public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException {
16454         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16455         mService.setCallerIsNormalPackage();
16456         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
16457         mService.mZenModeHelper = zenHelper;
16458         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16459                 .thenReturn(true);
16460 
16461         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
16462 
16463         verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("package"), anyInt(),
16464                 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
16465     }
16466 
16467     @Test
16468     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16469     public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException {
16470         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16471         mService.setCallerIsNormalPackage();
16472         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16473         mService.mZenModeHelper = zenModeHelper;
16474         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16475                 .thenReturn(true);
16476         mService.isSystemUid = true;
16477 
16478         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
16479 
16480         verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS),
16481                 eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), eq("package"), anyInt());
16482     }
16483 
16484     @Test
16485     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16486     public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException {
16487         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16488                 AssociationRequest.DEVICE_PROFILE_WATCH, true);
16489     }
16490 
16491     @Test
16492     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16493     public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException {
16494         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16495                 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
16496     }
16497 
16498     @Test
16499     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16500     public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen()
16501             throws RemoteException {
16502         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16503                 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
16504     }
16505 
16506     private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16507             @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
16508             throws RemoteException {
16509         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
16510         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16511         mService.mZenModeHelper = zenModeHelper;
16512         mService.setCallerIsNormalPackage();
16513         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16514                 .thenReturn(true);
16515         when(mCompanionMgr.getAssociations(anyString(), anyInt()))
16516                 .thenReturn(ImmutableList.of(
16517                         new AssociationInfo.Builder(1, mUserId, "package")
16518                                 .setDisplayName("My connected device")
16519                                 .setDeviceProfile(deviceProfile)
16520                                 .build()));
16521 
16522         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
16523 
16524         if (canSetGlobalPolicy) {
16525             verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS),
16526                     eq(null), eq(ZenModeConfig.ORIGIN_APP), anyString(), eq("package"), anyInt());
16527         } else {
16528             verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), anyString(), anyInt(),
16529                     eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
16530         }
16531     }
16532 
16533     @Test
16534     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16535     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16536     public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen()
16537             throws Exception {
16538         mService.setCallerIsNormalPackage();
16539         mService.mZenModeHelper = mock(ZenModeHelper.class);
16540         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
16541         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
16542         info.component = new ComponentName("pkg", "cls");
16543 
16544         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
16545                 INTERRUPTION_FILTER_PRIORITY);
16546 
16547         verify(mService.mZenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("pkg"),
16548                 eq(mUid), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
16549     }
16550 
16551     @Test
16552     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16553     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16554     public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen()
16555             throws Exception {
16556         mService.isSystemUid = true;
16557         mService.mZenModeHelper = mock(ZenModeHelper.class);
16558         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
16559         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
16560         info.component = new ComponentName("pkg", "cls");
16561 
16562         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
16563                 INTERRUPTION_FILTER_PRIORITY);
16564 
16565         verify(mService.mZenModeHelper).setManualZenMode(any(),
16566                 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM),
16567                 anyString(), eq("pkg"), eq(mUid));
16568     }
16569 
16570     @Test
16571     @DisableFlags(android.app.Flags.FLAG_MODES_API)
16572     public void requestInterruptionFilterFromListener_flagOff_callsRequestFromListener()
16573             throws Exception {
16574         mService.setCallerIsNormalPackage();
16575         mService.mZenModeHelper = mock(ZenModeHelper.class);
16576         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
16577         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
16578         info.component = new ComponentName("pkg", "cls");
16579 
16580         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
16581                 INTERRUPTION_FILTER_PRIORITY);
16582 
16583         verify(mService.mZenModeHelper).requestFromListener(eq(info.component),
16584                 eq(INTERRUPTION_FILTER_PRIORITY), eq(mUid), /* fromSystemOrSystemUi= */ eq(false));
16585     }
16586 
16587     @Test
16588     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16589     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16590     public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception {
16591         setUpRealZenTest();
16592         mService.setCallerIsNormalPackage();
16593         assertThat(mBinderService.getAutomaticZenRules()).isEmpty();
16594 
16595         // Create an implicit zen rule by calling setNotificationPolicy from an app.
16596         mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false);
16597         assertThat(mBinderService.getAutomaticZenRules()).hasSize(1);
16598         Map.Entry<String, AutomaticZenRule> rule = getOnlyElement(
16599                 mBinderService.getAutomaticZenRules().entrySet());
16600         assertThat(rule.getValue().getOwner()).isNull();
16601         assertThat(rule.getValue().getConfigurationActivity()).isNull();
16602 
16603         // Now try to update said rule (e.g. disable it). Should fail.
16604         // We also validate the exception message because NPE could be thrown by all sorts of test
16605         // issues (e.g. misconfigured mocks).
16606         rule.getValue().setEnabled(false);
16607         NullPointerException e = assertThrows(NullPointerException.class,
16608                 () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false));
16609         assertThat(e.getMessage()).isEqualTo(
16610                 "Rule must have a ConditionProviderService and/or configuration activity");
16611     }
16612 
16613     @Test
16614     @EnableFlags(android.app.Flags.FLAG_MODES_API)
16615     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16616     public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception {
16617         setUpRealZenTest();
16618         mService.setCallerIsNormalPackage();
16619         assertThat(mBinderService.getAutomaticZenRules()).isEmpty();
16620 
16621         // Create an implicit zen rule by calling setNotificationPolicy from an app.
16622         mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false);
16623         assertThat(mBinderService.getAutomaticZenRules()).hasSize(1);
16624         Map.Entry<String, AutomaticZenRule> rule = getOnlyElement(
16625                 mBinderService.getAutomaticZenRules().entrySet());
16626         assertThat(rule.getValue().getOwner()).isNull();
16627         assertThat(rule.getValue().getConfigurationActivity()).isNull();
16628 
16629         // Now update said rule from Settings (e.g. disable it). Should work!
16630         mService.isSystemUid = true;
16631         rule.getValue().setEnabled(false);
16632         mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false);
16633 
16634         Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement(
16635                 mBinderService.getAutomaticZenRules().entrySet());
16636         assertThat(updatedRule.getValue().isEnabled()).isFalse();
16637     }
16638 
16639     @Test
16640     @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI})
16641     public void setNotificationPolicy_fromSystemApp_appliesPriorityChannelsAllowed()
16642             throws Exception {
16643         setUpRealZenTest();
16644         // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default").
16645         mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT,
16646                 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0),
16647                 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID);
16648 
16649         // The caller will supply states with "wrong" hasPriorityChannels.
16650         int stateBlockingPriorityChannels = Policy.policyState(false, false);
16651         mBinderService.setNotificationPolicy(mPkg,
16652                 new Policy(1, 0, 0, 0, stateBlockingPriorityChannels, 0), false);
16653 
16654         // hasPriorityChannels is untouched and allowPriorityChannels was updated.
16655         assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1);
16656         assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo(
16657                 Policy.policyState(true, false));
16658 
16659         // Same but setting allowPriorityChannels to true.
16660         int stateAllowingPriorityChannels = Policy.policyState(false, true);
16661         mBinderService.setNotificationPolicy(mPkg,
16662                 new Policy(2, 0, 0, 0, stateAllowingPriorityChannels, 0), false);
16663 
16664         assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(2);
16665         assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo(
16666                 Policy.policyState(true, true));
16667     }
16668 
16669     @Test
16670     @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI})
16671     @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16672     public void setNotificationPolicy_fromRegularAppThatCanModifyPolicy_ignoresState()
16673             throws Exception {
16674         setUpRealZenTest();
16675         // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default").
16676         mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT,
16677                 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0),
16678                 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID);
16679         mService.setCallerIsNormalPackage();
16680 
16681         mBinderService.setNotificationPolicy(mPkg,
16682                 new Policy(1, 0, 0, 0, Policy.policyState(false, false), 0), false);
16683 
16684         // Policy was updated but the attempt to change state was ignored (it's a @hide API).
16685         assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1);
16686         assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo(
16687                 Policy.policyState(true, true));
16688     }
16689 
16690     /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */
16691     private void setUpRealZenTest() throws Exception {
16692         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16693                 .thenReturn(true);
16694 
16695         int iconResId = 79;
16696         String iconResName = "icon_79";
16697         String pkg = mContext.getPackageName();
16698         ApplicationInfo appInfoSpy = spy(new ApplicationInfo());
16699         appInfoSpy.icon = iconResId;
16700         when(appInfoSpy.loadLabel(any())).thenReturn("Test App");
16701         when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy);
16702 
16703         when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName);
16704         when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId);
16705         when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources);
16706     }
16707 
16708     @Test
16709     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
16710     public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception {
16711         Notification n = new Notification.Builder(mContext, "test")
16712                 .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true)
16713                 .build();
16714 
16715         assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
16716 
16717         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
16718 
16719         assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
16720     }
16721 
16722     @Test
16723     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne()
16724             throws RemoteException {
16725         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
16726                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16727 
16728         // Create recent notification.
16729         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16730                 System.currentTimeMillis());
16731         mService.addNotification(nr1);
16732 
16733         // Create old notification.
16734         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16735                 System.currentTimeMillis() - 60000);
16736         mService.addNotification(nr2);
16737 
16738         // Cancel specific notifications via listener.
16739         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
16740         mService.getBinderService().cancelNotificationsFromListener(null, keys);
16741         waitForIdle();
16742 
16743         // Notifications should not be active anymore.
16744         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
16745         assertThat(notifications).isEmpty();
16746         assertEquals(0, mService.getNotificationRecordCount());
16747         // Ensure cancel event is logged.
16748         verify(mAppOpsManager).noteOpNoThrow(
16749                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null);
16750     }
16751 
16752     @Test
16753     public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException {
16754         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
16755                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16756 
16757         // Create old notifications.
16758         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16759                 System.currentTimeMillis() - 60000);
16760         mService.addNotification(nr1);
16761 
16762         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16763                 System.currentTimeMillis() - 60000);
16764         mService.addNotification(nr2);
16765 
16766         // Cancel specific notifications via listener.
16767         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
16768         mService.getBinderService().cancelNotificationsFromListener(null, keys);
16769         waitForIdle();
16770 
16771         // Notifications should not be active anymore.
16772         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
16773         assertThat(notifications).isEmpty();
16774         assertEquals(0, mService.getNotificationRecordCount());
16775         // Ensure cancel event is not logged.
16776         verify(mAppOpsManager, never()).noteOpNoThrow(
16777                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
16778                 any(), any());
16779     }
16780 
16781     @Test
16782     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled()
16783             throws RemoteException {
16784         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
16785                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16786 
16787         // Create recent notification.
16788         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16789                 System.currentTimeMillis());
16790         mService.addNotification(nr1);
16791 
16792         // Create old notification.
16793         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16794                 System.currentTimeMillis() - 60000);
16795         mService.addNotification(nr2);
16796 
16797         // Cancel specific notifications via listener.
16798         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
16799         mService.getBinderService().cancelNotificationsFromListener(null, keys);
16800         waitForIdle();
16801 
16802         // Notifications should not be active anymore.
16803         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
16804         assertThat(notifications).isEmpty();
16805         assertEquals(0, mService.getNotificationRecordCount());
16806         // Ensure cancel event is not logged due to flag being disabled.
16807         verify(mAppOpsManager, never()).noteOpNoThrow(
16808                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
16809                 any(), any());
16810     }
16811 
16812     @Test
16813     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll()
16814             throws RemoteException {
16815         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
16816                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16817 
16818         // Create recent notification.
16819         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16820                 System.currentTimeMillis());
16821         mService.addNotification(nr1);
16822 
16823         // Create old notification.
16824         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16825                 System.currentTimeMillis() - 60000);
16826         mService.addNotification(nr2);
16827 
16828         // Cancel all notifications via listener.
16829         mService.getBinderService().cancelNotificationsFromListener(null, null);
16830         waitForIdle();
16831 
16832         // Notifications should not be active anymore.
16833         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
16834         assertThat(notifications).isEmpty();
16835         assertEquals(0, mService.getNotificationRecordCount());
16836         // Ensure cancel event is logged.
16837         verify(mAppOpsManager).noteOpNoThrow(
16838                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null);
16839     }
16840 
16841     @Test
16842     public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException {
16843         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
16844                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16845 
16846         // Create old notifications.
16847         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16848                 System.currentTimeMillis() - 60000);
16849         mService.addNotification(nr1);
16850 
16851         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16852                 System.currentTimeMillis() - 60000);
16853         mService.addNotification(nr2);
16854 
16855         // Cancel all notifications via listener.
16856         mService.getBinderService().cancelNotificationsFromListener(null, null);
16857         waitForIdle();
16858 
16859         // Notifications should not be active anymore.
16860         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
16861         assertThat(notifications).isEmpty();
16862         assertEquals(0, mService.getNotificationRecordCount());
16863         // Ensure cancel event is not logged.
16864         verify(mAppOpsManager, never()).noteOpNoThrow(
16865                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
16866                 any(), any());
16867     }
16868 
16869     @Test
16870     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled()
16871             throws RemoteException {
16872         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
16873                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16874 
16875         // Create recent notification.
16876         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16877                 System.currentTimeMillis());
16878         mService.addNotification(nr1);
16879 
16880         // Create old notification.
16881         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16882                 System.currentTimeMillis() - 60000);
16883         mService.addNotification(nr2);
16884 
16885         // Cancel all notifications via listener.
16886         mService.getBinderService().cancelNotificationsFromListener(null, null);
16887         waitForIdle();
16888 
16889         // Notifications should not be active anymore.
16890         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
16891         assertThat(notifications).isEmpty();
16892         assertEquals(0, mService.getNotificationRecordCount());
16893         // Ensure cancel event is not logged due to flag being disabled.
16894         verify(mAppOpsManager, never()).noteOpNoThrow(
16895                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
16896                 any(), any());
16897     }
16898 
16899     @Test
16900     @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS)
16901     public void testSetPrivateNotificationsAllowed() throws Exception {
16902         when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS))
16903                 .thenReturn(PERMISSION_GRANTED);
16904         mBinderService.setPrivateNotificationsAllowed(false);
16905         Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED)
16906                 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false);
16907         ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class);
16908         verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE));
16909 
16910         assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction());
16911         assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true));
16912         assertFalse(mBinderService.getPrivateNotificationsAllowed());
16913     }
16914 
16915     @Test
16916     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
16917     public void testCallNotificationListener_NotifiedOnPostCallStyle() throws Exception {
16918         ICallNotificationEventCallback listener = mock(
16919                 ICallNotificationEventCallback.class);
16920         when(listener.asBinder()).thenReturn(mock(IBinder.class));
16921         mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.CURRENT, listener);
16922         waitForIdle();
16923 
16924         final UserHandle userHandle = UserHandle.getUserHandleForUid(mUid);
16925         final NotificationRecord r = createAndPostCallStyleNotification(mPkg, userHandle,
16926                 "testCallNotificationListener_NotifiedOnPostCallStyle");
16927 
16928         verify(listener, times(1)).onCallNotificationPosted(mPkg, userHandle);
16929 
16930         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
16931                 r.getSbn().getUserId());
16932         waitForIdle();
16933 
16934         verify(listener, times(1)).onCallNotificationRemoved(mPkg, userHandle);
16935     }
16936 
16937     @Test
16938     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
16939     public void testCallNotificationListener_NotNotifiedOnPostNonCallStyle() throws Exception {
16940         ICallNotificationEventCallback listener = mock(
16941                 ICallNotificationEventCallback.class);
16942         when(listener.asBinder()).thenReturn(mock(IBinder.class));
16943         mBinderService.registerCallNotificationEventListener(mPkg,
16944                 UserHandle.getUserHandleForUid(mUid), listener);
16945         waitForIdle();
16946 
16947         Notification.Builder nb = new Notification.Builder(mContext,
16948                 mTestNotificationChannel.getId()).setSmallIcon(android.R.drawable.sym_def_app_icon);
16949         final NotificationRecord r = createAndPostNotification(nb,
16950                 "testCallNotificationListener_NotNotifiedOnPostNonCallStyle");
16951 
16952         verify(listener, never()).onCallNotificationPosted(anyString(), any());
16953 
16954         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
16955                 r.getSbn().getUserId());
16956         waitForIdle();
16957 
16958         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
16959     }
16960 
16961     @Test
16962     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
16963     public void testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId()
16964             throws Exception {
16965         ICallNotificationEventCallback listener = mock(
16966                 ICallNotificationEventCallback.class);
16967         when(listener.asBinder()).thenReturn(mock(IBinder.class));
16968         mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.ALL, listener);
16969         waitForIdle();
16970 
16971         final UserHandle otherUser = UserHandle.of(2);
16972         final NotificationRecord r = createAndPostCallStyleNotification(mPkg,
16973                 otherUser, "testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId");
16974 
16975         verify(listener, times(1)).onCallNotificationPosted(mPkg, otherUser);
16976 
16977         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
16978                 r.getSbn().getUserId());
16979         waitForIdle();
16980 
16981         verify(listener, times(1)).onCallNotificationRemoved(mPkg, otherUser);
16982     }
16983 
16984     @Test
16985     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
16986     public void testCallNotificationListener_differentPackage_notNotified() throws Exception {
16987         final String packageName = "package";
16988         ICallNotificationEventCallback listener = mock(
16989                 ICallNotificationEventCallback.class);
16990         when(listener.asBinder()).thenReturn(mock(IBinder.class));
16991         mBinderService.registerCallNotificationEventListener(packageName, UserHandle.ALL, listener);
16992         waitForIdle();
16993 
16994         final NotificationRecord r = createAndPostCallStyleNotification(mPkg,
16995                 UserHandle.of(mUserId),
16996                 "testCallNotificationListener_differentPackage_notNotified");
16997 
16998         verify(listener, never()).onCallNotificationPosted(anyString(), any());
16999 
17000         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
17001                 r.getSbn().getUserId());
17002         waitForIdle();
17003 
17004         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
17005     }
17006 
17007     @Test
17008     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17009     public void rankingTime_newNotification_noisy_matchesSbn() throws Exception {
17010         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId);
17011 
17012         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17013                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17014         waitForIdle();
17015 
17016         NotificationRecord posted = mService.mNotificationList.get(0);
17017         long originalPostTime = posted.getSbn().getPostTime();
17018         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17019     }
17020 
17021     @Test
17022     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17023     public void rankingTime_newNotification_silent_matchesSbn() throws Exception {
17024         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17025         NotificationRecord nr = generateNotificationRecord(low, mUserId);
17026 
17027         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17028                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17029         waitForIdle();
17030 
17031         NotificationRecord posted = mService.mNotificationList.get(0);
17032         long originalPostTime = posted.getSbn().getPostTime();
17033         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17034     }
17035 
17036     @Test
17037     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17038     public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception {
17039         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17040         NotificationRecord nr = generateNotificationRecord(low, mUserId);
17041 
17042         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17043                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17044         waitForIdle();
17045         NotificationRecord posted = mService.mNotificationList.get(0);
17046         long originalPostTime = posted.getSbn().getPostTime();
17047         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17048 
17049         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17050                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17051         waitForIdle();
17052         assertThat(mService.mNotificationList.get(0).getRankingTimeMs())
17053                 .isEqualTo(originalPostTime);
17054     }
17055 
17056     @Test
17057     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17058     public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception {
17059         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17060         NotificationRecord nr = generateNotificationRecord(low, 0, mUserId);
17061 
17062         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17063                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17064         waitForIdle();
17065         NotificationRecord posted = mService.mNotificationList.get(0);
17066         long originalPostTime = posted.getSbn().getPostTime();
17067         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17068 
17069         NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar");
17070         // no attention helper mocked behavior needed because this does not make noise
17071         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17072                 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
17073                 nrUpdate.getSbn().getUserId());
17074         waitForIdle();
17075 
17076         posted = mService.mNotificationList.get(0);
17077         assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
17078         assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
17079     }
17080 
17081     @Test
17082     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17083     public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception {
17084         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17085         NotificationRecord nr = generateNotificationRecord(low, mUserId);
17086 
17087         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17088                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17089         waitForIdle();
17090         NotificationRecord posted = mService.mNotificationList.get(0);
17091         long originalPostTime = posted.getSbn().getPostTime();
17092         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17093 
17094         NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId);
17095         when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() {
17096             public Object answer(InvocationOnMock invocation) {
17097                 Object[] args = invocation.getArguments();
17098                 ((NotificationRecord) args[0]).resetRankingTime();
17099                 return 2; // beep
17100             }
17101         });
17102         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17103                 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
17104                 nrUpdate.getSbn().getUserId());
17105         waitForIdle();
17106         posted = mService.mNotificationList.get(0);
17107         assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
17108         assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
17109     }
17110 
17111     @Test
17112     @EnableFlags(android.app.Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA)
17113     public void testRestrictAudioAttributes_listenersGetCorrectAttributes() throws Exception {
17114         NotificationChannel sound = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
17115         sound.setSound(Uri.EMPTY, new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build());
17116         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(
17117                 Arrays.asList(sound)));
17118 
17119         Notification n = new Notification.Builder(mContext, "a")
17120                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17121                 .build();
17122         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17123                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17124 
17125         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
17126                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
17127         waitForIdle();
17128 
17129         ArgumentCaptor<NotificationRecord> captor =
17130                 ArgumentCaptor.forClass(NotificationRecord.class);
17131         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17132                 captor.capture(), any(), anyBoolean());
17133 
17134         assertThat(captor.getValue().getChannel().getAudioAttributes().getUsage())
17135                 .isEqualTo(USAGE_NOTIFICATION);
17136     }
17137 
17138     @Test
17139     @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
17140     public void testFixNotification_missingTtl() throws Exception {
17141         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17142                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17143                 .build();
17144 
17145         mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
17146 
17147         assertThat(n.getTimeoutAfter()).isEqualTo(NOTIFICATION_TTL);
17148     }
17149 
17150     @Test
17151     @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
17152     public void testFixNotification_doesNotOverwriteTtl() throws Exception {
17153         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17154                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17155                 .setTimeoutAfter(20)
17156                 .build();
17157 
17158         mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
17159 
17160         assertThat(n.getTimeoutAfter()).isEqualTo(20);
17161     }
17162 
17163     @Test
17164     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
17165     public void testRejectOldNotification_oldWhen() throws Exception {
17166         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17167                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17168                 .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis())
17169                 .build();
17170         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17171                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17172         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17173 
17174         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
17175                 .isFalse();
17176     }
17177 
17178     @Test
17179     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
17180     public void testRejectOldNotification_mediumOldWhen() throws Exception {
17181         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17182                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17183                 .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis())
17184                 .build();
17185         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17186                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17187         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17188 
17189         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
17190                 .isTrue();
17191     }
17192 
17193     @Test
17194     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
17195     public void testRejectOldNotification_zeroWhen() throws Exception {
17196         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17197                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17198                 .setWhen(0)
17199                 .build();
17200         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17201                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17202         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17203 
17204         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
17205                 .isTrue();
17206     }
17207 
17208     @Test
17209     public void testClearUIJFromUninstallingPackage() throws Exception {
17210         NotificationRecord r =
17211                 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar");
17212         mService.addNotification(r);
17213 
17214         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt()))
17215                 .thenThrow(PackageManager.NameNotFoundException.class);
17216         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17217 
17218         mInternalService.cancelNotification(mPkg, mPkg, mUid, 0, r.getSbn().getTag(),
17219                 r.getSbn().getId(), mUserId);
17220 
17221         // no exception
17222     }
17223 
17224     @Test
17225     public void testPostFromMissingPackage_throws() throws Exception {
17226         NotificationRecord r =
17227                 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar");
17228 
17229         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt()))
17230                 .thenThrow(PackageManager.NameNotFoundException.class);
17231         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17232 
17233         try {
17234             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
17235                     r.getSbn().getId(), r.getSbn().getNotification(),
17236                     r.getSbn().getUserId());
17237             fail("Allowed to post a notification for an absent package");
17238         } catch (SecurityException e) {
17239             // yay
17240         }
17241     }
17242 
17243     @Test
17244     public void testGetEffectsSuppressor_noSuppressor() throws Exception {
17245         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17246         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17247         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true);
17248         assertThat(mBinderService.getEffectsSuppressor()).isNull();
17249     }
17250 
17251     @Test
17252     public void testGetEffectsSuppressor_suppressorSameApp() throws Exception {
17253         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17254         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17255         mService.isSystemUid = false;
17256         mService.isSystemAppId = false;
17257         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
17258                 HINT_HOST_DISABLE_EFFECTS);
17259         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true);
17260         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
17261     }
17262 
17263     @Test
17264     public void testGetEffectsSuppressor_suppressorDiffApp() throws Exception {
17265         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17266         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17267         mService.isSystemUid = false;
17268         mService.isSystemAppId = false;
17269         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
17270                 HINT_HOST_DISABLE_EFFECTS);
17271         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17272         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(null);
17273     }
17274 
17275     @Test
17276     public void testGetEffectsSuppressor_suppressorDiffAppSystemCaller() throws Exception {
17277         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17278         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17279         mService.isSystemUid = true;
17280         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
17281                 HINT_HOST_DISABLE_EFFECTS);
17282         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17283         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
17284     }
17285 
17286     @Test
17287     @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
17288     public void testApplyAdjustment_keyType_validType() throws Exception {
17289         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
17290         mService.addNotification(r);
17291         NotificationManagerService.WorkerHandler handler = mock(
17292                 NotificationManagerService.WorkerHandler.class);
17293         mService.setHandler(handler);
17294         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
17295         when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
17296 
17297         Bundle signals = new Bundle();
17298         signals.putInt(KEY_TYPE, TYPE_NEWS);
17299         Adjustment adjustment = new Adjustment(
17300                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
17301         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
17302         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17303 
17304         waitForIdle();
17305 
17306         r.applyAdjustments();
17307 
17308         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
17309 
17310         signals.putInt(KEY_TYPE, TYPE_PROMOTION);
17311         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17312         waitForIdle();
17313         r.applyAdjustments();
17314         assertThat(r.getChannel().getId()).isEqualTo(PROMOTIONS_ID);
17315 
17316         signals.putInt(KEY_TYPE, TYPE_SOCIAL_MEDIA);
17317         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17318         waitForIdle();
17319         r.applyAdjustments();
17320         assertThat(r.getChannel().getId()).isEqualTo(SOCIAL_MEDIA_ID);
17321 
17322         signals.putInt(KEY_TYPE, TYPE_CONTENT_RECOMMENDATION);
17323         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17324         waitForIdle();
17325         r.applyAdjustments();
17326         assertThat(r.getChannel().getId()).isEqualTo(RECS_ID);
17327     }
17328 
17329     @Test
17330     @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
17331             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
17332     public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception {
17333         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
17334         mService.addNotification(r);
17335         NotificationManagerService.WorkerHandler handler = mock(
17336                 NotificationManagerService.WorkerHandler.class);
17337         mService.setHandler(handler);
17338         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
17339         when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
17340 
17341         Bundle signals = new Bundle();
17342         signals.putInt(KEY_TYPE, TYPE_NEWS);
17343         Adjustment adjustment = new Adjustment(
17344                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
17345         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
17346         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17347 
17348         waitForIdle();
17349 
17350         r.applyAdjustments();
17351 
17352         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
17353 
17354         // When we block adjustments for this package
17355         when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false);
17356 
17357         signals.putInt(KEY_TYPE, TYPE_PROMOTION);
17358         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17359         waitForIdle();
17360         r.applyAdjustments();
17361         // Then the adjustment is not applied.
17362         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
17363     }
17364 
17365     @Test
17366     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17367     public void testSetCanBePromoted_granted() throws Exception {
17368         // qualifying posted notification
17369         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17370                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17371                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17372                 .setColor(Color.WHITE)
17373                 .setColorized(true)
17374                 .setOngoing(true)
17375                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17376                 .build();
17377 
17378         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17379                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17380         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17381 
17382         // qualifying enqueued notification
17383         Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17384                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17385                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17386                 .setColor(Color.WHITE)
17387                 .setColorized(true)
17388                 .setOngoing(true)
17389                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17390                 .build();
17391         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0,
17392                 n1, UserHandle.getUserHandleForUid(mUid), null, 0);
17393         NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel);
17394 
17395         // another package but otherwise would qualify
17396         Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17397                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17398                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17399                 .setColor(Color.WHITE)
17400                 .setColorized(true)
17401                 .setOngoing(true)
17402                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17403                 .build();
17404         StatusBarNotification sbn2 = new StatusBarNotification(PKG_O, PKG_O, 7, null, UID_O, 0,
17405                 n2, UserHandle.getUserHandleForUid(UID_O), null, 0);
17406         NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel);
17407 
17408         // not-qualifying posted notification
17409         Notification n3 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17410                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17411                 .build();
17412 
17413         StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17414                 n3, UserHandle.getUserHandleForUid(mUid), null, 0);
17415         NotificationRecord r3 = new NotificationRecord(mContext, sbn3, mTestNotificationChannel);
17416 
17417         mService.addNotification(r3);
17418         mService.addNotification(r2);
17419         mService.addNotification(r);
17420         mService.addEnqueuedNotification(r1);
17421 
17422         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17423 
17424         waitForIdle();
17425 
17426         ArgumentCaptor<NotificationRecord> captor =
17427                 ArgumentCaptor.forClass(NotificationRecord.class);
17428         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17429                 captor.capture(), any(), anyBoolean());
17430 
17431         // the posted one
17432         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17433                 FLAG_PROMOTED_ONGOING)).isTrue();
17434         // the enqueued one
17435         assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isTrue();
17436         // the other app
17437         assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17438         // same app, not qualifying
17439         assertThat(mService.hasFlag(r3.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17440     }
17441 
17442     @Test
17443     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17444     public void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception {
17445         // qualifying posted notification
17446         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17447                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17448                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17449                 .setColor(Color.WHITE)
17450                 .setColorized(true)
17451                 .setOngoing(true)
17452                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17453                 .build();
17454 
17455         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17456                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17457         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17458 
17459         mService.addNotification(r);
17460 
17461         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17462         waitForIdle();
17463         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17464         waitForIdle();
17465 
17466         ArgumentCaptor<NotificationRecord> captor =
17467                 ArgumentCaptor.forClass(NotificationRecord.class);
17468         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17469                 captor.capture(), any(), anyBoolean());
17470     }
17471 
17472     @Test
17473     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17474     public void testSetCanBePromoted_revoked() throws Exception {
17475         // start from true state
17476         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17477 
17478         // qualifying posted notification
17479         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17480                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17481                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17482                 .setColor(Color.WHITE)
17483                 .setColorized(true)
17484                 .setOngoing(true)
17485                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17486                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17487                 .build();
17488 
17489         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17490                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17491         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17492 
17493         // qualifying enqueued notification
17494         Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17495                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17496                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17497                 .setColor(Color.WHITE)
17498                 .setColorized(true)
17499                 .setOngoing(true)
17500                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17501                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17502                 .build();
17503         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0,
17504                 n1, UserHandle.getUserHandleForUid(mUid), null, 0);
17505         NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel);
17506 
17507         // doesn't qualify, same package
17508         Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17509                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17510                 .build();
17511         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17512                 n2, UserHandle.getUserHandleForUid(UID_O), null, 0);
17513         NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel);
17514 
17515         mService.addNotification(r2);
17516         mService.addNotification(r);
17517         mService.addEnqueuedNotification(r1);
17518 
17519         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17520 
17521         waitForIdle();
17522 
17523         ArgumentCaptor<NotificationRecord> captor =
17524                 ArgumentCaptor.forClass(NotificationRecord.class);
17525         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17526                 captor.capture(), any(), anyBoolean());
17527 
17528         // the posted one
17529         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17530                 FLAG_PROMOTED_ONGOING)).isFalse();
17531         // the enqueued one
17532         assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17533         // the not qualifying one
17534         assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17535     }
17536 
17537     @Test
17538     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17539     public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception {
17540         // start from true state
17541         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17542 
17543         // qualifying posted notification
17544         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17545                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17546                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17547                 .setColor(Color.WHITE)
17548                 .setColorized(true)
17549                 .setOngoing(true)
17550                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17551                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17552                 .build();
17553 
17554         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17555                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17556         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17557 
17558         mService.addNotification(r);
17559 
17560         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17561         waitForIdle();
17562         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17563         waitForIdle();
17564 
17565         ArgumentCaptor<NotificationRecord> captor =
17566                 ArgumentCaptor.forClass(NotificationRecord.class);
17567         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17568                 captor.capture(), any(), anyBoolean());
17569     }
17570 
17571     @Test
17572     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17573     public void testPostPromotableNotification() throws Exception {
17574         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17575         assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue();
17576 
17577         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17578                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17579                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17580                 .setColor(Color.WHITE)
17581                 .setColorized(true)
17582                 .setOngoing(true)
17583                 .build();
17584         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17585                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17586 
17587         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
17588                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
17589         waitForIdle();
17590 
17591         ArgumentCaptor<NotificationRecord> captor =
17592                 ArgumentCaptor.forClass(NotificationRecord.class);
17593         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17594                 captor.capture(), any(), anyBoolean());
17595 
17596         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17597                 FLAG_PROMOTED_ONGOING)).isTrue();
17598     }
17599 
17600     @Test
17601     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17602     public void testPostPromotableNotification_noPermission() throws Exception {
17603         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17604         assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isFalse();
17605 
17606         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17607                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17608                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17609                 .setColor(Color.WHITE)
17610                 .setColorized(true)
17611                 .setOngoing(true)
17612                 .build();
17613 
17614         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17615                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17616 
17617         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
17618                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
17619         waitForIdle();
17620 
17621         ArgumentCaptor<NotificationRecord> captor =
17622                 ArgumentCaptor.forClass(NotificationRecord.class);
17623         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17624                 captor.capture(), any(), anyBoolean());
17625 
17626         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17627                 FLAG_PROMOTED_ONGOING)).isFalse();
17628     }
17629 
17630     @Test
17631     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17632     public void testPostPromotableNotification_unimportantNotification() throws Exception {
17633         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17634         Notification n = new Notification.Builder(mContext, mMinChannel.getId())
17635                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17636                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17637                 .setColor(Color.WHITE)
17638                 .setColorized(true)
17639                 .setOngoing(true)
17640                 .build();
17641 
17642         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17643                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17644 
17645         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
17646                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
17647         waitForIdle();
17648 
17649         ArgumentCaptor<NotificationRecord> captor =
17650                 ArgumentCaptor.forClass(NotificationRecord.class);
17651         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17652                 captor.capture(), any(), anyBoolean());
17653 
17654         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17655                 FLAG_PROMOTED_ONGOING)).isFalse();
17656     }
17657 
17658     @Test
17659     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
17660     public void testAppCannotUseReservedBundleChannels() throws Exception {
17661         mService.mPreferencesHelper.createReservedChannel(mPkg, mUid, TYPE_NEWS);
17662         NotificationChannel news = mBinderService.getNotificationChannel(
17663                 mPkg, mContext.getUserId(), mPkg, NEWS_ID);
17664         assertThat(news).isNotNull();
17665 
17666         NotificationRecord nr = generateNotificationRecord(news);
17667         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
17668                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17669         waitForIdle();
17670 
17671         assertThat(mService.mNotificationList).isEmpty();
17672     }
17673 }
17674