• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.notification;
18 
19 import static android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS;
20 import static android.Manifest.permission.STATUS_BAR_SERVICE;
21 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
22 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
23 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
24 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
25 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
26 import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
27 import static android.app.Flags.FLAG_NM_SUMMARIZATION;
28 import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME;
29 import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
30 import static android.app.Notification.EXTRA_PICTURE;
31 import static android.app.Notification.EXTRA_PICTURE_ICON;
32 import static android.app.Notification.EXTRA_TEXT;
33 import static android.app.Notification.FLAG_AUTO_CANCEL;
34 import static android.app.Notification.FLAG_BUBBLE;
35 import static android.app.Notification.FLAG_CAN_COLORIZE;
36 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
37 import static android.app.Notification.FLAG_GROUP_SUMMARY;
38 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
39 import static android.app.Notification.FLAG_NO_CLEAR;
40 import static android.app.Notification.FLAG_NO_DISMISS;
41 import static android.app.Notification.FLAG_ONGOING_EVENT;
42 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
43 import static android.app.Notification.FLAG_PROMOTED_ONGOING;
44 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
45 import static android.app.Notification.GROUP_ALERT_CHILDREN;
46 import static android.app.Notification.VISIBILITY_PRIVATE;
47 import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
48 import static android.app.NotificationChannel.NEWS_ID;
49 import static android.app.NotificationChannel.PROMOTIONS_ID;
50 import static android.app.NotificationChannel.RECS_ID;
51 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
52 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
53 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
54 import static android.app.NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED;
55 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
56 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED;
57 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
58 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
59 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
60 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
61 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
62 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
63 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
64 import static android.app.NotificationManager.IMPORTANCE_HIGH;
65 import static android.app.NotificationManager.IMPORTANCE_LOW;
66 import static android.app.NotificationManager.IMPORTANCE_MAX;
67 import static android.app.NotificationManager.IMPORTANCE_MIN;
68 import static android.app.NotificationManager.IMPORTANCE_NONE;
69 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
70 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
71 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
72 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
73 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
74 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
78 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
79 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
80 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
81 import static android.app.PendingIntent.FLAG_IMMUTABLE;
82 import static android.app.PendingIntent.FLAG_MUTABLE;
83 import static android.app.PendingIntent.FLAG_ONE_SHOT;
84 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED;
85 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED;
86 import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
87 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
88 import static android.content.pm.PackageManager.FEATURE_TELECOM;
89 import static android.content.pm.PackageManager.FEATURE_WATCH;
90 import static android.content.pm.PackageManager.PERMISSION_DENIED;
91 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
92 import static android.media.AudioAttributes.USAGE_MEDIA;
93 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
94 import static android.os.Build.VERSION_CODES.O_MR1;
95 import static android.os.Build.VERSION_CODES.P;
96 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
97 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
98 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
99 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
100 import static android.os.UserHandle.USER_SYSTEM;
101 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
102 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
103 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
104 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
105 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
106 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
107 import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
108 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
109 import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
110 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
111 import static android.service.notification.Adjustment.KEY_TYPE;
112 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
113 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
114 import static android.service.notification.Adjustment.TYPE_NEWS;
115 import static android.service.notification.Adjustment.TYPE_PROMOTION;
116 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
117 import static android.service.notification.Condition.SOURCE_CONTEXT;
118 import static android.service.notification.Condition.SOURCE_USER_ACTION;
119 import static android.service.notification.Condition.STATE_TRUE;
120 import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
121 import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT;
122 import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
123 import static android.service.notification.Flags.FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION;
124 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
125 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
126 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
127 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
128 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
129 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
130 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
131 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
132 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
133 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
134 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
135 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
136 import static android.view.Display.DEFAULT_DISPLAY;
137 import static android.view.Display.INVALID_DISPLAY;
138 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
139 
140 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
141 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
142 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
143 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
144 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL;
145 import static com.android.server.notification.Flags.FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER;
146 import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS;
147 import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY;
148 import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
149 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
150 import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL;
151 import static com.android.server.notification.NotificationManagerService.TAG;
152 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
153 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
154 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
155 
156 import static com.google.common.collect.Iterables.getOnlyElement;
157 import static com.google.common.truth.Truth.assertThat;
158 import static com.google.common.truth.Truth.assertWithMessage;
159 
160 import static junit.framework.Assert.assertEquals;
161 import static junit.framework.Assert.assertFalse;
162 import static junit.framework.Assert.assertNotNull;
163 import static junit.framework.Assert.assertNotSame;
164 import static junit.framework.Assert.assertNull;
165 import static junit.framework.Assert.assertSame;
166 import static junit.framework.Assert.assertTrue;
167 import static junit.framework.Assert.fail;
168 
169 import static org.junit.Assert.assertNotEquals;
170 import static org.junit.Assert.assertThrows;
171 import static org.mockito.ArgumentMatchers.argThat;
172 import static org.mockito.ArgumentMatchers.isNull;
173 import static org.mockito.ArgumentMatchers.anyBoolean;
174 import static org.mockito.ArgumentMatchers.anyLong;
175 import static org.mockito.ArgumentMatchers.anyString;
176 import static org.mockito.ArgumentMatchers.eq;
177 import static org.mockito.Mockito.any;
178 import static org.mockito.Mockito.anyInt;
179 import static org.mockito.Mockito.atLeastOnce;
180 import static org.mockito.Mockito.clearInvocations;
181 import static org.mockito.Mockito.doAnswer;
182 import static org.mockito.Mockito.doNothing;
183 import static org.mockito.Mockito.doReturn;
184 import static org.mockito.Mockito.doThrow;
185 import static org.mockito.Mockito.inOrder;
186 import static org.mockito.Mockito.mock;
187 import static org.mockito.Mockito.never;
188 import static org.mockito.Mockito.reset;
189 import static org.mockito.Mockito.spy;
190 import static org.mockito.Mockito.timeout;
191 import static org.mockito.Mockito.times;
192 import static org.mockito.Mockito.verify;
193 import static org.mockito.Mockito.verifyNoMoreInteractions;
194 import static org.mockito.Mockito.when;
195 
196 import static java.util.Collections.emptyList;
197 import static java.util.Collections.singletonList;
198 
199 import android.Manifest;
200 import android.annotation.Nullable;
201 import android.annotation.SuppressLint;
202 import android.annotation.UserIdInt;
203 import android.app.ActivityManager;
204 import android.app.ActivityManagerInternal;
205 import android.app.AlarmManager;
206 import android.app.AppOpsManager;
207 import android.app.AutomaticZenRule;
208 import android.app.IActivityManager;
209 import android.app.ICallNotificationEventCallback;
210 import android.app.INotificationManager;
211 import android.app.ITransientNotification;
212 import android.app.IUriGrantsManager;
213 import android.app.Notification;
214 import android.app.Notification.MessagingStyle.Message;
215 import android.app.NotificationChannel;
216 import android.app.NotificationChannelGroup;
217 import android.app.NotificationManager;
218 import android.app.NotificationManager.Policy;
219 import android.app.PendingIntent;
220 import android.app.Person;
221 import android.app.RemoteInput;
222 import android.app.RemoteInputHistoryItem;
223 import android.app.StatsManager;
224 import android.app.ZenBypassingApp;
225 import android.app.admin.DevicePolicyManagerInternal;
226 import android.app.backup.BackupRestoreEventLogger;
227 import android.app.job.JobScheduler;
228 import android.app.role.RoleManager;
229 import android.app.usage.UsageStatsManagerInternal;
230 import android.companion.AssociationInfo;
231 import android.companion.AssociationRequest;
232 import android.companion.ICompanionDeviceManager;
233 import android.compat.testing.PlatformCompatChangeRule;
234 import android.content.BroadcastReceiver;
235 import android.content.ComponentName;
236 import android.content.ContentUris;
237 import android.content.Context;
238 import android.content.IIntentSender;
239 import android.content.Intent;
240 import android.content.IntentFilter;
241 import android.content.pm.ActivityInfo;
242 import android.content.pm.ApplicationInfo;
243 import android.content.pm.IPackageManager;
244 import android.content.pm.LauncherApps;
245 import android.content.pm.ModuleInfo;
246 import android.content.pm.PackageManager;
247 import android.content.pm.PackageManagerInternal;
248 import android.content.pm.ParceledListSlice;
249 import android.content.pm.ResolveInfo;
250 import android.content.pm.ShortcutInfo;
251 import android.content.pm.ShortcutServiceInternal;
252 import android.content.pm.UserInfo;
253 import android.content.pm.VersionedPackage;
254 import android.content.res.Resources;
255 import android.graphics.Bitmap;
256 import android.graphics.Color;
257 import android.graphics.drawable.Icon;
258 import android.media.AudioAttributes;
259 import android.media.AudioManager;
260 import android.media.session.MediaSession;
261 import android.net.Uri;
262 import android.os.Binder;
263 import android.os.Build;
264 import android.os.Bundle;
265 import android.os.Handler;
266 import android.os.IBinder;
267 import android.os.Looper;
268 import android.os.Parcel;
269 import android.os.Parcelable;
270 import android.os.PowerManager;
271 import android.os.PowerManager.WakeLock;
272 import android.os.Process;
273 import android.os.RemoteException;
274 import android.os.SystemClock;
275 import android.os.UserHandle;
276 import android.os.UserManager;
277 import android.os.WorkSource;
278 import android.permission.PermissionManager;
279 import android.platform.test.annotations.DisableFlags;
280 import android.platform.test.annotations.EnableFlags;
281 import android.platform.test.annotations.RequiresFlagsEnabled;
282 import android.platform.test.flag.junit.FlagsParameterization;
283 import android.platform.test.flag.junit.SetFlagsRule;
284 import android.platform.test.rule.LimitDevicesRule;
285 import android.provider.MediaStore;
286 import android.provider.Settings;
287 import android.service.notification.Adjustment;
288 import android.service.notification.Condition;
289 import android.service.notification.ConversationChannelWrapper;
290 import android.service.notification.DeviceEffectsApplier;
291 import android.service.notification.INotificationListener;
292 import android.service.notification.NotificationListenerFilter;
293 import android.service.notification.NotificationListenerService;
294 import android.service.notification.NotificationRankingUpdate;
295 import android.service.notification.NotificationStats;
296 import android.service.notification.StatusBarNotification;
297 import android.service.notification.ZenModeConfig;
298 import android.service.notification.ZenPolicy;
299 import android.telecom.TelecomManager;
300 import android.testing.TestWithLooperRule;
301 import android.testing.TestableContentResolver;
302 import android.testing.TestableLooper;
303 import android.testing.TestableLooper.RunWithLooper;
304 import android.testing.TestablePermissions;
305 import android.testing.TestableResources;
306 import android.text.Html;
307 import android.text.TextUtils;
308 import android.util.ArrayMap;
309 import android.util.ArraySet;
310 import android.util.AtomicFile;
311 import android.util.Log;
312 import android.util.Pair;
313 import android.util.Xml;
314 import android.view.accessibility.AccessibilityManager;
315 import android.widget.RemoteViews;
316 
317 import androidx.test.InstrumentationRegistry;
318 import androidx.test.filters.SmallTest;
319 
320 import com.android.internal.R;
321 import com.android.internal.config.sysui.TestableFlagResolver;
322 import com.android.internal.logging.InstanceId;
323 import com.android.internal.logging.InstanceIdSequence;
324 import com.android.internal.logging.InstanceIdSequenceFake;
325 import com.android.internal.messages.nano.SystemMessageProto;
326 import com.android.internal.statusbar.NotificationVisibility;
327 import com.android.internal.widget.LockPatternUtils;
328 import com.android.modules.utils.TypedXmlPullParser;
329 import com.android.modules.utils.TypedXmlSerializer;
330 import com.android.server.DeviceIdleInternal;
331 import com.android.server.LocalServices;
332 import com.android.server.SystemService;
333 import com.android.server.SystemService.TargetUser;
334 import com.android.server.UiServiceTestCase;
335 import com.android.server.job.JobSchedulerInternal;
336 import com.android.server.lights.LightsManager;
337 import com.android.server.lights.LogicalLight;
338 import com.android.server.notification.GroupHelper.NotificationAttributes;
339 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
340 import com.android.server.notification.NotificationManagerService.NotificationListeners;
341 import com.android.server.notification.NotificationManagerService.PostNotificationTracker;
342 import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory;
343 import com.android.server.pm.PackageManagerService;
344 import com.android.server.pm.UserManagerInternal;
345 import com.android.server.policy.PermissionPolicyInternal;
346 import com.android.server.statusbar.StatusBarManagerInternal;
347 import com.android.server.uri.UriGrantsManagerInternal;
348 import com.android.server.utils.quota.MultiRateLimiter;
349 import com.android.server.wm.ActivityTaskManagerInternal;
350 import com.android.server.wm.WindowManagerInternal;
351 
352 import com.google.android.collect.Lists;
353 import com.google.common.collect.ImmutableList;
354 import com.google.common.collect.Iterables;
355 
356 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
357 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
358 
359 import org.junit.After;
360 import org.junit.Assert;
361 import org.junit.Before;
362 import org.junit.ClassRule;
363 import org.junit.Rule;
364 import org.junit.Test;
365 import org.junit.rules.TestRule;
366 import org.junit.runner.RunWith;
367 import org.mockito.ArgumentCaptor;
368 import org.mockito.ArgumentMatcher;
369 import org.mockito.InOrder;
370 import org.mockito.Mock;
371 import org.mockito.Mockito;
372 import org.mockito.MockitoAnnotations;
373 import org.mockito.invocation.InvocationOnMock;
374 import org.mockito.stubbing.Answer;
375 
376 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
377 import platform.test.runner.parameterized.Parameters;
378 
379 import java.io.BufferedInputStream;
380 import java.io.BufferedOutputStream;
381 import java.io.ByteArrayInputStream;
382 import java.io.ByteArrayOutputStream;
383 import java.io.File;
384 import java.io.FileOutputStream;
385 import java.time.Duration;
386 import java.util.ArrayList;
387 import java.util.Arrays;
388 import java.util.HashSet;
389 import java.util.List;
390 import java.util.Map;
391 import java.util.concurrent.CountDownLatch;
392 import java.util.function.Consumer;
393 
394 @SmallTest
395 @RunWith(ParameterizedAndroidJunit4.class)
396 @RunWithLooper
397 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
398 public class NotificationManagerServiceTest extends UiServiceTestCase {
399     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
400     private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package";
401     private static final String PKG_NO_CHANNELS = "com.example.no.channels";
402     private static final int TEST_TASK_ID = 1;
403     private static final int UID_HEADLESS = 1_000_000;
404     private static final int TOAST_DURATION = 2_000;
405     private static final int SECONDARY_DISPLAY_ID = 42;
406     private static final int TEST_PROFILE_USERHANDLE = 12;
407     private static final long DELAY_FORCE_REGROUP_TIME = 3000;
408 
409     private static final String ACTION_NOTIFICATION_TIMEOUT =
410             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
411     private static final String EXTRA_KEY = "key";
412     private static final String SCHEME_TIMEOUT = "timeout";
413     private static final String REDACTED_TEXT = "redacted text";
414 
415     private static final AutomaticZenRule SOME_ZEN_RULE =
416             new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
417                     .setOwner(new ComponentName("pkg", "cls"))
418                     .build();
419 
420     @ClassRule
421     public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule();
422 
423     @Rule
424     public TestRule compatChangeRule = new PlatformCompatChangeRule();
425 
426     private TestableNotificationManagerService mService;
427     private INotificationManager mBinderService;
428     private NotificationManagerInternal mInternalService;
429     private ShortcutHelper mShortcutHelper;
430     @Mock
431     private IPackageManager mPackageManager;
432     @Mock
433     private PackageManager mPackageManagerClient;
434     @Mock
435     private PackageManagerInternal mPackageManagerInternal;
436     @Mock
437     private PermissionPolicyInternal mPermissionPolicyInternal;
438     @Mock
439     private WindowManagerInternal mWindowManagerInternal;
440     @Mock
441     private PermissionHelper mPermissionHelper;
442     private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
443     @Rule(order = Integer.MAX_VALUE)
444     public TestWithLooperRule mlooperRule = new TestWithLooperRule();
445     private TestableLooper mTestableLooper;
446     @Mock
447     private RankingHelper mRankingHelper;
448     @Mock private PreferencesHelper mPreferencesHelper;
449     AtomicFile mPolicyFile;
450     File mFile;
451     @Mock
452     private NotificationUsageStats mUsageStats;
453     @Mock
454     private UsageStatsManagerInternal mAppUsageStats;
455     @Mock
456     private AudioManager mAudioManager;
457     @Mock
458     private LauncherApps mLauncherApps;
459     @Mock
460     private ShortcutServiceInternal mShortcutServiceInternal;
461     @Mock
462     private UserManager mUserManager;
463     @Mock
464     ActivityManager mActivityManager;
465     @Mock
466     TelecomManager mTelecomManager;
467     @Mock
468     Resources mResources;
469     @Mock
470     RankingHandler mRankingHandler;
471     @Mock
472     ActivityManagerInternal mAmi;
473     @Mock
474     JobSchedulerInternal mJsi;
475     @Mock
476     private Looper mMainLooper;
477     @Mock
478     private NotificationManager mMockNm;
479     @Mock
480     private PermissionManager mPermissionManager;
481     @Mock
482     private DevicePolicyManagerInternal mDevicePolicyManager;
483     @Mock
484     private PowerManager mPowerManager;
485     @Mock
486     private LightsManager mLightsManager;
487     private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>();
488     private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory =
489             new TestPostNotificationTrackerFactory();
490 
491     private PendingIntent mActivityIntent;
492     private PendingIntent mActivityIntentImmutable;
493 
494     private static final int MAX_POST_DELAY = 1000;
495 
496     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
497             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
498 
499     NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW);
500 
501     NotificationChannel mMinChannel = new NotificationChannel("min", "min", IMPORTANCE_MIN);
502 
503     private final NotificationChannel mParentChannel =
504             new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT);
505     private final NotificationChannel mConversationChannel =
506             new NotificationChannel(
507                     CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT);
508 
509     private static final String PARENT_CHANNEL_ID = "parentChannelId";
510     private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId";
511     private static final String CONVERSATION_ID = "conversationId";
512 
513     private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
514 
515     private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
516     private static final String SEARCH_SELECTOR_PKG = "searchSelector";
517     private static final String ADSERVICES_MODULE_PKG = "com.android.adservices";
518     private static final String ADSERVICES_APK_PKG = "com.android.adservices.api";
519 
520     @Mock
521     private NotificationListeners mListeners;
522     @Mock
523     private NotificationListenerFilter mNlf;
524     @Mock private NotificationAssistants mAssistants;
525     @Mock private ConditionProviders mConditionProviders;
526     private ManagedServices.ManagedServiceInfo mListener;
527     @Mock private ICompanionDeviceManager mCompanionMgr;
528     @Mock SnoozeHelper mSnoozeHelper;
529     @Mock GroupHelper mGroupHelper;
530     @Mock
531     IBinder mPermOwner;
532     @Mock
533     IActivityManager mAm;
534     @Mock
535     ActivityTaskManagerInternal mAtm;
536     @Mock
537     IUriGrantsManager mUgm;
538     @Mock
539     UriGrantsManagerInternal mUgmInternal;
540     @Mock
541     AppOpsManager mAppOpsManager;
542     private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener;
543     @Mock
544     private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
545             mNotificationAssistantAccessGrantedCallback;
546     @Mock
547     UserManager mUm;
548     @Mock
549     UserManagerInternal mUmInternal;
550     @Mock
551     NotificationHistoryManager mHistoryManager;
552     @Mock
553     StatsManager mStatsManager;
554     @Mock
555     AlarmManager mAlarmManager;
556     @Mock JobScheduler mJobScheduler;
557     @Mock
558     MultiRateLimiter mToastRateLimiter;
559     BroadcastReceiver mPackageIntentReceiver;
560     BroadcastReceiver mUserIntentReceiver;
561     BroadcastReceiver mNotificationTimeoutReceiver;
562     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
563     TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
564 
565     TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
566     @Rule
567     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
568     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
569             1 << 30);
570     @Mock
571     StatusBarManagerInternal mStatusBar;
572 
573     @Mock
574     NotificationAttentionHelper mAttentionHelper;
575 
576     private NotificationManagerService.WorkerHandler mWorkerHandler;
577     private Handler mBroadcastsHandler;
578 
579     private class TestableToastCallback extends ITransientNotification.Stub {
580         @Override
show(IBinder windowToken)581         public void show(IBinder windowToken) {
582         }
583 
584         @Override
hide()585         public void hide() {
586         }
587     }
588 
589     private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory {
590 
591         private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>();
592 
593         @Override
newTracker(@ullable WakeLock optionalWakeLock)594         public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) {
595             PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker(
596                     optionalWakeLock);
597             mCreatedTrackers.add(tracker);
598             return tracker;
599         }
600     }
601 
602     @Parameters(name = "{0}")
getParams()603     public static List<FlagsParameterization> getParams() {
604         return FlagsParameterization.allCombinationsOf();
605     }
606 
NotificationManagerServiceTest(FlagsParameterization flags)607     public NotificationManagerServiceTest(FlagsParameterization flags) {
608         mSetFlagsRule.setFlagsParameterization(flags);
609     }
610 
611     @Before
setUp()612     public void setUp() throws Exception {
613         // Shell permisssions will override permissions of our app, so add all necessary permissions
614         // for this test here:
615         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
616                 "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG",
617                 "android.permission.READ_DEVICE_CONFIG",
618                 "android.permission.READ_CONTACTS");
619 
620         MockitoAnnotations.initMocks(this);
621 
622         DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
623         when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
624 
625         LocalServices.removeServiceForTest(UserManagerInternal.class);
626         LocalServices.addService(UserManagerInternal.class, mUmInternal);
627         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
628         LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
629         LocalServices.removeServiceForTest(WindowManagerInternal.class);
630         LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
631         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
632         LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
633         LocalServices.removeServiceForTest(DeviceIdleInternal.class);
634         LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
635         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
636         LocalServices.addService(ActivityManagerInternal.class, mAmi);
637         LocalServices.removeServiceForTest(JobSchedulerInternal.class);
638         LocalServices.addService(JobSchedulerInternal.class, mJsi);
639         LocalServices.removeServiceForTest(PackageManagerInternal.class);
640         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
641         LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
642         LocalServices.addService(PermissionPolicyInternal.class, mPermissionPolicyInternal);
643         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
644         LocalServices.addService(ShortcutServiceInternal.class, mShortcutServiceInternal);
645         mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
646         mContext.addMockSystemService(NotificationManager.class, mMockNm);
647         mContext.addMockSystemService(RoleManager.class, mock(RoleManager.class));
648         mContext.addMockSystemService(Context.LAUNCHER_APPS_SERVICE, mLauncherApps);
649         mContext.addMockSystemService(Context.USER_SERVICE, mUm);
650         mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE,
651                 mock(AccessibilityManager.class));
652 
653         doNothing().when(mContext).sendBroadcast(any(), anyString());
654         doNothing().when(mContext).sendBroadcastAsUser(any(), any());
655         doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
656         doNothing().when(mContext).sendBroadcastMultiplePermissions(any(), any(), any(), any());
657         doReturn(mContext).when(mContext).createContextAsUser(eq(mUser), anyInt());
658 
659         TestableContentResolver cr = mock(TestableContentResolver.class);
660         when(mContext.getContentResolver()).thenReturn(cr);
661         doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt());
662 
663         when(mAppOpsManager.checkOpNoThrow(
664                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
665                 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED);
666 
667         // Use this testable looper.
668         mTestableLooper = TestableLooper.get(this);
669         // MockPackageManager - default returns ApplicationInfo with matching calling UID
670         mContext.setMockPackageManager(mPackageManagerClient);
671 
672         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
673                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
674                     Object[] args = invocation.getArguments();
675                     return getApplicationInfo((String) args[0], mUid);
676                 });
677         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
678                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
679                     Object[] args = invocation.getArguments();
680                     return getApplicationInfo((String) args[0], mUid);
681                 });
682         when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
683         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer(
684                 (Answer<Boolean>) invocation -> {
685                     // TODO: b/317957802 - This is overly broad and basically makes ANY
686                     //  isSameApp() check pass,  requiring Mockito.reset() for meaningful
687                     //  tests! Make it more precise.
688                     Object[] args = invocation.getArguments();
689                     return (int) args[1] == mUid;
690                 });
691         when(mLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
692         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
693         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
694         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
695         when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{mPkg});
696         when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{mPkg});
697         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt()))
698                 .thenReturn(INVALID_TASK_ID);
699         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
700         when(mUm.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId});
701         when(mUmInternal.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId});
702         when(mAmi.getCurrentUserId()).thenReturn(mUserId);
703 
704         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true);
705 
706         ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
707         List<ActivityManager.AppTask> taskList = new ArrayList<>();
708         ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo();
709         taskInfo.taskId = TEST_TASK_ID;
710         when(task.getTaskInfo()).thenReturn(taskInfo);
711         taskList.add(task);
712         when(mAtm.getAppTasks(anyString(), anyInt())).thenReturn(taskList);
713 
714         // write to a test file; the system file isn't readable from tests
715         mFile = new File(mContext.getCacheDir(), "test.xml");
716         mFile.createNewFile();
717         final String preupgradeXml = "<notification-policy></notification-policy>";
718         mPolicyFile = new AtomicFile(mFile);
719         FileOutputStream fos = mPolicyFile.startWrite();
720         fos.write(preupgradeXml.getBytes());
721         mPolicyFile.finishWrite(fos);
722 
723         // Setup managed services
724         when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
725         when(mNlf.isPackageAllowed(any())).thenReturn(true);
726         when(mNlf.isPackageAllowed(null)).thenReturn(true);
727         when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
728         mListener = mListeners.new ManagedServiceInfo(
729                 null, new ComponentName(mPkg, "test_class"),
730                 mUserId, true, null, 0, 123);
731         ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
732         ArraySet<ComponentName> components = new ArraySet<>();
733         components.add(defaultComponent);
734         when(mListeners.getDefaultComponents()).thenReturn(components);
735         when(mConditionProviders.getDefaultPackages())
736                 .thenReturn(new ArraySet<>(Arrays.asList("config")));
737         when(mAssistants.getDefaultComponents()).thenReturn(components);
738         when(mAssistants.queryPackageForServices(
739                 anyString(), anyInt(), anyInt())).thenReturn(components);
740         when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
741         ManagedServices.Config listenerConfig = new ManagedServices.Config();
742         listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
743         when(mListeners.getConfig()).thenReturn(listenerConfig);
744         ManagedServices.Config assistantConfig = new ManagedServices.Config();
745         assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS;
746         when(mAssistants.getConfig()).thenReturn(assistantConfig);
747         ManagedServices.Config dndConfig = new ManagedServices.Config();
748         dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS;
749         when(mConditionProviders.getConfig()).thenReturn(dndConfig);
750 
751         when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
752 
753         // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks.
754         // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks,
755         // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't
756         // call release twice, etc) and we want the test to fail if such misuse happens, too.
757         PowerManager realPowerManager = mContext.getSystemService(PowerManager.class);
758         when(mPowerManager.newWakeLock(anyInt(), anyString())).then(
759                 (Answer<WakeLock>) invocation -> {
760                     WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0),
761                             invocation.getArgument(1));
762                     mAcquiredWakeLocks.add(wl);
763                     return wl;
764                 });
765 
766         // TODO (b/291907312): remove feature flag
767         // NOTE: Prefer using the @EnableFlags annotation where possible. Do not add any android.app
768         //  flags here.
769         mSetFlagsRule.disableFlags(
770                 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE);
771 
772         mActivityIntent = spy(PendingIntent.getActivity(mContext, 0,
773                 new Intent().setPackage(mPkg), PendingIntent.FLAG_MUTABLE));
774         mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0,
775                 new Intent().setPackage(mPkg), FLAG_IMMUTABLE));
776 
777         initNMS();
778     }
779 
initNMS()780     private void initNMS() throws Exception {
781         initNMS(SystemService.PHASE_BOOT_COMPLETED);
782     }
783 
initNMS(int upToBootPhase)784     private void initNMS(int upToBootPhase) throws Exception {
785         mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
786                 mNotificationInstanceIdSequence);
787 
788         // apps allowed as convos
789         mService.setStringArrayResourceValue(PKG_O);
790 
791         TestableResources tr = mContext.getOrCreateTestableResources();
792         tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName,
793                 SEARCH_SELECTOR_PKG);
794         tr.addOverride(R.array.config_notificationDefaultUnsupportedAdjustments,
795                 new String[] {KEY_TYPE});
796 
797         doAnswer(invocation -> {
798             mOnPermissionChangeListener = invocation.getArgument(2);
799             return null;
800         }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(),
801                 any());
802         when(mUmInternal.isUserInitialized(anyInt())).thenReturn(true);
803 
804         mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
805         mBroadcastsHandler = new Handler(mTestableLooper.getLooper());
806 
807         mService.init(mWorkerHandler, mRankingHandler, mBroadcastsHandler, mPackageManager,
808                 mPackageManagerClient, mLightsManager, mListeners, mAssistants, mConditionProviders,
809                 mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
810                 mGroupHelper, mAm, mAtm, mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal,
811                 mAppOpsManager, mUm, mHistoryManager, mStatsManager, mAmi, mToastRateLimiter,
812                 mPermissionHelper, mock(UsageStatsManagerInternal.class), mTelecomManager, mLogger,
813                 mTestFlagResolver, mPermissionManager, mPowerManager,
814                 mPostNotificationTrackerFactory);
815 
816         mService.setAttentionHelper(mAttentionHelper);
817         mService.setLockPatternUtils(mock(LockPatternUtils.class));
818 
819         // make sure PreferencesHelper doesn't try to interact with any real caches
820         PreferencesHelper prefHelper = spy(mService.mPreferencesHelper);
821         doNothing().when(prefHelper).invalidateNotificationChannelCache();
822         doNothing().when(prefHelper).invalidateNotificationChannelGroupCache();
823         mService.setPreferencesHelper(prefHelper);
824 
825         // Return first true for RoleObserver main-thread check
826         when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
827         ModuleInfo moduleInfo = new ModuleInfo();
828         moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG);
829         moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG));
830         when(mPackageManagerClient.getInstalledModules(anyInt()))
831                 .thenReturn(List.of(moduleInfo));
832         if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) {
833             mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
834         }
835 
836         Mockito.reset(mHistoryManager);
837         verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
838 
839         if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
840             mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
841             verify(mHistoryManager).onBootPhaseAppsCanStart();
842         }
843 
844         mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
845         mService.setStrongAuthTracker(mStrongAuthTracker);
846 
847         mShortcutHelper = mService.getShortcutHelper();
848         mShortcutHelper.setLauncherApps(mLauncherApps);
849         mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
850         mShortcutHelper.setUserManager(mUserManager);
851 
852         // Capture PackageIntentReceiver
853         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
854                 ArgumentCaptor.forClass(BroadcastReceiver.class);
855         ArgumentCaptor<IntentFilter> intentFilterCaptor =
856                 ArgumentCaptor.forClass(IntentFilter.class);
857 
858         verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
859                 any(), intentFilterCaptor.capture(), any(), any());
860         verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
861                 intentFilterCaptor.capture(), anyInt());
862         verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
863                 intentFilterCaptor.capture());
864         List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
865         List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues();
866 
867         for (int i = 0; i < intentFilters.size(); i++) {
868             final IntentFilter filter = intentFilters.get(i);
869             if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)
870                     && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED)
871                     && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
872                 mPackageIntentReceiver = broadcastReceivers.get(i);
873             }
874             if (filter.hasAction(Intent.ACTION_USER_STOPPED)
875                     || filter.hasAction(Intent.ACTION_USER_SWITCHED)
876                     || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)
877                     || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
878                 // There may be multiple receivers, get the NMS one
879                 if (broadcastReceivers.get(i).toString().contains(
880                         NotificationManagerService.class.getName())) {
881                     mUserIntentReceiver = broadcastReceivers.get(i);
882                 }
883             }
884             if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT)
885                     && filter.hasDataScheme(SCHEME_TIMEOUT)) {
886                 mNotificationTimeoutReceiver = broadcastReceivers.get(i);
887             }
888         }
889         assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
890         assertNotNull("User receiver should exist", mUserIntentReceiver);
891         if (!Flags.allNotifsNeedTtl()) {
892             assertNotNull("Notification timeout receiver should exist",
893                     mNotificationTimeoutReceiver);
894         }
895 
896         // Pretend the shortcut exists
897         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
898         shortcutInfos.add(createMockConvoShortcut());
899         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
900         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
901                 anyString(), anyInt(), any())).thenReturn(true);
902         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
903         mockIsUserVisible(DEFAULT_DISPLAY, true);
904         mockIsVisibleBackgroundUsersSupported(false);
905 
906         // Set the testable bubble extractor
907         RankingHelper rankingHelper = mService.getRankingHelper();
908         BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
909         extractor.setActivityManager(mActivityManager);
910 
911         // Tests call directly into the Binder.
912         mBinderService = mService.getBinderService();
913         mInternalService = mService.getInternalService();
914 
915         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(
916                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
917         mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice(
918                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
919         mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
920                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
921         assertNotNull(mBinderService.getNotificationChannel(
922                 mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID));
923         assertNotNull(mBinderService.getNotificationChannel(
924                 mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId()));
925         assertNotNull(mBinderService.getNotificationChannel(
926                 mPkg, mContext.getUserId(), mPkg, mMinChannel.getId()));
927         clearInvocations(mRankingHandler);
928         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
929 
930         var checker = mock(TestableNotificationManagerService.ComponentPermissionChecker.class);
931         mService.permissionChecker = checker;
932         when(checker.check(anyString(), anyInt(), anyInt(), anyBoolean()))
933                 .thenReturn(PackageManager.PERMISSION_DENIED);
934     }
935 
936     @After
assertNotificationRecordLoggerCallsValid()937     public void assertNotificationRecordLoggerCallsValid() {
938         waitForIdle(); // Finish async work, including all logging calls done by Runnables.
939         for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) {
940             if (call.wasLogged) {
941                 assertNotNull(call.event);
942                 if (call.event == NOTIFICATION_POSTED || call.event == NOTIFICATION_UPDATED) {
943                     assertThat(call.postDurationMillisLogged).isGreaterThan(0);
944                 } else {
945                     assertThat(call.postDurationMillisLogged).isNull();
946                 }
947             }
948         }
949         assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty();
950     }
951 
952     @After
assertAllTrackersFinishedOrCancelled()953     public void assertAllTrackersFinishedOrCancelled() {
954         waitForIdle(); // Finish async work.
955         // Verify that no trackers were left dangling.
956         for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) {
957             assertThat(tracker.isOngoing()).isFalse();
958         }
959         mPostNotificationTrackerFactory.mCreatedTrackers.clear();
960     }
961 
962     @After
assertAllWakeLocksReleased()963     public void assertAllWakeLocksReleased() {
964         waitForIdle(); // Finish async work.
965         for (WakeLock wakeLock : mAcquiredWakeLocks) {
966             assertThat(wakeLock.isHeld()).isFalse();
967         }
968     }
969 
970     @After
tearDown()971     public void tearDown() throws Exception {
972         if (mFile != null) mFile.delete();
973 
974         if (mActivityIntent != null) {
975             mActivityIntent.cancel();
976         }
977 
978         mService.clearNotifications();
979         if (mTestableLooper != null) {
980             mTestableLooper.processAllMessages();
981         }
982 
983         try {
984             mService.onDestroy();
985         } catch (IllegalStateException | IllegalArgumentException e) {
986             Log.e(TAG, "failed to destroy", e);
987             // can throw if a broadcast receiver was never registered
988         }
989 
990         InstrumentationRegistry.getInstrumentation()
991                 .getUiAutomation().dropShellPermissionIdentity();
992         if (mWorkerHandler != null) {
993             // Remove scheduled messages that would be processed when the test is already done, and
994             // could cause issues, for example, messages that remove/cancel shown toasts (this causes
995             // problematic interactions with mocks when they're no longer working as expected).
996             mWorkerHandler.removeCallbacksAndMessages(null);
997         }
998         if (mBroadcastsHandler != null) {
999             mBroadcastsHandler.removeCallbacksAndMessages(null);
1000         }
1001 
1002         if (mTestableLooper != null) {
1003             // Must remove static reference to this test object to prevent leak (b/261039202)
1004             mTestableLooper.remove(this);
1005         }
1006     }
1007 
createMockConvoShortcut()1008     private ShortcutInfo createMockConvoShortcut() {
1009         ShortcutInfo info = mock(ShortcutInfo.class);
1010         when(info.getPackage()).thenReturn(mPkg);
1011         when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
1012         when(info.getUserId()).thenReturn(USER_SYSTEM);
1013         when(info.isLongLived()).thenReturn(true);
1014         when(info.isEnabled()).thenReturn(true);
1015         return info;
1016     }
1017 
simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid)1018     private void simulatePackageSuspendBroadcast(boolean suspend, String pkg,
1019             int uid) {
1020         // mimics receive broadcast that package is (un)suspended
1021         // but does not actually (un)suspend the package
1022         final Bundle extras = new Bundle();
1023         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
1024                 new String[]{pkg});
1025         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid});
1026 
1027         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
1028                 : Intent.ACTION_PACKAGES_UNSUSPENDED;
1029         final Intent intent = new Intent(action);
1030         intent.putExtras(extras);
1031 
1032         mPackageIntentReceiver.onReceive(getContext(), intent);
1033     }
1034 
simulatePackageRemovedBroadcast(String pkg, int uid)1035     private void simulatePackageRemovedBroadcast(String pkg, int uid) {
1036         // mimics receive broadcast that package is removed, but doesn't remove the package.
1037         final Bundle extras = new Bundle();
1038         extras.putInt(Intent.EXTRA_UID, uid);
1039 
1040         final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
1041         intent.setData(Uri.parse("package:" + pkg));
1042         intent.putExtras(extras);
1043 
1044         mPackageIntentReceiver.onReceive(getContext(), intent);
1045     }
1046 
simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids)1047     private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) {
1048         // mimics receive broadcast that package is (un)distracting
1049         // but does not actually register that info with packagemanager
1050         final Bundle extras = new Bundle();
1051         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
1052         extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
1053         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids);
1054 
1055         final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
1056         intent.putExtras(extras);
1057 
1058         mPackageIntentReceiver.onReceive(getContext(), intent);
1059     }
1060 
simulateProfileAvailabilityActions(String intentAction)1061     private void simulateProfileAvailabilityActions(String intentAction) {
1062         final Intent intent = new Intent(intentAction);
1063         intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
1064         mUserIntentReceiver.onReceive(mContext, intent);
1065     }
1066 
generateResetComponentValues()1067     private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() {
1068         ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>();
1069         changed.put(true, new ArrayList<>());
1070         changed.put(false, new ArrayList<>());
1071         return changed;
1072     }
getApplicationInfo(String pkg, int uid)1073     private ApplicationInfo getApplicationInfo(String pkg, int uid) {
1074         final ApplicationInfo applicationInfo = new ApplicationInfo();
1075         applicationInfo.packageName = pkg;
1076         applicationInfo.uid = uid;
1077         applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir;
1078         switch (pkg) {
1079             case PKG_N_MR1:
1080                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
1081                 break;
1082             case PKG_O:
1083                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
1084                 break;
1085             case PKG_P:
1086                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
1087                 break;
1088             default:
1089                 applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
1090                 break;
1091         }
1092         return applicationInfo;
1093     }
1094 
waitForIdle()1095     public void waitForIdle() {
1096         if (mTestableLooper != null) {
1097             mTestableLooper.processAllMessages();
1098         }
1099     }
1100 
setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, int pkgPref, boolean channelEnabled)1101     private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled,
1102             int pkgPref, boolean channelEnabled) {
1103         Settings.Secure.putInt(mContext.getContentResolver(),
1104                 Settings.Secure.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0);
1105         mService.mPreferencesHelper.updateBubblesEnabled();
1106         assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled(
1107                 mock(UserHandle.class)));
1108         try {
1109             mBinderService.setBubblesAllowed(pkg, uid, pkgPref);
1110         } catch (RemoteException e) {
1111             e.printStackTrace();
1112         }
1113         mTestNotificationChannel.setAllowBubbles(channelEnabled);
1114     }
1115 
setUpPrefsForHistory(@serIdInt int userId, boolean globalEnabled)1116     private void setUpPrefsForHistory(@UserIdInt int userId, boolean globalEnabled)
1117             throws Exception {
1118         initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY);
1119 
1120         // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
1121         Settings.Secure.putIntForUser(mContext.getContentResolver(),
1122                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, userId);
1123         // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0
1124         Settings.Secure.putInt(mContext.getContentResolver(),
1125                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0);
1126         setUsers(new int[] {0, userId});
1127 
1128         // Forces an update by calling observe on mSettingsObserver, which picks up the settings
1129         // changes above.
1130         mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
1131 
1132         assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(),
1133                 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, userId) != 0);
1134     }
1135 
generateSbn(String pkg, int uid, long postTime, int userId)1136     private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) {
1137         Notification.Builder nb = new Notification.Builder(mContext, "a")
1138                 .setContentTitle("foo")
1139                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1140         StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid,
1141                 "tag" + System.currentTimeMillis(), uid, 0,
1142                 nb.build(), new UserHandle(userId), null, postTime);
1143         return sbn;
1144     }
1145 
generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary)1146     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1147             String groupKey, boolean isSummary) {
1148         return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey,
1149                 isSummary);
1150     }
1151 
generateNotificationRecord(NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary)1152     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1153             String tag, String groupKey, boolean isSummary) {
1154         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1155                 .setContentTitle("foo")
1156                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1157                 .setGroup(groupKey)
1158                 .setGroupSummary(isSummary);
1159         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id,
1160                 tag, mUid, 0,
1161                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1162         return new NotificationRecord(mContext, sbn, channel);
1163     }
1164 
generateNotificationRecord(NotificationChannel channel)1165     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
1166         return generateNotificationRecord(channel, null);
1167     }
1168 
generateNotificationRecord(NotificationChannel channel, Notification.TvExtender extender)1169     private NotificationRecord generateNotificationRecord(NotificationChannel channel,
1170             Notification.TvExtender extender) {
1171         if (channel == null) {
1172             channel = mTestNotificationChannel;
1173         }
1174         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1175                 .setContentTitle("foo")
1176                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1177                 .addAction(new Notification.Action.Builder(null, "test", mActivityIntent).build())
1178                 .addAction(new Notification.Action.Builder(
1179                         null, "test", mActivityIntentImmutable).build());
1180         if (extender != null) {
1181             nb.extend(extender);
1182         }
1183         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
1184                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1185         return new NotificationRecord(mContext, sbn, channel);
1186     }
1187 
generateNotificationRecord(NotificationChannel channel, long postTime)1188     private NotificationRecord generateNotificationRecord(NotificationChannel channel,
1189             long postTime) {
1190         final StatusBarNotification sbn = generateSbn(mPkg, mUid, postTime, mUserId);
1191         return new NotificationRecord(mContext, sbn, channel);
1192     }
1193 
generateNotificationRecord(NotificationChannel channel, int userId)1194     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) {
1195         return generateNotificationRecord(channel, 1, userId);
1196     }
1197 
generateNotificationRecord(NotificationChannel channel, int id, int userId)1198     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1199             int userId) {
1200         return generateNotificationRecord(channel, id, userId, "foo");
1201     }
1202 
generateNotificationRecord(NotificationChannel channel, int id, int userId, String title)1203     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
1204             int userId, String title) {
1205         if (channel == null) {
1206             channel = mTestNotificationChannel;
1207         }
1208         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1209                 .setContentTitle(title)
1210                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1211         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0,
1212                 nb.build(), new UserHandle(userId), null, 0);
1213         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
1214         return r;
1215     }
1216 
generateMessageBubbleNotifRecord(NotificationChannel channel, String tag)1217     private NotificationRecord generateMessageBubbleNotifRecord(NotificationChannel channel,
1218             String tag) {
1219         return generateMessageBubbleNotifRecord(true, channel, 1, tag, null, false, true);
1220     }
1221 
generateMessageBubbleNotifRecord(boolean addMetadata, NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, boolean mutable)1222     private NotificationRecord generateMessageBubbleNotifRecord(boolean addMetadata,
1223             NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary,
1224             boolean mutable) {
1225         if (channel == null) {
1226             channel = mTestNotificationChannel;
1227         }
1228         if (tag == null) {
1229             tag = "tag";
1230         }
1231         Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey,
1232                 isSummary, mutable);
1233         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id,
1234                 tag, mUid, 0,
1235                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1236         return new NotificationRecord(mContext, sbn, channel);
1237     }
1238 
generateRedactedSbn(NotificationChannel channel, int id, int userId)1239     private StatusBarNotification generateRedactedSbn(NotificationChannel channel, int id,
1240             int userId) {
1241         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1242                 .setContentTitle("foo")
1243                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1244                 .setContentText(REDACTED_TEXT);
1245         return new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0,
1246                 nb.build(), new UserHandle(userId), null, 0);
1247     }
1248 
getSignalExtractorSideEffects()1249     private Map<String, Answer> getSignalExtractorSideEffects() {
1250         Map<String, Answer> answers = new ArrayMap<>();
1251 
1252         answers.put("override group key", invocationOnMock -> {
1253             ((NotificationRecord) invocationOnMock.getArguments()[0])
1254                     .setOverrideGroupKey("bananas");
1255             return null;
1256         });
1257         answers.put("override people", invocationOnMock -> {
1258             ((NotificationRecord) invocationOnMock.getArguments()[0])
1259                     .setPeopleOverride(new ArrayList<>());
1260             return null;
1261         });
1262         answers.put("snooze criteria", invocationOnMock -> {
1263             ((NotificationRecord) invocationOnMock.getArguments()[0])
1264                     .setSnoozeCriteria(new ArrayList<>());
1265             return null;
1266         });
1267         answers.put("notification channel", invocationOnMock -> {
1268             ((NotificationRecord) invocationOnMock.getArguments()[0])
1269                     .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW));
1270             return null;
1271         });
1272         answers.put("badging", invocationOnMock -> {
1273             NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
1274             r.setShowBadge(!r.canShowBadge());
1275             return null;
1276         });
1277         answers.put("bubbles", invocationOnMock -> {
1278             NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
1279             r.setAllowBubble(!r.canBubble());
1280             return null;
1281         });
1282         answers.put("package visibility", invocationOnMock -> {
1283             ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride(
1284                     Notification.VISIBILITY_SECRET);
1285             return null;
1286         });
1287 
1288         return answers;
1289     }
1290 
getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary, boolean mutable)1291     private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata,
1292             String groupKey, boolean isSummary, boolean mutable) {
1293         // Give it a person
1294         Person person = new Person.Builder()
1295                 .setName("bubblebot")
1296                 .build();
1297         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
1298         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
1299         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
1300                 mutable ? mActivityIntent : mActivityIntentImmutable).addRemoteInput(remoteInput)
1301                 .build();
1302         // Make it messaging style
1303         Notification.Builder nb = new Notification.Builder(mContext,
1304                 mTestNotificationChannel.getId())
1305                 .setContentTitle("foo")
1306                 .setStyle(new Notification.MessagingStyle(person)
1307                         .setConversationTitle("Bubble Chat")
1308                         .addMessage("Hello?",
1309                                 SystemClock.currentThreadTimeMillis() - 300000, person)
1310                         .addMessage("Is it me you're looking for?",
1311                                 SystemClock.currentThreadTimeMillis(), person)
1312                 )
1313                 .setActions(replyAction)
1314                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1315                 .setShortcutId(VALID_CONVO_SHORTCUT_ID)
1316                 .setGroupSummary(isSummary);
1317         if (groupKey != null) {
1318             nb.setGroup(groupKey);
1319         }
1320         if (addBubbleMetadata) {
1321             nb.setBubbleMetadata(getBubbleMetadata());
1322         }
1323         return nb;
1324     }
1325 
getBubbleMetadata()1326     private Notification.BubbleMetadata getBubbleMetadata() {
1327         ActivityInfo info = new ActivityInfo();
1328         info.resizeMode = RESIZE_MODE_RESIZEABLE;
1329         ResolveInfo ri = new ResolveInfo();
1330         ri.activityInfo = info;
1331         when(mPackageManagerClient.resolveActivityAsUser(any(), anyInt(), anyInt())).thenReturn(ri);
1332 
1333         return new Notification.BubbleMetadata.Builder(
1334                 mActivityIntent,
1335                 Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon))
1336                 .build();
1337     }
1338 
addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)1339     private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)
1340             throws RemoteException {
1341 
1342         String groupKey = "BUBBLE_GROUP";
1343 
1344         // Notification that has bubble metadata
1345         NotificationRecord nrBubble = generateMessageBubbleNotifRecord(true /* addMetadata */,
1346                 mTestNotificationChannel, 1 /* id */, "tag", groupKey, false /* isSummary */,
1347                 true);
1348 
1349         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrBubble.getSbn().getTag(),
1350                 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(),
1351                 nrBubble.getSbn().getUserId());
1352         waitForIdle();
1353 
1354         // Make sure we are a bubble
1355         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
1356         assertEquals(1, notifsAfter.length);
1357         assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
1358 
1359         // Notification without bubble metadata
1360         NotificationRecord nrPlain = generateMessageBubbleNotifRecord(false /* addMetadata */,
1361                 mTestNotificationChannel, 2 /* id */, "tag", groupKey, false /* isSummary */,
1362                 true);
1363 
1364         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrPlain.getSbn().getTag(),
1365                 nrPlain.getSbn().getId(), nrPlain.getSbn().getNotification(),
1366                 nrPlain.getSbn().getUserId());
1367         waitForIdle();
1368 
1369         notifsAfter = mBinderService.getActiveNotifications(mPkg);
1370         assertEquals(2, notifsAfter.length);
1371 
1372         // Summary notification for both of those
1373         NotificationRecord nrSummary = generateMessageBubbleNotifRecord(false /* addMetadata */,
1374                 mTestNotificationChannel, 3 /* id */, "tag", groupKey, true /* isSummary */,
1375                 true);
1376 
1377         if (summaryAutoCancel) {
1378             nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL;
1379         }
1380         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrSummary.getSbn().getTag(),
1381                 nrSummary.getSbn().getId(), nrSummary.getSbn().getNotification(),
1382                 nrSummary.getSbn().getUserId());
1383         waitForIdle();
1384 
1385         notifsAfter = mBinderService.getActiveNotifications(mPkg);
1386         assertEquals(3, notifsAfter.length);
1387 
1388         return nrSummary;
1389     }
1390 
createAndPostCallStyleNotification(String packageName, UserHandle userHandle, String testName)1391     private NotificationRecord createAndPostCallStyleNotification(String packageName,
1392             UserHandle userHandle, String testName) throws Exception {
1393         Person person = new Person.Builder().setName("caller").build();
1394         Notification.Builder nb = new Notification.Builder(mContext,
1395                 mTestNotificationChannel.getId())
1396                 .setFlag(FLAG_USER_INITIATED_JOB, true)
1397                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
1398                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
1399         StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1,
1400                 testName, mUid, 0, nb.build(), userHandle, null, 0);
1401         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
1402 
1403         mService.addEnqueuedNotification(r);
1404         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1405                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run();
1406         waitForIdle();
1407 
1408         return mService.findNotificationLocked(
1409                 packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId());
1410     }
1411 
createAndPostNotification(Notification.Builder nb, String testName)1412     private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
1413             throws RemoteException {
1414         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0,
1415                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1416         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
1417 
1418         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1419                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
1420         waitForIdle();
1421 
1422         return mService.findNotificationLocked(
1423                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
1424     }
1425 
parcelAndUnparcel(T source, Parcelable.Creator<T> creator)1426     private static <T extends Parcelable> T parcelAndUnparcel(T source,
1427             Parcelable.Creator<T> creator) {
1428         Parcel parcel = Parcel.obtain();
1429         source.writeToParcel(parcel, 0);
1430         parcel.setDataPosition(0);
1431         return creator.createFromParcel(parcel);
1432     }
1433 
createPendingIntent(String action)1434     private PendingIntent createPendingIntent(String action) {
1435         return PendingIntent.getActivity(mContext, 0,
1436                 new Intent(action).setPackage(mContext.getPackageName()),
1437                 PendingIntent.FLAG_MUTABLE);
1438     }
1439 
allowTestPackageToToast()1440     private void allowTestPackageToToast() throws Exception {
1441         assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty();
1442         mService.isSystemUid = false;
1443         mService.isSystemAppId = false;
1444         setToastRateIsWithinQuota(true);
1445         setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false);
1446         // package is not suspended
1447         when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId))
1448                 .thenReturn(false);
1449     }
1450 
enqueueToast(String testPackage, ITransientNotification callback)1451     private boolean enqueueToast(String testPackage, ITransientNotification callback)
1452             throws RemoteException {
1453         return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(),
1454                 callback);
1455     }
1456 
enqueueToast(INotificationManager service, String testPackage, IBinder token, ITransientNotification callback)1457     private boolean enqueueToast(INotificationManager service, String testPackage,
1458             IBinder token, ITransientNotification callback) throws RemoteException {
1459         return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */
1460                 true, DEFAULT_DISPLAY);
1461     }
1462 
enqueueTextToast(String testPackage, CharSequence text)1463     private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException {
1464         return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY);
1465     }
1466 
enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, int displayId)1467     private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext,
1468             int displayId) throws RemoteException {
1469         return ((INotificationManager) mService.mService).enqueueTextToast(testPackage,
1470                 new Binder(), text, TOAST_DURATION, isUiContext, displayId,
1471                 /* textCallback= */ null);
1472     }
1473 
mockIsVisibleBackgroundUsersSupported(boolean supported)1474     private void mockIsVisibleBackgroundUsersSupported(boolean supported) {
1475         when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported);
1476     }
1477 
mockIsUserVisible(int displayId, boolean visible)1478     private void mockIsUserVisible(int displayId, boolean visible) {
1479         when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible);
1480     }
1481 
mockDisplayAssignedToUser(int displayId)1482     private void mockDisplayAssignedToUser(int displayId) {
1483         when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId);
1484     }
1485 
verifyToastShownForTestPackage(String text, int displayId)1486     private void verifyToastShownForTestPackage(String text, int displayId) {
1487         verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(),
1488                 eq(TOAST_DURATION), any(), eq(displayId));
1489     }
1490 
1491     @Test
1492     @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
testLimitTimeOutBroadcast()1493     public void testLimitTimeOutBroadcast() {
1494         NotificationChannel channel = new NotificationChannel("id", "name",
1495                 NotificationManager.IMPORTANCE_HIGH);
1496         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
1497                 .setContentTitle("foo")
1498                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
1499                 .setTimeoutAfter(1);
1500 
1501         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
1502                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
1503         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
1504 
1505         mService.scheduleTimeoutLocked(r);
1506         ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
1507         verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture());
1508         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
1509                 captor.getValue().getIntent().getPackage());
1510 
1511         mService.cancelScheduledTimeoutLocked(r);
1512         verify(mAlarmManager).cancel(captor.capture());
1513         assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
1514                 captor.getValue().getIntent().getPackage());
1515     }
1516 
1517     @Test
testDefaultAssistant_overrideDefault()1518     public void testDefaultAssistant_overrideDefault() {
1519         final int userId = mContext.getUserId();
1520         final String testComponent = "package/class";
1521         final List<UserInfo> userInfos = new ArrayList<>();
1522         userInfos.add(new UserInfo(userId, "", 0));
1523         final ArraySet<ComponentName> validAssistants = new ArraySet<>();
1524         validAssistants.add(ComponentName.unflattenFromString(testComponent));
1525         when(mActivityManager.isLowRamDevice()).thenReturn(false);
1526         when(mAssistants.queryPackageForServices(isNull(), anyInt(), anyInt()))
1527                 .thenReturn(validAssistants);
1528         when(mAssistants.getDefaultComponents()).thenReturn(validAssistants);
1529         when(mUm.getEnabledProfiles(anyInt())).thenReturn(userInfos);
1530 
1531         mService.setDefaultAssistantForUser(userId);
1532 
1533         verify(mAssistants).setPackageOrComponentEnabled(
1534                 eq(testComponent), eq(userId), eq(true), eq(true), eq(false));
1535     }
1536 
1537     @Test
testCreateNotificationChannels_SingleChannel()1538     public void testCreateNotificationChannels_SingleChannel() throws Exception {
1539         final NotificationChannel channel =
1540                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1541         mBinderService.createNotificationChannels(mPkg,
1542                 new ParceledListSlice(Arrays.asList(channel)));
1543         final NotificationChannel createdChannel =
1544                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1545         assertTrue(createdChannel != null);
1546     }
1547 
1548     @Test
testCreateNotificationChannels_NullChannelThrowsException()1549     public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
1550         try {
1551             mBinderService.createNotificationChannels(mPkg,
1552                     new ParceledListSlice(Arrays.asList((Object[])null)));
1553             fail("Exception should be thrown immediately.");
1554         } catch (NullPointerException e) {
1555             // pass
1556         }
1557     }
1558 
1559     @Test
testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()1560     public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()
1561             throws Exception {
1562         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1563         final NotificationChannel channel =
1564                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1565         mBinderService.createNotificationChannels(PKG_NO_CHANNELS,
1566                 new ParceledListSlice(Arrays.asList(channel)));
1567         verify(mWorkerHandler).post(eq(new NotificationManagerService
1568                 .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS,
1569                 mUserId, TEST_TASK_ID, mPermissionPolicyInternal)));
1570     }
1571 
1572     @Test
testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()1573     public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()
1574             throws Exception {
1575         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1576         assertTrue(mBinderService.getNumNotificationChannelsForPackage(mPkg, mUid, true) > 0);
1577 
1578         final NotificationChannel channel =
1579                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1580         mBinderService.createNotificationChannels(mPkg,
1581                 new ParceledListSlice(Arrays.asList(channel)));
1582         verify(mWorkerHandler, never()).post(any(
1583                 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class));
1584     }
1585 
1586     @Test
testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()1587     public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()
1588             throws Exception {
1589         reset(mPermissionPolicyInternal);
1590         when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
1591 
1592         final NotificationChannel channel =
1593                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1594         mBinderService.createNotificationChannels(mPkg,
1595                 new ParceledListSlice(Arrays.asList(channel)));
1596 
1597         verify(mWorkerHandler, never()).post(any(
1598                 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class));
1599     }
1600 
1601     @Test
testCreateNotificationChannels_TwoChannels()1602     public void testCreateNotificationChannels_TwoChannels() throws Exception {
1603         final NotificationChannel channel1 =
1604                 new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT);
1605         final NotificationChannel channel2 =
1606                 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
1607         mBinderService.createNotificationChannels(mPkg,
1608                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
1609         assertTrue(mBinderService.getNotificationChannel(
1610                 mPkg, mContext.getUserId(), mPkg, "id1") != null);
1611         assertTrue(mBinderService.getNotificationChannel(
1612                 mPkg, mContext.getUserId(), mPkg, "id2") != null);
1613     }
1614 
1615     @Test
testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()1616     public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
1617             throws Exception {
1618         final NotificationChannel channel =
1619                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1620         mBinderService.createNotificationChannels(mPkg,
1621                 new ParceledListSlice(Arrays.asList(channel)));
1622 
1623         // Recreating the channel doesn't throw, but ignores importance.
1624         final NotificationChannel dupeChannel =
1625                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1626         mBinderService.createNotificationChannels(mPkg,
1627                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1628         final NotificationChannel createdChannel =
1629                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1630         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
1631     }
1632 
1633     @Test
testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()1634     public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()
1635             throws Exception {
1636         final NotificationChannel channel =
1637                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1638         mBinderService.createNotificationChannels(mPkg,
1639                 new ParceledListSlice(Arrays.asList(channel)));
1640 
1641         // Recreating with a lower importance is allowed to modify the channel.
1642         final NotificationChannel dupeChannel =
1643                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
1644         mBinderService.createNotificationChannels(mPkg,
1645                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1646         final NotificationChannel createdChannel =
1647                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1648         assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
1649     }
1650 
1651     @Test
testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()1652     public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()
1653             throws Exception {
1654         final NotificationChannel channel =
1655                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1656         mBinderService.createNotificationChannels(mPkg,
1657                 new ParceledListSlice(Arrays.asList(channel)));
1658 
1659         // The user modifies importance directly, can no longer be changed by the app.
1660         final NotificationChannel updatedChannel =
1661                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1662         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, updatedChannel);
1663 
1664         // Recreating with a lower importance leaves channel unchanged.
1665         final NotificationChannel dupeChannel =
1666                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
1667         mBinderService.createNotificationChannels(mPkg,
1668                 new ParceledListSlice(Arrays.asList(dupeChannel)));
1669         final NotificationChannel createdChannel =
1670                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1671         assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
1672     }
1673 
1674     @Test
testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()1675     public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
1676             throws Exception {
1677         final NotificationChannel channel1 =
1678                 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
1679         final NotificationChannel channel2 =
1680                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
1681         mBinderService.createNotificationChannels(mPkg,
1682                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
1683         final NotificationChannel createdChannel =
1684                 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id");
1685         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
1686     }
1687 
1688     @Test
testBlockedNotifications_suspended()1689     public void testBlockedNotifications_suspended() throws Exception {
1690         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
1691 
1692         NotificationChannel channel = new NotificationChannel("id", "name",
1693                 IMPORTANCE_HIGH);
1694         NotificationRecord r = generateNotificationRecord(channel);
1695 
1696         // isBlocked is only used for user blocking, not app suspension
1697         assertFalse(mService.isRecordBlockedLocked(r));
1698     }
1699 
1700     @Test
testBlockedNotifications_blockedChannel()1701     public void testBlockedNotifications_blockedChannel() throws Exception {
1702         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1703 
1704         NotificationChannel channel = new NotificationChannel("id", "name",
1705                 NotificationManager.IMPORTANCE_NONE);
1706         NotificationRecord r = generateNotificationRecord(channel);
1707         assertTrue(mService.isRecordBlockedLocked(r));
1708 
1709         mBinderService.createNotificationChannels(
1710                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1711         final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1712         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1713                 "testBlockedNotifications_blockedChannel",
1714                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1715         waitForIdle();
1716         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1717     }
1718 
1719     @Test
testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()1720     public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()
1721             throws Exception {
1722         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1723         when(mAmi.applyForegroundServiceNotification(
1724                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1725 
1726         NotificationChannel channel = new NotificationChannel("blocked", "name",
1727                 NotificationManager.IMPORTANCE_NONE);
1728         mBinderService.createNotificationChannels(
1729                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1730 
1731         final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1732         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1733         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1734                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1735         waitForIdle();
1736         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1737         assertEquals(IMPORTANCE_LOW,
1738                 mService.getNotificationRecord(sbn.getKey()).getImportance());
1739         assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
1740                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1741     }
1742 
1743     @Test
testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()1744     public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()
1745             throws Exception {
1746         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1747         when(mAmi.applyForegroundServiceNotification(
1748                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1749 
1750         NotificationChannel channel =
1751                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH);
1752         mBinderService.createNotificationChannels(
1753                 mPkg, new ParceledListSlice(Arrays.asList(channel)));
1754 
1755         NotificationChannel update =
1756                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
1757         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update);
1758         waitForIdle();
1759         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1760                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1761 
1762         StatusBarNotification sbn = generateNotificationRecord(channel).getSbn();
1763         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1764         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
1765                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1766         waitForIdle();
1767         // The first time a foreground service notification is shown, we allow the channel
1768         // to be updated to allow it to be seen.
1769         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1770         assertEquals(IMPORTANCE_LOW,
1771                 mService.getNotificationRecord(sbn.getKey()).getImportance());
1772         assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
1773                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1774         mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId());
1775         waitForIdle();
1776 
1777         update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
1778         update.setUserVisibleTaskShown(true);
1779         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update);
1780         waitForIdle();
1781         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1782                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1783 
1784         sbn = generateNotificationRecord(channel).getSbn();
1785         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1786         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1787                 "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService",
1788                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1789         waitForIdle();
1790         // The second time it is shown, we keep the user's preference.
1791         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1792         assertNull(mService.getNotificationRecord(sbn.getKey()));
1793         assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
1794                 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance());
1795     }
1796 
1797     @Test
testBlockedNotifications_blockedChannelGroup()1798     public void testBlockedNotifications_blockedChannelGroup() throws Exception {
1799         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1800         mService.setPreferencesHelper(mPreferencesHelper);
1801         when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())).
1802                 thenReturn(true);
1803 
1804         NotificationChannel channel = new NotificationChannel("id", "name",
1805                 NotificationManager.IMPORTANCE_HIGH);
1806         channel.setGroup("something");
1807         NotificationRecord r = generateNotificationRecord(channel);
1808         assertTrue(mService.isRecordBlockedLocked(r));
1809     }
1810 
1811     @Test
testEnqueuedBlockedNotifications_blockedApp()1812     public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
1813         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1814         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1815 
1816         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1817         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1818                 "testEnqueuedBlockedNotifications_blockedApp",
1819                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1820         waitForIdle();
1821         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1822     }
1823 
1824     @Test
testEnqueuedBlockedNotifications_blockedAppForegroundService()1825     public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
1826         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1827         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1828         when(mAmi.applyForegroundServiceNotification(
1829                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
1830 
1831         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1832         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
1833         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1834                 "testEnqueuedBlockedNotifications_blockedAppForegroundService",
1835                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
1836         waitForIdle();
1837         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
1838         assertNull(mService.getNotificationRecord(sbn.getKey()));
1839     }
1840 
1841     /**
1842      * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive
1843      * devices can use car categories.
1844      */
1845     @Test
testEnqueuedRestrictedNotifications_hasPermission()1846     public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception {
1847         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1848                 .thenReturn(true);
1849         // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot
1850         // obtain. Mocking out enforce permission call to ensure notifications can be created when
1851         // permitted.
1852         doNothing().when(mContext).enforceCallingPermission(
1853                 eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString());
1854         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1855                 Notification.CATEGORY_CAR_WARNING,
1856                 Notification.CATEGORY_CAR_INFORMATION);
1857         int id = 0;
1858         for (String category: categories) {
1859             final StatusBarNotification sbn =
1860                     generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn();
1861             sbn.getNotification().category = category;
1862             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1863                     "testEnqueuedRestrictedNotifications_asSystem",
1864                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
1865         }
1866         waitForIdle();
1867         assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length);
1868     }
1869 
1870 
1871     /**
1872      * Confirm restricted notification categories only apply to automotive.
1873      */
1874     @Test
testEnqueuedRestrictedNotifications_notAutomotive()1875     public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception {
1876         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1877                 .thenReturn(false);
1878         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1879                 Notification.CATEGORY_CAR_WARNING,
1880                 Notification.CATEGORY_CAR_INFORMATION);
1881         int id = 0;
1882         for (String category: categories) {
1883             final StatusBarNotification sbn =
1884                     generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn();
1885             sbn.getNotification().category = category;
1886             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1887                     "testEnqueuedRestrictedNotifications_notAutomotive",
1888                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
1889         }
1890         waitForIdle();
1891         assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length);
1892     }
1893 
1894     /**
1895      * Confirm if an application tries to use the car categories on a automotive device without the
1896      * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown.
1897      */
1898     @Test
testEnqueuedRestrictedNotifications_noPermission()1899     public void testEnqueuedRestrictedNotifications_noPermission() throws Exception {
1900         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
1901                 .thenReturn(true);
1902         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
1903                 Notification.CATEGORY_CAR_WARNING,
1904                 Notification.CATEGORY_CAR_INFORMATION);
1905         for (String category: categories) {
1906             final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
1907             sbn.getNotification().category = category;
1908             try {
1909                 mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
1910                         "testEnqueuedRestrictedNotifications_badUser",
1911                         sbn.getId(), sbn.getNotification(), sbn.getUserId());
1912                 fail("Calls from non system apps should not allow use of restricted categories");
1913             } catch (SecurityException e) {
1914                 // pass
1915             }
1916         }
1917         waitForIdle();
1918         assertEquals(0, mBinderService.getActiveNotifications(mPkg).length);
1919     }
1920 
1921     @Test
testSetNotificationsEnabledForPackage_noChange()1922     public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
1923         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1924         mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
1925 
1926         verify(mPermissionHelper, never()).setNotificationPermission(
1927                 anyString(), anyInt(), anyBoolean(), anyBoolean());
1928     }
1929 
1930     @Test
testSetNotificationsEnabledForPackage()1931     public void testSetNotificationsEnabledForPackage() throws Exception {
1932         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
1933         mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
1934 
1935         verify(mPermissionHelper).setNotificationPermission(
1936                 mContext.getPackageName(), mUserId, false, true);
1937 
1938         verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
1939         List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls();
1940         Assert.assertEquals(
1941                 NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
1942                 calls.get(calls.size() -1).event);
1943     }
1944 
1945     @Test
testBlockedNotifications_blockedByAssistant()1946     public void testBlockedNotifications_blockedByAssistant() throws Exception {
1947         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1948         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
1949 
1950         NotificationChannel channel = new NotificationChannel("id", "name",
1951                 NotificationManager.IMPORTANCE_HIGH);
1952         NotificationRecord r = generateNotificationRecord(channel);
1953         mService.addEnqueuedNotification(r);
1954 
1955         Bundle bundle = new Bundle();
1956         bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE);
1957         Adjustment adjustment = new Adjustment(
1958                 r.getSbn().getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier());
1959         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
1960 
1961         NotificationManagerService.PostNotificationRunnable runnable =
1962                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1963                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
1964         runnable.run();
1965         waitForIdle();
1966 
1967         verify(mUsageStats, never()).registerPostedByApp(any());
1968     }
1969 
1970     @Test
testBlockedNotifications_blockedByUser()1971     public void testBlockedNotifications_blockedByUser() throws Exception {
1972         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
1973         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
1974 
1975         NotificationChannel channel = new NotificationChannel("id", "name",
1976                 NotificationManager.IMPORTANCE_HIGH);
1977         NotificationRecord r = generateNotificationRecord(channel);
1978         mService.addEnqueuedNotification(r);
1979 
1980         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
1981 
1982         NotificationManagerService.PostNotificationRunnable runnable =
1983                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
1984                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
1985         runnable.run();
1986         waitForIdle();
1987 
1988         verify(mUsageStats).registerBlocked(any());
1989         verify(mUsageStats, never()).registerPostedByApp(any());
1990     }
1991 
1992     @Test
testEnqueueNotificationInternal_noChannel()1993     public void testEnqueueNotificationInternal_noChannel() throws Exception {
1994         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
1995         NotificationRecord nr = generateNotificationRecord(
1996                 new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
1997 
1998         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
1999                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
2000         waitForIdle();
2001 
2002         verify(mPermissionHelper).hasPermission(mUid);
2003         verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
2004 
2005         reset(mPermissionHelper);
2006         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
2007 
2008         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
2009                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
2010         waitForIdle();
2011 
2012         verify(mPermissionHelper).hasPermission(mUid);
2013         assertThat(mService.mChannelToastsSent).contains(mUid);
2014     }
2015 
2016     @Test
testEnqueueNotification_appBlocked()2017     public void testEnqueueNotification_appBlocked() throws Exception {
2018         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
2019 
2020         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2021                 "testEnqueueNotification_appBlocked", 0,
2022                 generateNotificationRecord(null).getNotification(), mUserId);
2023         waitForIdle();
2024         verify(mWorkerHandler, never()).post(
2025                 any(NotificationManagerService.EnqueueNotificationRunnable.class));
2026     }
2027 
2028     @Test
testEnqueueNotificationWithTag_PopulatesGetActiveNotifications()2029     public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
2030         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2031                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2032                 generateNotificationRecord(null).getNotification(), mUserId);
2033         waitForIdle();
2034         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
2035         assertEquals(1, notifs.length);
2036         assertEquals(1, mService.getNotificationRecordCount());
2037     }
2038 
2039     @Test
testEnqueueNotificationWithTag_WritesExpectedLogs()2040     public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception {
2041         final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog";
2042         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2043                 generateNotificationRecord(null).getNotification(), mUserId);
2044         waitForIdle();
2045         assertEquals(1, mNotificationRecordLogger.numCalls());
2046 
2047         NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0);
2048         assertTrue(call.wasLogged);
2049         assertEquals(NOTIFICATION_POSTED, call.event);
2050         assertNotNull(call.r);
2051         assertNull(call.old);
2052         assertEquals(0, call.position);
2053         assertEquals(0, call.buzzBeepBlink);
2054         assertEquals(mPkg, call.r.getSbn().getPackageName());
2055         assertEquals(0, call.r.getSbn().getId());
2056         assertEquals(tag, call.r.getSbn().getTag());
2057         assertEquals(1, call.getInstanceId());  // Fake instance IDs are assigned in order
2058         assertThat(call.postDurationMillisLogged).isGreaterThan(0);
2059     }
2060 
2061     @Test
testEnqueueNotificationWithTag_LogsOnMajorUpdates()2062     public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception {
2063         final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates";
2064         Notification original = new Notification.Builder(mContext,
2065                 mTestNotificationChannel.getId())
2066                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
2067         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, original, mUserId);
2068         Notification update = new Notification.Builder(mContext,
2069                 mTestNotificationChannel.getId())
2070                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2071                 .setCategory(Notification.CATEGORY_ALARM).build();
2072         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, update, mUserId);
2073         waitForIdle();
2074         assertEquals(2, mNotificationRecordLogger.numCalls());
2075 
2076         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2077         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2078         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
2079         assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0);
2080 
2081         assertTrue(mNotificationRecordLogger.get(1).wasLogged);
2082         assertEquals(NOTIFICATION_UPDATED, mNotificationRecordLogger.event(1));
2083         // Instance ID doesn't change on update of an active notification
2084         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
2085         assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isGreaterThan(0);
2086     }
2087 
2088     @Test
testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate()2089     public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception {
2090         final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate";
2091         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2092                 generateNotificationRecord(null).getNotification(), mUserId);
2093         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2094                 generateNotificationRecord(null).getNotification(), mUserId);
2095         waitForIdle();
2096         assertEquals(2, mNotificationRecordLogger.numCalls());
2097         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2098         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2099         assertFalse(mNotificationRecordLogger.get(1).wasLogged);
2100         assertNull(mNotificationRecordLogger.event(1));
2101     }
2102 
2103     @Test
testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate()2104     public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception {
2105         final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate";
2106         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0,
2107                 generateNotificationRecord(null).getNotification(),
2108                 mUserId);
2109         final Notification notif = generateNotificationRecord(null).getNotification();
2110         notif.extras.putString(Notification.EXTRA_TITLE, "Changed title");
2111         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notif, mUserId);
2112         waitForIdle();
2113         assertEquals(2, mNotificationRecordLogger.numCalls());
2114         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2115         assertNull(mNotificationRecordLogger.event(1));
2116     }
2117 
2118     @Test
testEnqueueNotificationWithTag_LogsAgainAfterCancel()2119     public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception {
2120         final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel";
2121         Notification notification = new Notification.Builder(mContext,
2122                 mTestNotificationChannel.getId())
2123                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
2124         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId);
2125         waitForIdle();
2126         mBinderService.cancelNotificationWithTag(mPkg, mPkg, tag, 0, mUserId);
2127         waitForIdle();
2128         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId);
2129         waitForIdle();
2130         assertEquals(3, mNotificationRecordLogger.numCalls());
2131 
2132         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0));
2133         assertTrue(mNotificationRecordLogger.get(0).wasLogged);
2134         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
2135         assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0);
2136 
2137         assertEquals(
2138                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
2139                 mNotificationRecordLogger.event(1));
2140         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
2141         // Cancel is not post, so no logged post_duration_millis.
2142         assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isNull();
2143 
2144         assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(2));
2145         assertTrue(mNotificationRecordLogger.get(2).wasLogged);
2146         // New instance ID because notification was canceled before re-post
2147         assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId());
2148         assertThat(mNotificationRecordLogger.get(2).postDurationMillisLogged).isGreaterThan(0);
2149     }
2150 
2151     @Test
testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed()2152     public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception {
2153         when(mAmi.applyForegroundServiceNotification(
2154                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
2155         mContext.getTestablePermissions().setPermission(
2156                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
2157 
2158         final String tag = "testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed";
2159 
2160         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2161                 .setContentTitle("foo")
2162                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2163                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
2164                 .build();
2165         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, tag, mUid, 0,
2166                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
2167         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag,
2168                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2169         waitForIdle();
2170 
2171         StatusBarNotification[] notifs =
2172                 mBinderService.getActiveNotifications(mPkg);
2173         assertThat(notifs[0].getNotification().flags).isEqualTo(
2174                 FLAG_FOREGROUND_SERVICE | FLAG_CAN_COLORIZE | FLAG_NO_CLEAR);
2175     }
2176 
2177     @Test
testEnqueueNotificationWithTag_nullAction_fixed()2178     public void testEnqueueNotificationWithTag_nullAction_fixed() throws Exception {
2179         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2180                 .setContentTitle("foo")
2181                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2182                 .addAction(new Notification.Action.Builder(null, "one", null).build())
2183                 .addAction(new Notification.Action.Builder(null, "two", null).build())
2184                 .addAction(new Notification.Action.Builder(null, "three", null).build())
2185                 .build();
2186         n.actions[1] = null;
2187 
2188         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
2189         waitForIdle();
2190 
2191         StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg);
2192         assertThat(posted).hasLength(1);
2193         assertThat(posted[0].getNotification().actions).hasLength(2);
2194         assertThat(posted[0].getNotification().actions[0].title.toString()).isEqualTo("one");
2195         assertThat(posted[0].getNotification().actions[1].title.toString()).isEqualTo("three");
2196     }
2197 
2198     @Test
testEnqueueNotificationWithTag_allNullActions_fixed()2199     public void testEnqueueNotificationWithTag_allNullActions_fixed() throws Exception {
2200         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2201                 .setContentTitle("foo")
2202                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2203                 .addAction(new Notification.Action.Builder(null, "one", null).build())
2204                 .addAction(new Notification.Action.Builder(null, "two", null).build())
2205                 .build();
2206         n.actions[0] = null;
2207         n.actions[1] = null;
2208 
2209         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
2210         waitForIdle();
2211 
2212         StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg);
2213         assertThat(posted).hasLength(1);
2214         assertThat(posted[0].getNotification().actions).isNull();
2215     }
2216 
2217     @Test
enqueueNotificationWithTag_usesAndFinishesTracker()2218     public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception {
2219         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2220                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2221                 generateNotificationRecord(null).getNotification(), mUserId);
2222 
2223         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2224         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue();
2225 
2226         waitForIdle();
2227 
2228         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(1);
2229         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2230         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2231     }
2232 
2233     @Test
enqueueNotificationWithTag_throws_usesAndCancelsTracker()2234     public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception {
2235         // Simulate not enqueued due to rejected inputs.
2236         assertThrows(Exception.class,
2237                 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2238                         "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2239                         /* notification= */ null, mUserId));
2240 
2241         waitForIdle();
2242 
2243         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2244         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2245         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2246     }
2247 
2248     @Test
enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker()2249     public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception {
2250         // Simulate not enqueued due to snoozing inputs.
2251         when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
2252                 .thenReturn("zzzzzzz");
2253 
2254         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2255                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2256                 generateNotificationRecord(null).getNotification(), mUserId);
2257         waitForIdle();
2258 
2259         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2260         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2261         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2262     }
2263 
2264     @Test
enqueueNotificationWithTag_notPosted_usesAndCancelsTracker()2265     public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception {
2266         // Simulate not posted due to blocked app.
2267         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
2268 
2269         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2270                 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0,
2271                 generateNotificationRecord(null).getNotification(), mUserId);
2272         waitForIdle();
2273 
2274         assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0);
2275         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1);
2276         assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse();
2277     }
2278 
2279     @Test
enqueueNotification_acquiresAndReleasesWakeLock()2280     public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception {
2281         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2282                 "enqueueNotification_acquiresAndReleasesWakeLock", 0,
2283                 generateNotificationRecord(null).getNotification(), mUserId);
2284 
2285         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2286         assertThat(mAcquiredWakeLocks).hasSize(1);
2287         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2288 
2289         waitForIdle();
2290 
2291         assertThat(mAcquiredWakeLocks).hasSize(1);
2292         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2293     }
2294 
2295     @Test
enqueueNotification_throws_acquiresAndReleasesWakeLock()2296     public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception {
2297         // Simulate not enqueued due to rejected inputs.
2298         assertThrows(Exception.class,
2299                 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2300                         "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0,
2301                         /* notification= */ null, mUserId));
2302 
2303         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2304         assertThat(mAcquiredWakeLocks).hasSize(1);
2305         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2306     }
2307 
2308     @Test
enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock()2309     public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception {
2310         // Simulate not enqueued due to snoozing inputs.
2311         when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
2312                 .thenReturn("zzzzzzz");
2313 
2314         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2315                 "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0,
2316                 generateNotificationRecord(null).getNotification(), mUserId);
2317 
2318         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2319         assertThat(mAcquiredWakeLocks).hasSize(1);
2320         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2321 
2322         waitForIdle();
2323 
2324         assertThat(mAcquiredWakeLocks).hasSize(1);
2325         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2326     }
2327 
2328     @Test
enqueueNotification_notPosted_acquiresAndReleasesWakeLock()2329     public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception {
2330         // Simulate enqueued but not posted due to missing small icon.
2331         Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId())
2332                 .setContentTitle("foo")
2333                 .build();
2334 
2335         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2336                 "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0,
2337                 notif, mUserId);
2338 
2339         verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2340         assertThat(mAcquiredWakeLocks).hasSize(1);
2341         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
2342 
2343         waitForIdle();
2344 
2345         // NLSes were not called.
2346         verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean());
2347 
2348         assertThat(mAcquiredWakeLocks).hasSize(1);
2349         assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
2350     }
2351 
2352     @Test
enqueueNotification_setsWakeLockWorkSource()2353     public void enqueueNotification_setsWakeLockWorkSource() throws Exception {
2354         // Use a "full" mock for the PowerManager (instead of the one that delegates to the real
2355         // service) so we can return a mocked WakeLock that we can verify() on.
2356         reset(mPowerManager);
2357         WakeLock wakeLock = mock(WakeLock.class);
2358         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock);
2359 
2360         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2361                 "enqueueNotification_setsWakeLockWorkSource", 0,
2362                 generateNotificationRecord(null).getNotification(), mUserId);
2363         waitForIdle();
2364 
2365         InOrder inOrder = inOrder(mPowerManager, wakeLock);
2366         inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
2367         inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, mPkg)));
2368         inOrder.verify(wakeLock).acquire(anyLong());
2369         inOrder.verify(wakeLock).release();
2370         inOrder.verifyNoMoreInteractions();
2371     }
2372 
2373     @Test
testCancelNonexistentNotification()2374     public void testCancelNonexistentNotification() throws Exception {
2375         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2376                 "testCancelNonexistentNotification", 0, mUserId);
2377         waitForIdle();
2378         // The notification record logger doesn't even get called when a nonexistent notification
2379         // is cancelled, because that happens very frequently and is not interesting.
2380         assertEquals(0, mNotificationRecordLogger.numCalls());
2381     }
2382 
2383     @Test
testCancelNotificationImmediatelyAfterEnqueue()2384     public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
2385         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2386                 "testCancelNotificationImmediatelyAfterEnqueue", 0,
2387                 generateNotificationRecord(null).getNotification(), mUserId);
2388         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2389                 "testCancelNotificationImmediatelyAfterEnqueue", 0, mUserId);
2390         waitForIdle();
2391         StatusBarNotification[] notifs =
2392                 mBinderService.getActiveNotifications(mPkg);
2393         assertEquals(0, notifs.length);
2394         assertEquals(0, mService.getNotificationRecordCount());
2395     }
2396 
2397     @Test
testPostCancelPostNotifiesListeners()2398     public void testPostCancelPostNotifiesListeners() throws Exception {
2399         // WHEN a notification is posted
2400         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2401         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(),
2402                 sbn.getNotification(), sbn.getUserId());
2403         mTestableLooper.moveTimeForward(1);
2404         // THEN it is canceled
2405         mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId());
2406         mTestableLooper.moveTimeForward(1);
2407         // THEN it is posted again (before the cancel has a chance to finish)
2408         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(),
2409                 sbn.getNotification(), sbn.getUserId());
2410         // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected
2411         waitForIdle();
2412 
2413         // The final enqueue made it to the listener instead of being canceled
2414         StatusBarNotification[] notifs =
2415                 mBinderService.getActiveNotifications(mPkg);
2416         assertEquals(1, notifs.length);
2417         assertEquals(1, mService.getNotificationRecordCount());
2418     }
2419 
2420     @Test
testCancelNotificationWhilePostedAndEnqueued()2421     public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
2422         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2423                 "testCancelNotificationWhilePostedAndEnqueued", 0,
2424                 generateNotificationRecord(null).getNotification(), mUserId);
2425         waitForIdle();
2426         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2427                 "testCancelNotificationWhilePostedAndEnqueued", 0,
2428                 generateNotificationRecord(null).getNotification(), mUserId);
2429         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
2430                 "testCancelNotificationWhilePostedAndEnqueued", 0, mUserId);
2431         waitForIdle();
2432         StatusBarNotification[] notifs =
2433                 mBinderService.getActiveNotifications(mPkg);
2434         assertEquals(0, notifs.length);
2435         assertEquals(0, mService.getNotificationRecordCount());
2436         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
2437         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
2438         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
2439     }
2440 
2441     @Test
testCancelNotificationsFromListenerImmediatelyAfterEnqueue()2442     public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
2443         NotificationRecord r = generateNotificationRecord(null);
2444         final StatusBarNotification sbn = r.getSbn();
2445         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2446                 "testCancelNotificationsFromListenerImmediatelyAfterEnqueue",
2447                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2448         mBinderService.cancelNotificationsFromListener(null, null);
2449         waitForIdle();
2450         StatusBarNotification[] notifs =
2451                 mBinderService.getActiveNotifications(sbn.getPackageName());
2452         assertEquals(0, notifs.length);
2453         assertEquals(0, mService.getNotificationRecordCount());
2454     }
2455 
2456     @Test
testCancelAllNotificationsImmediatelyAfterEnqueue()2457     public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
2458         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2459         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2460                 "testCancelAllNotificationsImmediatelyAfterEnqueue",
2461                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
2462         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2463         waitForIdle();
2464         StatusBarNotification[] notifs =
2465                 mBinderService.getActiveNotifications(sbn.getPackageName());
2466         assertEquals(0, notifs.length);
2467         assertEquals(0, mService.getNotificationRecordCount());
2468     }
2469 
2470     @Test
testUserInitiatedClearAll_noLeak()2471     public void testUserInitiatedClearAll_noLeak() throws Exception {
2472         final NotificationRecord n = generateNotificationRecord(
2473                 mTestNotificationChannel, 1, "group", true);
2474 
2475         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2476                 "testUserInitiatedClearAll_noLeak",
2477                 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId());
2478         waitForIdle();
2479 
2480         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
2481                 n.getUserId());
2482         waitForIdle();
2483         StatusBarNotification[] notifs =
2484                 mBinderService.getActiveNotifications(n.getSbn().getPackageName());
2485         assertEquals(0, notifs.length);
2486         assertEquals(0, mService.getNotificationRecordCount());
2487         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
2488         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
2489         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
2490     }
2491 
2492     @Test
testCancelAllNotificationsCancelsChildren()2493     public void testCancelAllNotificationsCancelsChildren() throws Exception {
2494         final NotificationRecord parent = generateNotificationRecord(
2495                 mTestNotificationChannel, 1, "group1", true);
2496         final NotificationRecord child = generateNotificationRecord(
2497                 mTestNotificationChannel, 2, "group1", false);
2498 
2499         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2500                 "testCancelAllNotificationsCancelsChildren",
2501                 parent.getSbn().getId(), parent.getSbn().getNotification(),
2502                 parent.getSbn().getUserId());
2503         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2504                 "testCancelAllNotificationsCancelsChildren",
2505                 child.getSbn().getId(), child.getSbn().getNotification(),
2506                 child.getSbn().getUserId());
2507         waitForIdle();
2508 
2509         mBinderService.cancelAllNotifications(mPkg, parent.getSbn().getUserId());
2510         waitForIdle();
2511         assertEquals(0, mService.getNotificationRecordCount());
2512     }
2513 
2514     @Test
testCancelAllNotificationsMultipleEnqueuedDoesNotCrash()2515     public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
2516         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
2517         for (int i = 0; i < 10; i++) {
2518             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2519                     "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash",
2520                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
2521         }
2522         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
2523         waitForIdle();
2524 
2525         assertEquals(0, mService.getNotificationRecordCount());
2526     }
2527 
2528     @Test
testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash()2529     public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception {
2530         final NotificationRecord parent = generateNotificationRecord(
2531                 mTestNotificationChannel, 1, "group1", true);
2532         final NotificationRecord parentAsChild = generateNotificationRecord(
2533                 mTestNotificationChannel, 1, "group1", false);
2534         final NotificationRecord child = generateNotificationRecord(
2535                 mTestNotificationChannel, 2, "group1", false);
2536 
2537         // fully post parent notification
2538         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2539                 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2540                 parent.getSbn().getId(), parent.getSbn().getNotification(),
2541                 parent.getSbn().getUserId());
2542         waitForIdle();
2543 
2544         // enqueue the child several times
2545         for (int i = 0; i < 10; i++) {
2546             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2547                     "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2548                     child.getSbn().getId(), child.getSbn().getNotification(),
2549                     child.getSbn().getUserId());
2550         }
2551         // make the parent a child, which will cancel the child notification
2552         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
2553                 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash",
2554                 parentAsChild.getSbn().getId(), parentAsChild.getSbn().getNotification(),
2555                 parentAsChild.getSbn().getUserId());
2556         waitForIdle();
2557 
2558         assertEquals(0, mService.getNotificationRecordCount());
2559     }
2560 
2561     @Test
2562     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationAdded()2563     public void testAutobundledSummary_notificationAdded() {
2564         NotificationRecord summary =
2565                 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2566         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2567         mService.addNotification(summary);
2568         mService.mSummaryByGroupKey.put("pkg", summary);
2569         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2570         mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
2571 
2572         mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY,
2573                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2574                     mock(Icon.class), 0,
2575                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2576         waitForIdle();
2577 
2578         assertTrue(summary.getSbn().isOngoing());
2579     }
2580 
2581     @Test
2582     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationAdded_forcedGrouping()2583     public void testAutobundledSummary_notificationAdded_forcedGrouping() {
2584         NotificationRecord summary =
2585                 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2586         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2587         mService.addNotification(summary);
2588         mService.mSummaryByGroupKey.put("pkg", summary);
2589         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2590         mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey());
2591 
2592         mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(),
2593                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2594                     mock(Icon.class), 0,
2595                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2596         waitForIdle();
2597 
2598         assertTrue(summary.getSbn().isOngoing());
2599     }
2600 
2601     @Test
2602     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationRemoved()2603     public void testAutobundledSummary_notificationRemoved() {
2604         NotificationRecord summary =
2605                 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2606         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2607         summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
2608         mService.addNotification(summary);
2609         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2610         mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
2611         mService.mSummaryByGroupKey.put(summary.getGroupKey(), summary);
2612 
2613         mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY,
2614                 new NotificationAttributes(GroupHelper.BASE_FLAGS,
2615                     mock(Icon.class), 0,
2616                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2617         waitForIdle();
2618 
2619         assertFalse(summary.getSbn().isOngoing());
2620     }
2621 
2622     @Test
2623     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAutobundledSummary_notificationRemoved_forceGrouping()2624     public void testAutobundledSummary_notificationRemoved_forceGrouping() {
2625         NotificationRecord summary =
2626             generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true);
2627         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2628         summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
2629         mService.addNotification(summary);
2630         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2631         mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey());
2632 
2633         mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(),
2634                 new NotificationAttributes(GroupHelper.BASE_FLAGS,
2635                     mock(Icon.class), 0,
2636                     VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false);
2637         waitForIdle();
2638 
2639         assertFalse(summary.getSbn().isOngoing());
2640     }
2641 
2642     @Test
2643     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAggregatedSummary_updateSummaryAttributes()2644     public void testAggregatedSummary_updateSummaryAttributes() {
2645         final String aggregateGroupName = "Aggregate_Test";
2646         final String newChannelId = "newChannelId";
2647         final NotificationChannel newChannel = new NotificationChannel(
2648                 newChannelId, newChannelId, IMPORTANCE_DEFAULT);
2649         mService.setPreferencesHelper(mPreferencesHelper);
2650         final NotificationRecord summary =
2651                 generateNotificationRecord(mTestNotificationChannel, 0, aggregateGroupName, true);
2652         final String groupKey = summary.getGroupKey();
2653         summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
2654         mService.addNotification(summary);
2655         mService.mAutobundledSummaries.put(0, new ArrayMap<>());
2656         mService.mAutobundledSummaries.get(0).put(groupKey, summary.getKey());
2657         when(mPreferencesHelper.getNotificationChannel(eq("pkg"), anyInt(),
2658                 eq(newChannelId), anyBoolean())).thenReturn(newChannel);
2659 
2660         mService.updateAutobundledSummaryLocked(0, "pkg", groupKey,
2661                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
2662                     mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, newChannelId),
2663                     false);
2664         waitForIdle();
2665 
2666         assertTrue(summary.getSbn().isOngoing());
2667         assertThat(summary.getNotification().getGroupAlertBehavior()).isEqualTo(
2668                 GROUP_ALERT_CHILDREN);
2669 
2670         assertThat(summary.getChannel().getId()).isEqualTo(newChannelId);
2671     }
2672 
2673     @Test
2674     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAddAggregateNotification_notifyPostedLocked()2675     public void testAddAggregateNotification_notifyPostedLocked() throws Exception {
2676         final String originalGroupName = "originalGroup";
2677         final NotificationRecord r =
2678                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
2679         mService.addNotification(r);
2680         mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true);
2681 
2682         assertThat(r.getSbn().getOverrideGroupKey()).isEqualTo("grpKey");
2683         verify(mRankingHandler, times(1)).requestSort();
2684         verify(mListeners, times(1)).notifyPostedLocked(eq(r), eq(r));
2685     }
2686 
2687     @Test
2688     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testAddAggregateSummaryNotification_convertSummary()2689     public void testAddAggregateSummaryNotification_convertSummary() throws Exception {
2690         final String originalGroupName = "originalGroup";
2691         final NotificationRecord r =
2692                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
2693         final String groupKey = r.getGroupKey();
2694         mService.addNotification(r);
2695         assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isTrue();
2696         boolean isConverted = mService.convertSummaryToNotificationLocked(r.getKey());
2697 
2698         assertThat(isConverted).isTrue();
2699         assertThat(r.getSbn().isGroup()).isTrue();
2700         assertThat(r.getNotification().isGroupSummary()).isFalse();
2701         assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isFalse();
2702     }
2703 
2704     @Test
2705     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2706             Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
testAggregateGroups_RemoveAppSummary()2707     public void testAggregateGroups_RemoveAppSummary() throws Exception {
2708         final String originalGroupName = "originalGroup";
2709         final NotificationRecord r =
2710                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
2711         mService.addNotification(r);
2712         mService.removeAppSummaryLocked(r.getKey());
2713 
2714         assertThat(r.isCanceled).isTrue();
2715         waitForIdle();
2716         verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(0));
2717     }
2718 
2719     @Test
2720     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION})
testAggregateGroups_RemoveAppSummary_onClassification()2721     public void testAggregateGroups_RemoveAppSummary_onClassification() throws Exception {
2722         final String originalGroupName = "originalGroup";
2723         final int summaryId = 0;
2724         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
2725                 summaryId + 1, originalGroupName, false);
2726         mService.addNotification(r1);
2727         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
2728                 summaryId + 2, originalGroupName, false);
2729         mService.addNotification(r2);
2730         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
2731                 summaryId, originalGroupName, true);
2732         mService.addNotification(summary);
2733         final String originalGroupKey = summary.getGroupKey();
2734         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
2735 
2736         // Regroup first child notification
2737         r1.setOverrideGroupKey("newGroup");
2738         // Check that removeAppProvidedSummaryOnClassificationLocked is null
2739         //  => there is still one child left in the original group
2740         assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r1.getKey(),
2741                 originalGroupKey)).isNull();
2742 
2743         // Regroup last child notification
2744         r2.setOverrideGroupKey("newGroup");
2745         // Check that removeAppProvidedSummaryOnClassificationLocked returns the original summary
2746         //  and that the original app-provided summary is canceled
2747         assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r2.getKey(),
2748                 originalGroupKey)).isEqualTo(summary);
2749         waitForIdle();
2750         verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(summaryId));
2751         assertThat(mService.mSummaryByGroupKey).doesNotContainKey(originalGroupKey);
2752     }
2753 
2754     @Test
2755     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testUngroupingAggregateSummary()2756     public void testUngroupingAggregateSummary() throws Exception {
2757         final String originalGroupName = "originalGroup";
2758         final String aggregateGroupName = "Aggregate_Test";
2759         final int summaryId = Integer.MAX_VALUE;
2760         // Add 2 group notifications without a summary
2761         NotificationRecord nr0 =
2762                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
2763         NotificationRecord nr1 =
2764                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
2765         mService.addNotification(nr0);
2766         mService.addNotification(nr1);
2767         mService.mSummaryByGroupKey.remove(nr0.getGroupKey());
2768 
2769         // GroupHelper is a mock, so make the calls it would make
2770         // Add aggregate group summary
2771         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
2772                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
2773                 nr0.getChannel().getId());
2774         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
2775                 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
2776         mService.addNotification(aggregateSummary);
2777         nr0.setOverrideGroupKey(aggregateGroupName);
2778         nr1.setOverrideGroupKey(aggregateGroupName);
2779         final String fullAggregateGroupKey = nr0.getGroupKey();
2780 
2781         // Check that the aggregate group summary was created
2782         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
2783         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
2784                 nr0.getChannel().getId());
2785         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
2786 
2787         // Cancel both children
2788         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
2789                 nr0.getSbn().getId(), nr0.getSbn().getUserId());
2790         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
2791                 nr1.getSbn().getId(), nr1.getSbn().getUserId());
2792         waitForIdle();
2793 
2794         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any(), eq(false));
2795         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any(), eq(false));
2796 
2797         // GroupHelper would send 'remove summary' event
2798         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(),
2799                 fullAggregateGroupKey);
2800         waitForIdle();
2801 
2802         // Make sure the summary was removed and not re-posted
2803         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
2804     }
2805 
2806     @Test
2807     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2808             Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
testCancelGroupChildrenForCanceledSummary_singletonGroup()2809     public void testCancelGroupChildrenForCanceledSummary_singletonGroup() throws Exception {
2810         final String originalGroupName = "originalGroup";
2811         final String aggregateGroupName = "Aggregate_Test";
2812         final int summaryId = Integer.MAX_VALUE;
2813         // Add a "singleton group"
2814         NotificationRecord nr0 =
2815                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
2816         NotificationRecord nr1 =
2817                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
2818         final NotificationRecord summary =
2819                 generateNotificationRecord(mTestNotificationChannel, 2, originalGroupName, true);
2820         final String originalGroupKey = summary.getGroupKey();
2821         mService.addNotification(nr0);
2822         mService.addNotification(nr1);
2823         mService.addNotification(summary);
2824 
2825         // GroupHelper is a mock, so make the calls it would make
2826         // Remove the app's summary notification
2827         mService.removeAppSummaryLocked(summary.getKey());
2828         waitForIdle();
2829 
2830         // Add aggregate group summary
2831         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
2832                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
2833                 nr0.getChannel().getId());
2834         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
2835             nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
2836         mService.addNotification(aggregateSummary);
2837 
2838         nr0.setOverrideGroupKey(aggregateGroupName);
2839         nr1.setOverrideGroupKey(aggregateGroupName);
2840         final String fullAggregateGroupKey = nr0.getGroupKey();
2841 
2842         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
2843         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
2844                 nr0.getChannel().getId());
2845         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
2846         assertThat(mService.mSummaryByGroupKey.containsKey(originalGroupKey)).isFalse();
2847 
2848         // Cancel the original app summary (is already removed)
2849         mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(),
2850                 summary.getSbn().getPackageName(), summary.getSbn().getTag(),
2851                 summary.getSbn().getId(), summary.getSbn().getUserId());
2852         waitForIdle();
2853 
2854         // Check if NMS.CancelNotificationRunnable calls maybeCancelGroupChildrenForCanceledSummary
2855         verify(mGroupHelper, times(1)).maybeCancelGroupChildrenForCanceledSummary(
2856                 eq(summary.getSbn().getPackageName()), eq(summary.getSbn().getTag()),
2857                 eq(summary.getSbn().getId()), eq(summary.getSbn().getUserId()),
2858                 eq(REASON_APP_CANCEL));
2859     }
2860 
2861     @Test
2862     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testUpdateChannel_notifyGroupHelper()2863     public void testUpdateChannel_notifyGroupHelper() throws Exception {
2864         mService.setPreferencesHelper(mPreferencesHelper);
2865         mTestNotificationChannel.setLightColor(Color.CYAN);
2866         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
2867                 eq(mTestNotificationChannel.getId()), anyBoolean()))
2868                 .thenReturn(mTestNotificationChannel);
2869 
2870         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel);
2871         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2872         waitForIdle();
2873 
2874         verify(mGroupHelper, times(1)).onChannelUpdated(eq(Process.myUserHandle().getIdentifier()),
2875                 eq(mPkg), eq(mTestNotificationChannel), any(), any());
2876     }
2877 
2878     @Test
2879     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed()2880     public void testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed() throws Exception {
2881         final String aggregateGroupName = "Aggregate_Test";
2882 
2883         // build autogroup summary notification
2884         Notification.Builder nb = new Notification.Builder(mContext,
2885                 mTestNotificationChannel.getId())
2886                 .setContentTitle("foo")
2887                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
2888                 .setGroup(aggregateGroupName)
2889                 .setGroupSummary(true)
2890                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true);
2891         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
2892                 "tag" + System.currentTimeMillis(), mUid, 0, nb.build(),
2893                 UserHandle.getUserHandleForUid(mUid), null, 0);
2894         final NotificationRecord summary = new NotificationRecord(mContext, sbn,
2895                 mTestNotificationChannel);
2896 
2897         final NotificationRecord child = generateNotificationRecord(
2898                 mTestNotificationChannel, 2, aggregateGroupName, false);
2899         mService.addNotification(summary);
2900         mService.addNotification(child);
2901         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
2902 
2903         // snooze child only
2904         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
2905                 mService.new SnoozeNotificationRunnable(
2906                     child.getKey(), 100, null);
2907         snoozeNotificationRunnable.run();
2908 
2909         // only child should be snoozed
2910         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
2911 
2912         // both group summary and child should be cancelled
2913         assertNull(mService.getNotificationRecord(summary.getKey()));
2914         assertNull(mService.getNotificationRecord(child.getKey()));
2915 
2916         assertEquals(4, mNotificationRecordLogger.numCalls());
2917         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
2918                 mNotificationRecordLogger.event(0));
2919         assertEquals(
2920                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
2921                 mNotificationRecordLogger.event(1));
2922     }
2923 
2924     @Test
2925     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2926             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testOnlyForceGroupIfNeeded_newNotification_notAutogrouped()2927     public void testOnlyForceGroupIfNeeded_newNotification_notAutogrouped() {
2928         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
2929         when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false);
2930         mService.addEnqueuedNotification(r);
2931         NotificationManagerService.PostNotificationRunnable runnable =
2932                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
2933                     r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
2934         runnable.run();
2935         waitForIdle();
2936 
2937         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2938         waitForIdle();
2939 
2940         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
2941         verify(mGroupHelper, times(1)).onNotificationPostedWithDelay(eq(r), any(), any());
2942     }
2943 
2944     @Test
2945     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2946             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped()2947     public void testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped() {
2948         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
2949         when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(true);
2950         mService.addEnqueuedNotification(r);
2951         NotificationManagerService.PostNotificationRunnable runnable =
2952             mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
2953                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
2954         runnable.run();
2955         waitForIdle();
2956 
2957         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2958         waitForIdle();
2959 
2960         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
2961         verify(mGroupHelper, never()).onNotificationPostedWithDelay(eq(r), any(), any());
2962     }
2963 
2964     @Test
2965     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
2966             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testRemoveScheduledForceGroup_onNotificationCanceled()2967     public void testRemoveScheduledForceGroup_onNotificationCanceled() throws Exception {
2968         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "tag", null,
2969                 false);
2970         when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false);
2971         mService.addEnqueuedNotification(r);
2972         NotificationManagerService.PostNotificationRunnable runnable =
2973                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
2974                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
2975         runnable.run();
2976         waitForIdle();
2977 
2978         // Post an update to the notification
2979         NotificationRecord r_update =
2980                 generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, false);
2981         mService.addEnqueuedNotification(r_update);
2982         runnable = mService.new PostNotificationRunnable(r_update.getKey(),
2983                 r_update.getSbn().getPackageName(), r_update.getUid(),
2984                 mPostNotificationTrackerFactory.newTracker(null));
2985         runnable.run();
2986         waitForIdle();
2987 
2988         // Cancel the notification
2989         mBinderService.cancelNotificationWithTag(r.getSbn().getPackageName(),
2990                 r.getSbn().getPackageName(), r.getSbn().getTag(),
2991                 r.getSbn().getId(), r.getSbn().getUserId());
2992         waitForIdle();
2993 
2994         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
2995         waitForIdle();
2996 
2997         // Check that onNotificationPostedWithDelay was canceled
2998         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
2999         verify(mGroupHelper, never()).onNotificationPostedWithDelay(any(), any(), any());
3000     }
3001 
3002     @Test
3003     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testEnqueueNotification_forceGrouped_clearsSummaryFlag()3004     public void testEnqueueNotification_forceGrouped_clearsSummaryFlag() throws Exception {
3005         final String originalGroupName = "originalGroup";
3006         final String aggregateGroupName = "Aggregate_Test";
3007 
3008         // Old record was a summary and it was auto-grouped
3009         final NotificationRecord r =
3010                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
3011         mService.addNotification(r);
3012         mService.convertSummaryToNotificationLocked(r.getKey());
3013         mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true);
3014 
3015         assertThat(mService.mNotificationList).hasSize(1);
3016 
3017         // Update record is a summary
3018         final Notification updatedNotification = generateNotificationRecord(
3019                 mTestNotificationChannel, 0, originalGroupName, true).getNotification();
3020         assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY);
3021 
3022         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
3023                 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId());
3024         waitForIdle();
3025 
3026         // Check that FLAG_GROUP_SUMMARY was removed
3027         assertThat(mService.mNotificationList).hasSize(1);
3028         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0);
3029     }
3030 
3031     @Test
3032     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag()3033     public void testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag()
3034             throws Exception {
3035         final String originalGroupName = "originalGroup";
3036         final String aggregateGroupName = "Aggregate_Test";
3037 
3038         // Old record was not summary and it was auto-grouped
3039         final NotificationRecord r =
3040                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
3041         mService.addNotification(r);
3042         mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true);
3043         assertThat(mService.mNotificationList).hasSize(1);
3044 
3045         // Update record is a summary
3046         final Notification updatedNotification = generateNotificationRecord(
3047                 mTestNotificationChannel, 0, originalGroupName, true).getNotification();
3048         assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY);
3049 
3050         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
3051                 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId());
3052         waitForIdle();
3053 
3054         // Check that FLAG_GROUP_SUMMARY was removed
3055         assertThat(mService.mNotificationList).hasSize(1);
3056         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0);
3057     }
3058 
3059     @Test
3060     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testEnqueueNotification_notForceGrouped_dontClearSummaryFlag()3061     public void testEnqueueNotification_notForceGrouped_dontClearSummaryFlag()
3062             throws Exception {
3063         final String originalGroupName = "originalGroup";
3064 
3065         // Old record was a summary and it was not auto-grouped
3066         final NotificationRecord r =
3067                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
3068         mService.addNotification(r);
3069         assertThat(mService.mNotificationList).hasSize(1);
3070 
3071         // Update record is a summary
3072         final Notification updatedNotification = generateNotificationRecord(
3073                 mTestNotificationChannel, 0, originalGroupName, true).getNotification();
3074         assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY);
3075 
3076         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
3077                 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId());
3078         waitForIdle();
3079 
3080         // Check that FLAG_GROUP_SUMMARY was not removed
3081         assertThat(mService.mNotificationList).hasSize(1);
3082         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(
3083                 FLAG_GROUP_SUMMARY);
3084     }
3085 
3086     @Test
3087     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag()3088     public void testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag() {
3089         final String originalGroupName = "originalGroup";
3090         final String aggregateGroupName = "Aggregate_Test";
3091 
3092         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null,
3093                 originalGroupName, true);
3094         r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY;
3095         r.setOverrideGroupKey(aggregateGroupName);
3096         mService.addEnqueuedNotification(r);
3097 
3098         mInternalService.removeForegroundServiceFlagFromNotification(
3099                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
3100         waitForIdle();
3101 
3102         assertThat(mService.mEnqueuedNotifications).hasSize(1);
3103         assertThat(mService.mEnqueuedNotifications.get(0).getFlags() & FLAG_GROUP_SUMMARY)
3104                 .isEqualTo(0);
3105     }
3106 
3107     @Test
3108     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag()3109     public void testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag() {
3110         final String originalGroupName = "originalGroup";
3111         final String aggregateGroupName = "Aggregate_Test";
3112 
3113         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null,
3114                 originalGroupName, true);
3115         r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY;
3116         r.setOverrideGroupKey(aggregateGroupName);
3117         mService.addNotification(r);
3118 
3119         mInternalService.removeForegroundServiceFlagFromNotification(
3120                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
3121         waitForIdle();
3122 
3123         assertThat(mService.mNotificationList).hasSize(1);
3124         assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0);
3125     }
3126 
3127     @Test
3128     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
3129             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testScheduleGroupHelperWithDelay_onChildNotificationCanceled()3130     public void testScheduleGroupHelperWithDelay_onChildNotificationCanceled() throws Exception {
3131         // Post summary + 2 child notification
3132         final String originalGroupName = "originalGroup";
3133         final int summaryId = 0;
3134         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
3135                 summaryId + 1, originalGroupName, false);
3136         mService.addNotification(r1);
3137         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
3138                 summaryId + 2, originalGroupName, false);
3139         mService.addNotification(r2);
3140         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
3141                 summaryId, originalGroupName, true);
3142         mService.addNotification(summary);
3143         final String originalGroupKey = summary.getGroupKey();
3144         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
3145 
3146         // Cancel the child notifications
3147         mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
3148                 r1.getSbn().getPackageName(), r1.getSbn().getTag(),
3149                 r1.getSbn().getId(), r1.getSbn().getUserId());
3150         waitForIdle();
3151 
3152         mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
3153                 r2.getSbn().getPackageName(), r2.getSbn().getTag(),
3154                 r2.getSbn().getId(), r2.getSbn().getUserId());
3155         waitForIdle();
3156 
3157         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
3158         waitForIdle();
3159 
3160         // Check that onGroupedNotificationRemovedWithDelay was called only once
3161         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any(), eq(false));
3162         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any(), eq(false));
3163         verify(mGroupHelper, times(1)).onGroupedNotificationRemovedWithDelay(eq(summary), any(),
3164                 any());
3165     }
3166 
3167     @Test
3168     @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
3169             android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()3170     public void testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()
3171             throws Exception {
3172         // Post summary + 2 child notification
3173         final String originalGroupName = "originalGroup";
3174         final int summaryId = 0;
3175         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
3176                 summaryId + 1, originalGroupName, false);
3177         mService.addNotification(r1);
3178         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
3179                 summaryId + 2, originalGroupName, false);
3180         mService.addNotification(r2);
3181         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
3182                 summaryId, originalGroupName, true);
3183         mService.addNotification(summary);
3184         final String originalGroupKey = summary.getGroupKey();
3185         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
3186 
3187         // Cancel all notifications: children + summary
3188         mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
3189                 r1.getSbn().getPackageName(), r1.getSbn().getTag(),
3190                 r1.getSbn().getId(), r1.getSbn().getUserId());
3191         waitForIdle();
3192 
3193         mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
3194                 r2.getSbn().getPackageName(), r2.getSbn().getTag(),
3195                 r2.getSbn().getId(), r2.getSbn().getUserId());
3196         waitForIdle();
3197 
3198         mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(),
3199                 summary.getSbn().getPackageName(), summary.getSbn().getTag(),
3200                 summary.getSbn().getId(), summary.getSbn().getUserId());
3201         waitForIdle();
3202 
3203         mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
3204         waitForIdle();
3205 
3206         // Check that onGroupedNotificationRemovedWithDelay was never called: summary was canceled
3207         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any(), eq(false));
3208         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any(), eq(false));
3209         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(summary), any(), eq(false));
3210         verify(mGroupHelper, never()).onGroupedNotificationRemovedWithDelay(any(), any(), any());
3211     }
3212 
3213     @Test
testCancelAllNotifications_IgnoreForegroundService()3214     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
3215         when(mAmi.applyForegroundServiceNotification(
3216                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
3217         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3218         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3219         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3220                 "testCancelAllNotifications_IgnoreForegroundService",
3221                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3222         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3223         waitForIdle();
3224         StatusBarNotification[] notifs =
3225                 mBinderService.getActiveNotifications(sbn.getPackageName());
3226         assertEquals(1, notifs.length);
3227         assertEquals(1, mService.getNotificationRecordCount());
3228     }
3229 
3230     @Test
testCancelAllNotifications_FgsFlag_NoFgs_Allowed()3231     public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception {
3232         when(mAmi.applyForegroundServiceNotification(
3233                 any(), anyString(), anyInt(), anyString(), anyInt()))
3234                 .thenReturn(NOT_FOREGROUND_SERVICE);
3235         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3236         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3237         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3238                 "testCancelAllNotifications_IgnoreForegroundService",
3239                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3240         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3241         waitForIdle();
3242         StatusBarNotification[] notifs =
3243                 mBinderService.getActiveNotifications(sbn.getPackageName());
3244         assertEquals(0, notifs.length);
3245     }
3246 
3247     @Test
testCancelAllNotifications_IgnoreOtherPackages()3248     public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
3249         when(mAmi.applyForegroundServiceNotification(
3250                 any(), anyString(), anyInt(), anyString(), anyInt()))
3251                 .thenReturn(SHOW_IMMEDIATELY);
3252         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3253         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3254         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3255                 "testCancelAllNotifications_IgnoreOtherPackages",
3256                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3257         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
3258         waitForIdle();
3259         StatusBarNotification[] notifs =
3260                 mBinderService.getActiveNotifications(sbn.getPackageName());
3261         assertEquals(1, notifs.length);
3262         assertEquals(1, mService.getNotificationRecordCount());
3263     }
3264 
3265     @Test
testCancelAllNotifications_NullPkgRemovesAll()3266     public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
3267         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3268         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3269                 "testCancelAllNotifications_NullPkgRemovesAll",
3270                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3271         mBinderService.cancelAllNotifications(null, sbn.getUserId());
3272         waitForIdle();
3273         StatusBarNotification[] notifs =
3274                 mBinderService.getActiveNotifications(sbn.getPackageName());
3275         assertEquals(0, notifs.length);
3276         assertEquals(0, mService.getNotificationRecordCount());
3277     }
3278 
3279     @Test
testCancelAllNotifications_NullPkgIgnoresUserAllNotifications()3280     public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
3281         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3282         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3283                 "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications",
3284                 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
3285         // Null pkg is how we signal a user switch.
3286         mBinderService.cancelAllNotifications(null, sbn.getUserId());
3287         waitForIdle();
3288         StatusBarNotification[] notifs =
3289                 mBinderService.getActiveNotifications(sbn.getPackageName());
3290         assertEquals(1, notifs.length);
3291         assertEquals(1, mService.getNotificationRecordCount());
3292     }
3293 
3294     @Test
testAppInitiatedCancelAllNotifications_CancelsNoClearFlag()3295     public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception {
3296         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3297         sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3298         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
3299                 "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag",
3300                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3301         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
3302         waitForIdle();
3303         StatusBarNotification[] notifs =
3304                 mBinderService.getActiveNotifications(sbn.getPackageName());
3305         assertEquals(0, notifs.length);
3306     }
3307 
3308     @Test
testCancelAllNotifications_CancelsNoClearFlag()3309     public void testCancelAllNotifications_CancelsNoClearFlag() throws Exception {
3310         final NotificationRecord notif = generateNotificationRecord(
3311                 mTestNotificationChannel, 1, "group", true);
3312         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3313         mService.addNotification(notif);
3314         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
3315                 notif.getUserId(), REASON_CANCEL);
3316         waitForIdle();
3317         StatusBarNotification[] notifs =
3318                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3319         assertEquals(0, notifs.length);
3320     }
3321 
3322     @Test
testUserInitiatedCancelAllOnClearAll_NoClearFlag()3323     public void testUserInitiatedCancelAllOnClearAll_NoClearFlag() throws Exception {
3324         final NotificationRecord notif = generateNotificationRecord(
3325                 mTestNotificationChannel, 1, "group", true);
3326         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
3327         mService.addNotification(notif);
3328 
3329         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3330                 notif.getUserId());
3331         waitForIdle();
3332         StatusBarNotification[] notifs =
3333                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3334         assertEquals(1, notifs.length);
3335     }
3336 
3337     @Test
testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue()3338     public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
3339         when(mAmi.applyForegroundServiceNotification(
3340                 any(), anyString(), anyInt(), anyString(), anyInt()))
3341                 .thenReturn(SHOW_IMMEDIATELY);
3342         Notification n =
3343                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
3344                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
3345                         .build();
3346         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
3347                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
3348         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3349         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null,
3350                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3351         mInternalService.removeForegroundServiceFlagFromNotification(mPkg, sbn.getId(),
3352                 sbn.getUserId());
3353         waitForIdle();
3354         StatusBarNotification[] notifs =
3355                 mBinderService.getActiveNotifications(sbn.getPackageName());
3356         assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE);
3357     }
3358 
3359     @Test
testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag()3360     public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
3361         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
3362         sbn.getNotification().flags =
3363                 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
3364         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
3365                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3366         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
3367         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
3368                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
3369         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3370                 sbn.getUserId());
3371         waitForIdle();
3372         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
3373         assertEquals(0, mService.getNotificationRecordCount());
3374     }
3375 
3376     @Test
3377     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelWithTagDoesNotCancelLifetimeExtended()3378     public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception {
3379         final NotificationRecord notif = generateNotificationRecord(null);
3380         notif.getSbn().getNotification().flags =
3381                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3382         mService.addNotification(notif);
3383         final StatusBarNotification sbn = notif.getSbn();
3384 
3385         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3386         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3387 
3388         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3389                 sbn.getUserId());
3390         waitForIdle();
3391 
3392         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3393         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3394 
3395         // Checks that a post update is sent.
3396         verify(mWorkerHandler, times(1))
3397                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3398         ArgumentCaptor<NotificationRecord> captor =
3399                 ArgumentCaptor.forClass(NotificationRecord.class);
3400         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3401                 anyBoolean());
3402         assertThat(captor.getValue().getNotification().flags
3403                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3404                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3405     }
3406 
3407     @Test
3408     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testMultipleCancelOfLifetimeExtendedSendsOneUpdate()3409     public void testMultipleCancelOfLifetimeExtendedSendsOneUpdate() throws Exception {
3410         final NotificationRecord notif = generateNotificationRecord(null);
3411         notif.getSbn().getNotification().flags =
3412                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3413         mService.addNotification(notif);
3414         final StatusBarNotification sbn = notif.getSbn();
3415 
3416         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3417         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3418 
3419         // Send two cancelations.
3420         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3421                 sbn.getUserId());
3422         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
3423                 sbn.getUserId());
3424         waitForIdle();
3425 
3426         assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
3427         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
3428 
3429         // Checks that only one post update is sent.
3430         verify(mWorkerHandler, times(1))
3431                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3432         ArgumentCaptor<NotificationRecord> captor =
3433                 ArgumentCaptor.forClass(NotificationRecord.class);
3434         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3435                 anyBoolean());
3436         assertThat(captor.getValue().getNotification().flags
3437                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3438                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3439     }
3440 
3441     @Test
3442     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelAllClearsLifetimeExtended()3443     public void testCancelAllClearsLifetimeExtended() throws Exception {
3444         final NotificationRecord notif = generateNotificationRecord(
3445                 mTestNotificationChannel, 1, "group", true);
3446         notif.getNotification().flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3447         mService.addNotification(notif);
3448         StatusBarNotification[] notifs =
3449                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3450         assertThat(notifs.length).isEqualTo(1);
3451 
3452         // Simulate a "cancel all" received.
3453         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
3454                 notif.getUserId());
3455         waitForIdle();
3456         notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3457         assertThat(notifs.length).isEqualTo(0);
3458 
3459         // Test that no update post is sent to System UI.
3460         verify(mWorkerHandler, never())
3461                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
3462     }
3463 
3464     @Test
3465     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testAppCancelAllDoesNotCancelLifetimeExtended()3466     public void testAppCancelAllDoesNotCancelLifetimeExtended() throws Exception {
3467         // Adds a lifetime extended notification.
3468         final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1,
3469                 null, false);
3470         notif.getSbn().getNotification().flags =
3471                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3472         mService.addNotification(notif);
3473         // Adds a second, non-lifetime extended notification.
3474         final NotificationRecord notifCancelable = generateNotificationRecord(
3475                 mTestNotificationChannel, 2, null, false);
3476         mService.addNotification(notifCancelable);
3477         // Verify that both notifications have been posted and are active.
3478         assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(2);
3479 
3480         mBinderService.cancelAllNotifications(mPkg, notif.getSbn().getUserId());
3481         waitForIdle();
3482 
3483         // The non-lifetime extended notification, with id = 2, has been cancelled.
3484         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
3485         assertThat(notifs.length).isEqualTo(1);
3486         assertThat(notifs[0].getId()).isEqualTo(1);
3487 
3488         // Checks that a post update is sent.
3489         verify(mWorkerHandler, times(1))
3490                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3491         ArgumentCaptor<NotificationRecord> captor =
3492                 ArgumentCaptor.forClass(NotificationRecord.class);
3493         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3494                 anyBoolean());
3495         assertThat(captor.getValue().getNotification().flags
3496                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3497                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3498     }
3499 
3500     @Test
3501     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testLifetimeExtendedCancelledOnClick()3502     public void testLifetimeExtendedCancelledOnClick() throws Exception {
3503         // Adds a lifetime extended notification.
3504         final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1,
3505                 null, false);
3506         notif.getSbn().getNotification().flags =
3507                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3508         mService.addNotification(notif);
3509         // Verify that the notification is posted and active.
3510         assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(1);
3511 
3512         // Click the notification.
3513         final NotificationVisibility nv = NotificationVisibility.obtain(notif.getKey(), 1, 2, true);
3514         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
3515                 notif.getKey(), nv);
3516         waitForIdle();
3517 
3518         // The notification has been cancelled.
3519         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
3520         assertThat(notifs.length).isEqualTo(0);
3521     }
3522 
3523     @Test
testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()3524     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()
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         final NotificationRecord child = generateNotificationRecord(
3534                 mTestNotificationChannel, 2, "group", false);
3535         final NotificationRecord child2 = generateNotificationRecord(
3536                 mTestNotificationChannel, 3, "group", false);
3537         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
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(1, notifs.length);
3548     }
3549 
3550     @Test
testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()3551     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()
3552             throws Exception {
3553         when(mAmi.applyForegroundServiceNotification(
3554                 any(), anyString(), anyInt(), anyString(), anyInt()))
3555                 .thenReturn(SHOW_IMMEDIATELY);
3556         mService.isSystemUid = false;
3557         mService.isSystemAppId = false;
3558         final NotificationRecord parent = generateNotificationRecord(
3559                 mTestNotificationChannel, 1, "group", true);
3560         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3561         final NotificationRecord child = generateNotificationRecord(
3562                 mTestNotificationChannel, 2, "group", false);
3563         final NotificationRecord child2 = generateNotificationRecord(
3564                 mTestNotificationChannel, 3, "group", false);
3565         mService.addNotification(parent);
3566         mService.addNotification(child);
3567         mService.addNotification(child2);
3568         mService.getBinderService().cancelNotificationWithTag(
3569                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3570                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3571         waitForIdle();
3572         StatusBarNotification[] notifs =
3573                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3574         assertEquals(3, notifs.length);
3575     }
3576 
3577     @Test
testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()3578     public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()
3579             throws Exception {
3580         mService.isSystemUid = false;
3581         mService.isSystemAppId = false;
3582         final NotificationRecord parent = generateNotificationRecord(
3583                 mTestNotificationChannel, 1, "group", true);
3584         final NotificationRecord child = generateNotificationRecord(
3585                 mTestNotificationChannel, 2, "group", false);
3586         final NotificationRecord child2 = generateNotificationRecord(
3587                 mTestNotificationChannel, 3, "group", false);
3588         child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3589         mService.addNotification(parent);
3590         mService.addNotification(child);
3591         mService.addNotification(child2);
3592         mService.getBinderService().cancelNotificationWithTag(
3593                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3594                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3595         waitForIdle();
3596         StatusBarNotification[] notifs =
3597                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3598         assertEquals(0, notifs.length);
3599     }
3600 
3601     @Test
testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()3602     public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()
3603             throws Exception {
3604         mService.isSystemUid = false;
3605         mService.isSystemAppId = false;
3606         final NotificationRecord parent = generateNotificationRecord(
3607                 mTestNotificationChannel, 1, "group", true);
3608         parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3609         final NotificationRecord child = generateNotificationRecord(
3610                 mTestNotificationChannel, 2, "group", false);
3611         final NotificationRecord child2 = generateNotificationRecord(
3612                 mTestNotificationChannel, 3, "group", false);
3613         mService.addNotification(parent);
3614         mService.addNotification(child);
3615         mService.addNotification(child2);
3616         mService.getBinderService().cancelNotificationWithTag(
3617                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
3618                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
3619         waitForIdle();
3620         StatusBarNotification[] notifs =
3621                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3622         assertEquals(0, notifs.length);
3623     }
3624 
3625     @Test
testCancelAllNotificationsFromApp_cannotCancelFgsChild()3626     public void testCancelAllNotificationsFromApp_cannotCancelFgsChild()
3627             throws Exception {
3628         when(mAmi.applyForegroundServiceNotification(
3629                 any(), anyString(), anyInt(), anyString(), anyInt()))
3630                 .thenReturn(SHOW_IMMEDIATELY);
3631         mService.isSystemUid = false;
3632         mService.isSystemAppId = false;
3633         final NotificationRecord parent = generateNotificationRecord(
3634                 mTestNotificationChannel, 1, "group", true);
3635         final NotificationRecord child = generateNotificationRecord(
3636                 mTestNotificationChannel, 2, "group", false);
3637         final NotificationRecord child2 = generateNotificationRecord(
3638                 mTestNotificationChannel, 3, "group", false);
3639         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3640         final NotificationRecord newGroup = generateNotificationRecord(
3641                 mTestNotificationChannel, 4, "group2", false);
3642         mService.addNotification(parent);
3643         mService.addNotification(child);
3644         mService.addNotification(child2);
3645         mService.addNotification(newGroup);
3646         mService.getBinderService().cancelAllNotifications(
3647                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3648         waitForIdle();
3649         StatusBarNotification[] notifs =
3650                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3651         assertEquals(1, notifs.length);
3652     }
3653 
3654     @Test
testCancelAllNotifications_fromApp_cannotCancelFgsParent()3655     public void testCancelAllNotifications_fromApp_cannotCancelFgsParent()
3656             throws Exception {
3657         when(mAmi.applyForegroundServiceNotification(
3658                 any(), anyString(), anyInt(), anyString(), anyInt()))
3659                 .thenReturn(SHOW_IMMEDIATELY);
3660         mService.isSystemUid = false;
3661         mService.isSystemAppId = false;
3662         final NotificationRecord parent = generateNotificationRecord(
3663                 mTestNotificationChannel, 1, "group", true);
3664         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3665         final NotificationRecord child = generateNotificationRecord(
3666                 mTestNotificationChannel, 2, "group", false);
3667         final NotificationRecord child2 = generateNotificationRecord(
3668                 mTestNotificationChannel, 3, "group", false);
3669         final NotificationRecord newGroup = generateNotificationRecord(
3670                 mTestNotificationChannel, 4, "group2", false);
3671         mService.addNotification(parent);
3672         mService.addNotification(child);
3673         mService.addNotification(child2);
3674         mService.addNotification(newGroup);
3675         mService.getBinderService().cancelAllNotifications(
3676                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3677         waitForIdle();
3678         StatusBarNotification[] notifs =
3679                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3680         assertEquals(1, notifs.length);
3681     }
3682 
3683     @Test
testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()3684     public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()
3685             throws Exception {
3686         mService.isSystemUid = false;
3687         mService.isSystemAppId = false;
3688         final NotificationRecord parent = generateNotificationRecord(
3689                 mTestNotificationChannel, 1, "group", true);
3690         final NotificationRecord child = generateNotificationRecord(
3691                 mTestNotificationChannel, 2, "group", false);
3692         final NotificationRecord child2 = generateNotificationRecord(
3693                 mTestNotificationChannel, 3, "group", false);
3694         child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3695         final NotificationRecord newGroup = generateNotificationRecord(
3696                 mTestNotificationChannel, 4, "group2", false);
3697         mService.addNotification(parent);
3698         mService.addNotification(child);
3699         mService.addNotification(child2);
3700         mService.addNotification(newGroup);
3701         mService.getBinderService().cancelAllNotifications(
3702                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3703         waitForIdle();
3704         StatusBarNotification[] notifs =
3705                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3706         assertEquals(0, notifs.length);
3707     }
3708 
3709     @Test
testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()3710     public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()
3711             throws Exception {
3712         mService.isSystemUid = false;
3713         mService.isSystemAppId = false;
3714         final NotificationRecord parent = generateNotificationRecord(
3715                 mTestNotificationChannel, 1, "group", true);
3716         parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
3717         final NotificationRecord child = generateNotificationRecord(
3718                 mTestNotificationChannel, 2, "group", false);
3719         final NotificationRecord child2 = generateNotificationRecord(
3720                 mTestNotificationChannel, 3, "group", false);
3721         final NotificationRecord newGroup = generateNotificationRecord(
3722                 mTestNotificationChannel, 4, "group2", false);
3723         mService.addNotification(parent);
3724         mService.addNotification(child);
3725         mService.addNotification(child2);
3726         mService.addNotification(newGroup);
3727         mService.getBinderService().cancelAllNotifications(
3728                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
3729         waitForIdle();
3730         StatusBarNotification[] notifs =
3731                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3732         assertEquals(0, notifs.length);
3733     }
3734 
3735     @Test
testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()3736     public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()
3737             throws Exception {
3738         final NotificationRecord parent = generateNotificationRecord(
3739                 mTestNotificationChannel, 1, "group", true);
3740         parent.getNotification().flags |= FLAG_ONGOING_EVENT;
3741         final NotificationRecord child = generateNotificationRecord(
3742                 mTestNotificationChannel, 2, "group", false);
3743         final NotificationRecord child2 = generateNotificationRecord(
3744                 mTestNotificationChannel, 3, "group", false);
3745         final NotificationRecord newGroup = generateNotificationRecord(
3746                 mTestNotificationChannel, 4, "group2", false);
3747         mService.addNotification(parent);
3748         mService.addNotification(child);
3749         mService.addNotification(child2);
3750         mService.addNotification(newGroup);
3751         mService.getBinderService().cancelNotificationsFromListener(null, null);
3752         waitForIdle();
3753         StatusBarNotification[] notifs =
3754                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3755         assertEquals(1, notifs.length);
3756     }
3757 
3758     @Test
testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()3759     public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()
3760             throws Exception {
3761         final NotificationRecord parent = generateNotificationRecord(
3762                 mTestNotificationChannel, 1, "group", true);
3763         final NotificationRecord child = generateNotificationRecord(
3764                 mTestNotificationChannel, 2, "group", false);
3765         final NotificationRecord child2 = generateNotificationRecord(
3766                 mTestNotificationChannel, 3, "group", false);
3767         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3768         final NotificationRecord newGroup = generateNotificationRecord(
3769                 mTestNotificationChannel, 4, "group2", false);
3770         mService.addNotification(parent);
3771         mService.addNotification(child);
3772         mService.addNotification(child2);
3773         mService.addNotification(newGroup);
3774         mService.getBinderService().cancelNotificationsFromListener(null, null);
3775         waitForIdle();
3776         StatusBarNotification[] notifs =
3777                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3778         assertEquals(1, notifs.length);
3779     }
3780 
3781     @Test
testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()3782     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()
3783             throws Exception {
3784         when(mAmi.applyForegroundServiceNotification(
3785                 any(), anyString(), anyInt(), anyString(), anyInt()))
3786                 .thenReturn(SHOW_IMMEDIATELY);
3787         final NotificationRecord parent = generateNotificationRecord(
3788                 mTestNotificationChannel, 1, "group", true);
3789         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3790         final NotificationRecord child = generateNotificationRecord(
3791                 mTestNotificationChannel, 2, "group", false);
3792         final NotificationRecord child2 = generateNotificationRecord(
3793                 mTestNotificationChannel, 3, "group", false);
3794         final NotificationRecord newGroup = generateNotificationRecord(
3795                 mTestNotificationChannel, 4, "group2", false);
3796         mService.addNotification(parent);
3797         mService.addNotification(child);
3798         mService.addNotification(child2);
3799         mService.addNotification(newGroup);
3800         mService.getBinderService().cancelNotificationsFromListener(null, null);
3801         waitForIdle();
3802         StatusBarNotification[] notifs =
3803                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3804         assertEquals(0, notifs.length);
3805     }
3806 
3807     @Test
testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()3808     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()
3809             throws Exception {
3810         when(mAmi.applyForegroundServiceNotification(
3811                 any(), anyString(), anyInt(), anyString(), anyInt()))
3812                 .thenReturn(SHOW_IMMEDIATELY);
3813         final NotificationRecord parent = generateNotificationRecord(
3814                 mTestNotificationChannel, 1, "group", true);
3815         final NotificationRecord child = generateNotificationRecord(
3816                 mTestNotificationChannel, 2, "group", false);
3817         final NotificationRecord child2 = generateNotificationRecord(
3818                 mTestNotificationChannel, 3, "group", false);
3819         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3820         final NotificationRecord newGroup = generateNotificationRecord(
3821                 mTestNotificationChannel, 4, "group2", false);
3822         mService.addNotification(parent);
3823         mService.addNotification(child);
3824         mService.addNotification(child2);
3825         mService.addNotification(newGroup);
3826         mService.getBinderService().cancelNotificationsFromListener(null, null);
3827         waitForIdle();
3828         StatusBarNotification[] notifs =
3829                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3830         assertEquals(0, notifs.length);
3831     }
3832 
3833     @Test
testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()3834     public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()
3835             throws Exception {
3836         final NotificationRecord parent = generateNotificationRecord(
3837                 mTestNotificationChannel, 1, "group", true);
3838         parent.getNotification().flags |= FLAG_NO_CLEAR;
3839         final NotificationRecord child = generateNotificationRecord(
3840                 mTestNotificationChannel, 2, "group", false);
3841         final NotificationRecord child2 = generateNotificationRecord(
3842                 mTestNotificationChannel, 3, "group", false);
3843         final NotificationRecord newGroup = generateNotificationRecord(
3844                 mTestNotificationChannel, 4, "group2", false);
3845         mService.addNotification(parent);
3846         mService.addNotification(child);
3847         mService.addNotification(child2);
3848         mService.addNotification(newGroup);
3849         mService.getBinderService().cancelNotificationsFromListener(null, null);
3850         waitForIdle();
3851         StatusBarNotification[] notifs =
3852                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3853         assertEquals(1, notifs.length);
3854     }
3855 
3856     @Test
testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()3857     public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()
3858             throws Exception {
3859         final NotificationRecord parent = generateNotificationRecord(
3860                 mTestNotificationChannel, 1, "group", true);
3861         final NotificationRecord child = generateNotificationRecord(
3862                 mTestNotificationChannel, 2, "group", false);
3863         final NotificationRecord child2 = generateNotificationRecord(
3864                 mTestNotificationChannel, 3, "group", false);
3865         child2.getNotification().flags |= FLAG_NO_CLEAR;
3866         final NotificationRecord newGroup = generateNotificationRecord(
3867                 mTestNotificationChannel, 4, "group2", false);
3868         mService.addNotification(parent);
3869         mService.addNotification(child);
3870         mService.addNotification(child2);
3871         mService.addNotification(newGroup);
3872         mService.getBinderService().cancelNotificationsFromListener(null, null);
3873         waitForIdle();
3874         StatusBarNotification[] notifs =
3875                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3876         assertEquals(1, notifs.length);
3877     }
3878 
3879     @Test
testCancelNotificationsFromListener_clearAll_Ongoing()3880     public void testCancelNotificationsFromListener_clearAll_Ongoing()
3881             throws Exception {
3882         final NotificationRecord child2 = generateNotificationRecord(
3883                 mTestNotificationChannel, 3, null, false);
3884         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3885         mService.addNotification(child2);
3886         String[] keys = {child2.getSbn().getKey()};
3887         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3888         waitForIdle();
3889         StatusBarNotification[] notifs =
3890                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3891         assertEquals(1, notifs.length);
3892     }
3893 
3894     @Test
testCancelNotificationsFromListener_clearAll_NoClear()3895     public void testCancelNotificationsFromListener_clearAll_NoClear()
3896             throws Exception {
3897         final NotificationRecord child2 = generateNotificationRecord(
3898                 mTestNotificationChannel, 3, null, false);
3899         child2.getNotification().flags |= FLAG_NO_CLEAR;
3900         mService.addNotification(child2);
3901         mService.getBinderService().cancelNotificationsFromListener(null, null);
3902         waitForIdle();
3903         StatusBarNotification[] notifs =
3904                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3905         assertEquals(1, notifs.length);
3906     }
3907 
3908     @Test
testCancelNotificationsFromListener_clearAll_Fgs()3909     public void testCancelNotificationsFromListener_clearAll_Fgs()
3910             throws Exception {
3911         when(mAmi.applyForegroundServiceNotification(
3912                 any(), anyString(), anyInt(), anyString(), anyInt()))
3913                 .thenReturn(SHOW_IMMEDIATELY);
3914         final NotificationRecord child2 = generateNotificationRecord(
3915                 mTestNotificationChannel, 3, null, false);
3916         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
3917         mService.addNotification(child2);
3918         mService.getBinderService().cancelNotificationsFromListener(null, null);
3919         waitForIdle();
3920         StatusBarNotification[] notifs =
3921                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
3922         assertEquals(0, notifs.length);
3923     }
3924 
3925     @Test
3926     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()3927     public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()
3928             throws Exception {
3929         final NotificationRecord notif = generateNotificationRecord(
3930                 mTestNotificationChannel, 1, null, false);
3931         notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
3932         mService.addNotification(notif);
3933         verify(mWorkerHandler, times(0))
3934                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3935         mService.getBinderService().cancelNotificationsFromListener(null, null);
3936         waitForIdle();
3937         // Notification not cancelled.
3938         StatusBarNotification[] notifs =
3939                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
3940         assertThat(notifs.length).isEqualTo(1);
3941 
3942         // Checks that a post update is sent.
3943         verify(mWorkerHandler, times(1))
3944                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
3945         ArgumentCaptor<NotificationRecord> captor =
3946                 ArgumentCaptor.forClass(NotificationRecord.class);
3947         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
3948                 anyBoolean());
3949         assertThat(captor.getValue().getNotification().flags
3950                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
3951                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
3952     }
3953 
3954     @Test
testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()3955     public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()
3956             throws Exception {
3957         final NotificationRecord parent = generateNotificationRecord(
3958                 mTestNotificationChannel, 1, "group", true);
3959         parent.getNotification().flags |= FLAG_ONGOING_EVENT;
3960         final NotificationRecord child = generateNotificationRecord(
3961                 mTestNotificationChannel, 2, "group", false);
3962         final NotificationRecord child2 = generateNotificationRecord(
3963                 mTestNotificationChannel, 3, "group", false);
3964         final NotificationRecord newGroup = generateNotificationRecord(
3965                 mTestNotificationChannel, 4, "group2", false);
3966         mService.addNotification(parent);
3967         mService.addNotification(child);
3968         mService.addNotification(child2);
3969         mService.addNotification(newGroup);
3970         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3971                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3972         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3973         waitForIdle();
3974         StatusBarNotification[] notifs =
3975                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
3976         assertEquals(1, notifs.length);
3977     }
3978 
3979     @Test
testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()3980     public void testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()
3981             throws Exception {
3982         final NotificationRecord parent = generateNotificationRecord(
3983                 mTestNotificationChannel, 1, "group", true);
3984         final NotificationRecord child = generateNotificationRecord(
3985                 mTestNotificationChannel, 2, "group", false);
3986         final NotificationRecord child2 = generateNotificationRecord(
3987                 mTestNotificationChannel, 3, "group", false);
3988         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
3989         final NotificationRecord newGroup = generateNotificationRecord(
3990                 mTestNotificationChannel, 4, "group2", false);
3991         mService.addNotification(parent);
3992         mService.addNotification(child);
3993         mService.addNotification(child2);
3994         mService.addNotification(newGroup);
3995         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
3996                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
3997         mService.getBinderService().cancelNotificationsFromListener(null, keys);
3998         waitForIdle();
3999         StatusBarNotification[] notifs =
4000                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4001         assertEquals(1, notifs.length);
4002     }
4003 
4004     @Test
testCancelNotificationsFromListener_byKey_GroupWithFgsParent()4005     public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent()
4006             throws Exception {
4007         when(mAmi.applyForegroundServiceNotification(
4008                 any(), anyString(), anyInt(), anyString(), anyInt()))
4009                 .thenReturn(SHOW_IMMEDIATELY);
4010         final NotificationRecord parent = generateNotificationRecord(
4011                 mTestNotificationChannel, 1, "group", true);
4012         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4013         final NotificationRecord child = generateNotificationRecord(
4014                 mTestNotificationChannel, 2, "group", false);
4015         final NotificationRecord child2 = generateNotificationRecord(
4016                 mTestNotificationChannel, 3, "group", false);
4017         final NotificationRecord newGroup = generateNotificationRecord(
4018                 mTestNotificationChannel, 4, "group2", false);
4019         mService.addNotification(parent);
4020         mService.addNotification(child);
4021         mService.addNotification(child2);
4022         mService.addNotification(newGroup);
4023         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4024                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4025         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4026         waitForIdle();
4027         StatusBarNotification[] notifs =
4028                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4029         assertEquals(0, notifs.length);
4030     }
4031 
4032     @Test
testCancelNotificationsFromListener_byKey_GroupWithFgsChild()4033     public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild()
4034             throws Exception {
4035         when(mAmi.applyForegroundServiceNotification(
4036                 any(), anyString(), anyInt(), anyString(), anyInt()))
4037                 .thenReturn(SHOW_IMMEDIATELY);
4038         final NotificationRecord parent = generateNotificationRecord(
4039                 mTestNotificationChannel, 1, "group", true);
4040         final NotificationRecord child = generateNotificationRecord(
4041                 mTestNotificationChannel, 2, "group", false);
4042         final NotificationRecord child2 = generateNotificationRecord(
4043                 mTestNotificationChannel, 3, "group", false);
4044         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4045         final NotificationRecord newGroup = generateNotificationRecord(
4046                 mTestNotificationChannel, 4, "group2", false);
4047         mService.addNotification(parent);
4048         mService.addNotification(child);
4049         mService.addNotification(child2);
4050         mService.addNotification(newGroup);
4051         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4052                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4053         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4054         waitForIdle();
4055         StatusBarNotification[] notifs =
4056                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4057         assertEquals(0, notifs.length);
4058     }
4059 
4060     @Test
testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()4061     public void testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()
4062             throws Exception {
4063         final NotificationRecord parent = generateNotificationRecord(
4064                 mTestNotificationChannel, 1, "group", true);
4065         parent.getNotification().flags |= FLAG_NO_CLEAR;
4066         final NotificationRecord child = generateNotificationRecord(
4067                 mTestNotificationChannel, 2, "group", false);
4068         final NotificationRecord child2 = generateNotificationRecord(
4069                 mTestNotificationChannel, 3, "group", false);
4070         final NotificationRecord newGroup = generateNotificationRecord(
4071                 mTestNotificationChannel, 4, "group2", false);
4072         mService.addNotification(parent);
4073         mService.addNotification(child);
4074         mService.addNotification(child2);
4075         mService.addNotification(newGroup);
4076         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4077                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4078         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4079         waitForIdle();
4080         StatusBarNotification[] notifs =
4081                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4082         assertEquals(0, notifs.length);
4083     }
4084 
4085     @Test
testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()4086     public void testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()
4087             throws Exception {
4088         final NotificationRecord parent = generateNotificationRecord(
4089                 mTestNotificationChannel, 1, "group", true);
4090         final NotificationRecord child = generateNotificationRecord(
4091                 mTestNotificationChannel, 2, "group", false);
4092         final NotificationRecord child2 = generateNotificationRecord(
4093                 mTestNotificationChannel, 3, "group", false);
4094         child2.getNotification().flags |= FLAG_NO_CLEAR;
4095         final NotificationRecord newGroup = generateNotificationRecord(
4096                 mTestNotificationChannel, 4, "group2", false);
4097         mService.addNotification(parent);
4098         mService.addNotification(child);
4099         mService.addNotification(child2);
4100         mService.addNotification(newGroup);
4101         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
4102                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
4103         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4104         waitForIdle();
4105         StatusBarNotification[] notifs =
4106                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4107         assertEquals(0, notifs.length);
4108     }
4109 
4110     @Test
testCancelNotificationsFromListener_byKey_Ongoing()4111     public void testCancelNotificationsFromListener_byKey_Ongoing()
4112             throws Exception {
4113         final NotificationRecord child2 = generateNotificationRecord(
4114                 mTestNotificationChannel, 3, null, false);
4115         child2.getNotification().flags |= FLAG_ONGOING_EVENT;
4116         mService.addNotification(child2);
4117         String[] keys = {child2.getSbn().getKey()};
4118         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4119         waitForIdle();
4120         StatusBarNotification[] notifs =
4121                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
4122         assertEquals(1, notifs.length);
4123     }
4124 
4125     @Test
testCancelNotificationsFromListener_byKey_NoClear()4126     public void testCancelNotificationsFromListener_byKey_NoClear()
4127             throws Exception {
4128         final NotificationRecord child2 = generateNotificationRecord(
4129                 mTestNotificationChannel, 3, null, false);
4130         child2.getNotification().flags |= FLAG_NO_CLEAR;
4131         mService.addNotification(child2);
4132         String[] keys = {child2.getSbn().getKey()};
4133         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4134         waitForIdle();
4135         StatusBarNotification[] notifs =
4136                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
4137         assertEquals(0, notifs.length);
4138     }
4139 
4140     @Test
testCancelNotificationsFromListener_byKey_Fgs()4141     public void testCancelNotificationsFromListener_byKey_Fgs()
4142             throws Exception {
4143         when(mAmi.applyForegroundServiceNotification(
4144                 any(), anyString(), anyInt(), anyString(), anyInt()))
4145                 .thenReturn(SHOW_IMMEDIATELY);
4146         final NotificationRecord child2 = generateNotificationRecord(
4147                 mTestNotificationChannel, 3, null, false);
4148         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4149         mService.addNotification(child2);
4150         String[] keys = {child2.getSbn().getKey()};
4151         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4152         waitForIdle();
4153         StatusBarNotification[] notifs =
4154                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
4155         assertEquals(0, notifs.length);
4156     }
4157 
4158     @Test
4159     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()4160     public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()
4161             throws Exception {
4162         final NotificationRecord notif = generateNotificationRecord(
4163                 mTestNotificationChannel, 3, null, false);
4164         notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
4165         mService.addNotification(notif);
4166         String[] keys = {notif.getSbn().getKey()};
4167         mService.getBinderService().cancelNotificationsFromListener(null, keys);
4168         waitForIdle();
4169         StatusBarNotification[] notifs =
4170                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
4171         assertEquals(1, notifs.length);
4172 
4173         // Checks that a post update is sent.
4174         verify(mWorkerHandler, times(1))
4175                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
4176         ArgumentCaptor<NotificationRecord> captor =
4177                 ArgumentCaptor.forClass(NotificationRecord.class);
4178         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
4179                 anyBoolean());
4180         assertThat(captor.getValue().getNotification().flags
4181                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
4182                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
4183     }
4184 
4185     @Test
testGroupInstanceIds()4186     public void testGroupInstanceIds() throws Exception {
4187         final NotificationRecord group1 = generateNotificationRecord(
4188                 mTestNotificationChannel, 1, "group1", true);
4189         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds",
4190                 group1.getSbn().getId(), group1.getSbn().getNotification(),
4191                 group1.getSbn().getUserId());
4192         waitForIdle();
4193 
4194         // same group, child, should be returned
4195         final NotificationRecord group1Child = generateNotificationRecord(
4196                 mTestNotificationChannel, 2, "group1", false);
4197         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds",
4198                 group1Child.getSbn().getId(),
4199                 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
4200         waitForIdle();
4201 
4202         assertEquals(2, mNotificationRecordLogger.numCalls());
4203         assertEquals(mNotificationRecordLogger.get(0).getInstanceId(),
4204                 mNotificationRecordLogger.get(1).groupInstanceId.getId());
4205     }
4206 
4207     @Test
testFindGroupNotificationsLocked()4208     public void testFindGroupNotificationsLocked() throws Exception {
4209         // make sure the same notification can be found in both lists and returned
4210         final NotificationRecord group1 = generateNotificationRecord(
4211                 mTestNotificationChannel, 1, "group1", true);
4212         mService.addEnqueuedNotification(group1);
4213         mService.addNotification(group1);
4214 
4215         // should not be returned
4216         final NotificationRecord group2 = generateNotificationRecord(
4217                 mTestNotificationChannel, 2, "group2", true);
4218         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
4219                 group2.getSbn().getId(), group2.getSbn().getNotification(),
4220                 group2.getSbn().getUserId());
4221         waitForIdle();
4222 
4223         // should not be returned
4224         final NotificationRecord nonGroup = generateNotificationRecord(
4225                 mTestNotificationChannel, 3, null, false);
4226         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
4227                 nonGroup.getSbn().getId(), nonGroup.getSbn().getNotification(),
4228                 nonGroup.getSbn().getUserId());
4229         waitForIdle();
4230 
4231         // same group, child, should be returned
4232         final NotificationRecord group1Child = generateNotificationRecord(
4233                 mTestNotificationChannel, 4, "group1", false);
4234         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked",
4235                 group1Child.getSbn().getId(),
4236                 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
4237         waitForIdle();
4238 
4239         List<NotificationRecord> inGroup1 =
4240                 mService.findGroupNotificationsLocked(mPkg, group1.getGroupKey(),
4241                         group1.getSbn().getUserId());
4242         assertEquals(3, inGroup1.size());
4243         for (NotificationRecord record : inGroup1) {
4244             assertTrue(record.getGroupKey().equals(group1.getGroupKey()));
4245             assertTrue(record.getSbn().getId() == 1 || record.getSbn().getId() == 4);
4246         }
4247     }
4248 
4249     @Test
testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing()4250     public void testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing() throws Exception {
4251         final NotificationRecord notif = generateNotificationRecord(
4252                 mTestNotificationChannel, 1, "group", true);
4253         notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
4254         mService.addNotification(notif);
4255         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0,
4256                 Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL);
4257         waitForIdle();
4258         StatusBarNotification[] notifs =
4259                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
4260         assertEquals(0, notifs.length);
4261     }
4262 
4263     @Test
testAppInitiatedCancelAllNotifications_CancelsOngoingFlag()4264     public void testAppInitiatedCancelAllNotifications_CancelsOngoingFlag() throws Exception {
4265         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
4266         sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
4267         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
4268                 "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag",
4269                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
4270         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
4271         waitForIdle();
4272         StatusBarNotification[] notifs =
4273                 mBinderService.getActiveNotifications(sbn.getPackageName());
4274         assertEquals(0, notifs.length);
4275     }
4276 
4277     @Test
testCancelAllNotificationsInt_CancelsOngoingFlag()4278     public void testCancelAllNotificationsInt_CancelsOngoingFlag() throws Exception {
4279         final NotificationRecord notif = generateNotificationRecord(
4280                 mTestNotificationChannel, 1, "group", true);
4281         notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
4282         mService.addNotification(notif);
4283         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
4284                 notif.getUserId(), REASON_CANCEL);
4285         waitForIdle();
4286         StatusBarNotification[] notifs =
4287                 mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
4288         assertEquals(0, notifs.length);
4289     }
4290 
4291     @Test
testUserInitiatedCancelAllWithGroup_OngoingFlag()4292     public void testUserInitiatedCancelAllWithGroup_OngoingFlag() throws Exception {
4293         final NotificationRecord parent = generateNotificationRecord(
4294                 mTestNotificationChannel, 1, "group", true);
4295         final NotificationRecord child = generateNotificationRecord(
4296                 mTestNotificationChannel, 2, "group", false);
4297         final NotificationRecord child2 = generateNotificationRecord(
4298                 mTestNotificationChannel, 3, "group", false);
4299         child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
4300         final NotificationRecord newGroup = generateNotificationRecord(
4301                 mTestNotificationChannel, 4, "group2", false);
4302         mService.addNotification(parent);
4303         mService.addNotification(child);
4304         mService.addNotification(child2);
4305         mService.addNotification(newGroup);
4306         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
4307                 parent.getUserId());
4308         waitForIdle();
4309         StatusBarNotification[] notifs =
4310                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4311         assertEquals(1, notifs.length);
4312     }
4313 
4314     @Test
testUserInitiatedCancelAllWithGroup_NoClearFlag()4315     public void testUserInitiatedCancelAllWithGroup_NoClearFlag() throws Exception {
4316         final NotificationRecord parent = generateNotificationRecord(
4317                 mTestNotificationChannel, 1, "group", true);
4318         final NotificationRecord child = generateNotificationRecord(
4319                 mTestNotificationChannel, 2, "group", false);
4320         final NotificationRecord child2 = generateNotificationRecord(
4321                 mTestNotificationChannel, 3, "group", false);
4322         child2.getNotification().flags |= Notification.FLAG_NO_CLEAR;
4323         final NotificationRecord newGroup = generateNotificationRecord(
4324                 mTestNotificationChannel, 4, "group2", false);
4325         mService.addNotification(parent);
4326         mService.addNotification(child);
4327         mService.addNotification(child2);
4328         mService.addNotification(newGroup);
4329         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
4330                 parent.getUserId());
4331         waitForIdle();
4332         StatusBarNotification[] notifs =
4333                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4334         assertEquals(1, notifs.length);
4335     }
4336 
4337     @Test
testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag()4338     public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception {
4339         when(mAmi.applyForegroundServiceNotification(
4340                 any(), anyString(), anyInt(), anyString(), anyInt()))
4341                 .thenReturn(SHOW_IMMEDIATELY);
4342         final NotificationRecord parent = generateNotificationRecord(
4343                 mTestNotificationChannel, 1, "group", true);
4344         final NotificationRecord child = generateNotificationRecord(
4345                 mTestNotificationChannel, 2, "group", false);
4346         final NotificationRecord child2 = generateNotificationRecord(
4347                 mTestNotificationChannel, 3, "group", false);
4348         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
4349         final NotificationRecord newGroup = generateNotificationRecord(
4350                 mTestNotificationChannel, 4, "group2", false);
4351         mService.addNotification(parent);
4352         mService.addNotification(child);
4353         mService.addNotification(child2);
4354         mService.addNotification(newGroup);
4355         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
4356                 parent.getUserId());
4357         waitForIdle();
4358         StatusBarNotification[] notifs =
4359                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
4360         assertEquals(0, notifs.length);
4361     }
4362 
4363     @Test
testDefaultChannelUpdatesApp_postMigrationToPermissions()4364     public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception {
4365         final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
4366                 PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
4367                 NotificationChannel.DEFAULT_CHANNEL_ID);
4368         defaultChannel.setImportance(IMPORTANCE_NONE);
4369 
4370         mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
4371 
4372         verify(mPermissionHelper).setNotificationPermission(
4373                 PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
4374     }
4375 
4376     @Test
testPostNotification_appPermissionFixed()4377     public void testPostNotification_appPermissionFixed() throws Exception {
4378         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
4379         when(mPermissionHelper.isPermissionFixed(mPkg, mUserId)).thenReturn(true);
4380 
4381         NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
4382         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
4383                 "testPostNotification_appPermissionFixed", 0,
4384                 temp.getNotification(), mUserId);
4385         waitForIdle();
4386         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
4387         StatusBarNotification[] notifs =
4388                 mBinderService.getActiveNotifications(mPkg);
4389         assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
4390     }
4391 
4392     @Test
testSummaryNotification_appPermissionFixed()4393     public void testSummaryNotification_appPermissionFixed() {
4394         NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
4395         mService.addNotification(temp);
4396 
4397         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
4398         when(mPermissionHelper.isPermissionFixed(mPkg, temp.getUserId())).thenReturn(true);
4399 
4400         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
4401             mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
4402 
4403         NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(),
4404             temp.getSbn().getPackageName(), temp.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr);
4405 
4406         assertThat(r.isImportanceFixed()).isTrue();
4407     }
4408 
4409     @Test
testTvExtenderChannelOverride_onTv()4410     public void testTvExtenderChannelOverride_onTv() throws Exception {
4411         mService.setIsTelevision(true);
4412         mService.setPreferencesHelper(mPreferencesHelper);
4413         when(mPreferencesHelper.getNotificationChannel(
4414                 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
4415                     new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
4416 
4417         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
4418         mBinderService.enqueueNotificationWithTag(
4419                 mPkg,
4420                 mPkg,
4421                 "testTvExtenderChannelOverride_onTv",
4422                 0,
4423                 generateNotificationRecord(null, tv).getNotification(),
4424                 mUserId);
4425         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
4426                 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean());
4427     }
4428 
4429     @Test
testTvExtenderChannelOverride_notOnTv()4430     public void testTvExtenderChannelOverride_notOnTv() throws Exception {
4431         mService.setIsTelevision(false);
4432         mService.setPreferencesHelper(mPreferencesHelper);
4433         when(mPreferencesHelper.getNotificationChannel(
4434                 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
4435                 mTestNotificationChannel);
4436 
4437         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
4438         mBinderService.enqueueNotificationWithTag(
4439                 mPkg,
4440                 mPkg,
4441                 "testTvExtenderChannelOverride_notOnTv",
4442                 0,
4443                 generateNotificationRecord(null, tv).getNotification(),
4444                 mUserId);
4445         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
4446                 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null),
4447                 anyBoolean(), anyBoolean());
4448     }
4449 
4450     @Test
onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()4451     public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()
4452             throws RemoteException {
4453         // Have preexisting posted notifications from revoked package and other packages.
4454         mService.addNotification(new NotificationRecord(mContext,
4455                 generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel));
4456         mService.addNotification(new NotificationRecord(mContext,
4457                 generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
4458         // Have preexisting enqueued notifications from revoked package and other packages.
4459         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4460                 generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel));
4461         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4462                 generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
4463         assertThat(mService.mNotificationList).hasSize(2);
4464         assertThat(mService.mEnqueuedNotifications).hasSize(2);
4465 
4466         when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001);
4467         when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
4468 
4469         mOnPermissionChangeListener.onOpChanged(
4470                 AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0);
4471         waitForIdle();
4472 
4473         assertThat(mService.mNotificationList).hasSize(1);
4474         assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other");
4475         assertThat(mService.mEnqueuedNotifications).hasSize(1);
4476         assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo(
4477                 "other");
4478     }
4479 
4480     @Test
onOpChanged_permissionStillGranted_notificationsAreNotAffected()4481     public void onOpChanged_permissionStillGranted_notificationsAreNotAffected()
4482             throws RemoteException {
4483         // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission
4484         // being now granted, AND having previously posted notifications from said package) should
4485         // never happen (if we trust the broadcasts are correct). So this test is for a what-if
4486         // scenario, to verify we still handle it reasonably.
4487 
4488         // Have preexisting posted notifications from specific package and other packages.
4489         mService.addNotification(new NotificationRecord(mContext,
4490                 generateSbn("granted", 1001, 1, 0), mTestNotificationChannel));
4491         mService.addNotification(new NotificationRecord(mContext,
4492                 generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
4493         // Have preexisting enqueued notifications from specific package and other packages.
4494         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4495                 generateSbn("granted", 1001, 3, 0), mTestNotificationChannel));
4496         mService.addEnqueuedNotification(new NotificationRecord(mContext,
4497                 generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
4498         assertThat(mService.mNotificationList).hasSize(2);
4499         assertThat(mService.mEnqueuedNotifications).hasSize(2);
4500 
4501         when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001);
4502         when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
4503 
4504         mOnPermissionChangeListener.onOpChanged(
4505                 AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0);
4506         waitForIdle();
4507 
4508         assertThat(mService.mNotificationList).hasSize(2);
4509         assertThat(mService.mEnqueuedNotifications).hasSize(2);
4510     }
4511 
4512     @Test
onOpChanged_notInitializedUser_ignored()4513     public void onOpChanged_notInitializedUser_ignored() throws RemoteException {
4514         when(mUmInternal.isUserInitialized(eq(0))).thenReturn(false);
4515 
4516         mOnPermissionChangeListener.onOpChanged(
4517                 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
4518         waitForIdle();
4519 
4520         // We early-exited and didn't even query PM for package details.
4521         verify(mPackageManagerInternal, never()).getPackageUid(any(), anyLong(), anyInt());
4522     }
4523 
4524     @Test
setNotificationsEnabledForPackage_disabling_clearsNotifications()4525     public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception {
4526         mService.addNotification(new NotificationRecord(mContext,
4527                 generateSbn("package", 1001, 1, 0), mTestNotificationChannel));
4528         assertThat(mService.mNotificationList).hasSize(1);
4529         when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001);
4530         when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn(
4531                 true);
4532 
4533         // Start with granted permission and simulate effect of revoking it.
4534         when(mPermissionHelper.hasPermission(1001)).thenReturn(true);
4535         doAnswer(invocation -> {
4536             when(mPermissionHelper.hasPermission(1001)).thenReturn(false);
4537             mOnPermissionChangeListener.onOpChanged(
4538                     AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
4539             return null;
4540         }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true);
4541 
4542         mBinderService.setNotificationsEnabledForPackage("package", 1001, false);
4543         waitForIdle();
4544 
4545         assertThat(mService.mNotificationList).hasSize(0);
4546 
4547         mTestableLooper.moveTimeForward(500);
4548         waitForIdle();
4549         verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null));
4550     }
4551 
4552     @Test
testUpdateAppNotifyCreatorBlock()4553     public void testUpdateAppNotifyCreatorBlock() throws Exception {
4554         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
4555 
4556         mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, false);
4557         Thread.sleep(500);
4558         waitForIdle();
4559 
4560         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4561         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4562 
4563         assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
4564                 captor.getValue().getAction());
4565         assertEquals(mPkg, captor.getValue().getPackage());
4566         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
4567     }
4568 
4569     @Test
testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting()4570     public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
4571         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
4572 
4573         mBinderService.setNotificationsEnabledForPackage(mPkg, 0, false);
4574         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
4575     }
4576 
4577     @Test
testUpdateAppNotifyCreatorUnblock()4578     public void testUpdateAppNotifyCreatorUnblock() throws Exception {
4579         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
4580 
4581         mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, true);
4582         Thread.sleep(500);
4583         waitForIdle();
4584 
4585         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4586         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4587 
4588         assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
4589                 captor.getValue().getAction());
4590         assertEquals(mPkg, captor.getValue().getPackage());
4591         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
4592     }
4593 
4594     @Test
testUpdateChannelNotifyCreatorBlock()4595     public void testUpdateChannelNotifyCreatorBlock() throws Exception {
4596         mService.setPreferencesHelper(mPreferencesHelper);
4597         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4598                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4599                 .thenReturn(mTestNotificationChannel);
4600 
4601         NotificationChannel updatedChannel =
4602                 new NotificationChannel(mTestNotificationChannel.getId(),
4603                         mTestNotificationChannel.getName(), IMPORTANCE_NONE);
4604 
4605         mBinderService.updateNotificationChannelForPackage(mPkg, 0, updatedChannel);
4606         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4607         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4608 
4609         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
4610                 captor.getValue().getAction());
4611         assertEquals(mPkg, captor.getValue().getPackage());
4612         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
4613                         NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
4614         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4615     }
4616 
4617     @Test
testUpdateChannelNotifyCreatorUnblock()4618     public void testUpdateChannelNotifyCreatorUnblock() throws Exception {
4619         NotificationChannel existingChannel =
4620                 new NotificationChannel(mTestNotificationChannel.getId(),
4621                         mTestNotificationChannel.getName(), IMPORTANCE_NONE);
4622         mService.setPreferencesHelper(mPreferencesHelper);
4623         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4624                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4625                 .thenReturn(existingChannel);
4626 
4627         mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel);
4628         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4629         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4630 
4631         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
4632                 captor.getValue().getAction());
4633         assertEquals(mPkg, captor.getValue().getPackage());
4634         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
4635                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
4636         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4637     }
4638 
4639     @Test
testUpdateChannelNoNotifyCreatorOtherChanges()4640     public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception {
4641         NotificationChannel existingChannel =
4642                 new NotificationChannel(mTestNotificationChannel.getId(),
4643                         mTestNotificationChannel.getName(), IMPORTANCE_MAX);
4644         mService.setPreferencesHelper(mPreferencesHelper);
4645         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4646                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4647                 .thenReturn(existingChannel);
4648 
4649         mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel);
4650         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
4651     }
4652 
4653     @Test
testUpdateGroupNotifyCreatorBlock()4654     public void testUpdateGroupNotifyCreatorBlock() throws Exception {
4655         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
4656         mService.setPreferencesHelper(mPreferencesHelper);
4657         when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()),
4658                 eq(mPkg), anyInt()))
4659                 .thenReturn(existing);
4660 
4661         NotificationChannelGroup updated = new NotificationChannelGroup("id", "name");
4662         updated.setBlocked(true);
4663 
4664         mBinderService.updateNotificationChannelGroupForPackage(mPkg, 0, updated);
4665         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4666         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4667 
4668         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
4669                 captor.getValue().getAction());
4670         assertEquals(mPkg, captor.getValue().getPackage());
4671         assertEquals(existing.getId(), captor.getValue().getStringExtra(
4672                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
4673         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4674     }
4675 
4676     @Test
testUpdateGroupNotifyCreatorUnblock()4677     public void testUpdateGroupNotifyCreatorUnblock() throws Exception {
4678         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
4679         existing.setBlocked(true);
4680         mService.setPreferencesHelper(mPreferencesHelper);
4681         when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()),
4682                 eq(mPkg), anyInt()))
4683                 .thenReturn(existing);
4684 
4685         mBinderService.updateNotificationChannelGroupForPackage(
4686                 mPkg, 0, new NotificationChannelGroup("id", "name"));
4687         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
4688         verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
4689 
4690         assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
4691                 captor.getValue().getAction());
4692         assertEquals(mPkg, captor.getValue().getPackage());
4693         assertEquals(existing.getId(), captor.getValue().getStringExtra(
4694                 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
4695         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
4696     }
4697 
4698     @Test
testUpdateGroupNoNotifyCreatorOtherChanges()4699     public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception {
4700         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
4701         mService.setPreferencesHelper(mPreferencesHelper);
4702         when(mPreferencesHelper.getNotificationChannelGroup(
4703                 eq(existing.getId()), eq(mPkg), anyInt()))
4704                 .thenReturn(existing);
4705 
4706         mBinderService.updateNotificationChannelGroupForPackage(
4707                 mPkg, 0, new NotificationChannelGroup("id", "new name"));
4708         verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
4709     }
4710 
4711     @Test
testCreateChannelNotifyListener()4712     public void testCreateChannelNotifyListener() throws Exception {
4713         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4714                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4715         mService.setPreferencesHelper(mPreferencesHelper);
4716         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4717                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4718                 .thenReturn(mTestNotificationChannel);
4719         NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW);
4720         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4721                 eq(channel2.getId()), anyBoolean()))
4722                 .thenReturn(channel2);
4723         when(mPreferencesHelper.createNotificationChannel(eq(mPkg), anyInt(),
4724                 eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()))
4725                 .thenReturn(true);
4726 
4727         reset(mListeners);
4728         mBinderService.createNotificationChannels(mPkg,
4729                 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2)));
4730         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4731                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4732                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4733         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4734                 eq(Process.myUserHandle()), eq(channel2),
4735                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4736     }
4737 
4738     @Test
testCreateChannelGroupNotifyListener()4739     public void testCreateChannelGroupNotifyListener() throws Exception {
4740         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4741                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4742         mService.setPreferencesHelper(mPreferencesHelper);
4743         NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
4744         NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
4745 
4746         reset(mListeners);
4747         mBinderService.createNotificationChannelGroups(mPkg,
4748                 new ParceledListSlice(Arrays.asList(group1, group2)));
4749         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4750                 eq(Process.myUserHandle()), eq(group1),
4751                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4752         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4753                 eq(Process.myUserHandle()), eq(group2),
4754                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
4755     }
4756 
4757     @Test
testUpdateChannelNotifyListener()4758     public void testUpdateChannelNotifyListener() throws Exception {
4759         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4760                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4761         mService.setPreferencesHelper(mPreferencesHelper);
4762         mTestNotificationChannel.setLightColor(Color.CYAN);
4763         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4764                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4765                 .thenReturn(mTestNotificationChannel);
4766 
4767         reset(mListeners);
4768         mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel);
4769         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4770                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4771                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
4772     }
4773 
4774     @Test
testDeleteChannelNotifyListener()4775     public void testDeleteChannelNotifyListener() throws Exception {
4776         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4777                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4778         mService.setPreferencesHelper(mPreferencesHelper);
4779         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4780                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4781                 .thenReturn(mTestNotificationChannel);
4782         when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
4783                 eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true);
4784         reset(mListeners);
4785         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
4786         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
4787                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
4788                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4789     }
4790 
4791     @Test
4792     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testAppsCannotDeleteBundleChannel()4793     public void testAppsCannotDeleteBundleChannel() throws Exception {
4794         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4795                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4796         mService.setPreferencesHelper(mPreferencesHelper);
4797         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4798                 eq(NEWS_ID), anyBoolean()))
4799                 .thenReturn(mTestNotificationChannel);
4800         when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
4801                 eq(NEWS_ID), anyInt(), anyBoolean())).thenReturn(true);
4802         reset(mListeners);
4803         mBinderService.deleteNotificationChannel(mPkg, NEWS_ID);
4804         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
4805                 eq(Process.myUserHandle()), any(),
4806                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4807     }
4808 
4809     @Test
testDeleteChannelOnlyDoExtraWorkIfExisted()4810     public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
4811         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4812                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4813         mService.setPreferencesHelper(mPreferencesHelper);
4814         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
4815                 eq(mTestNotificationChannel.getId()), anyBoolean()))
4816                 .thenReturn(null);
4817         reset(mListeners);
4818         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
4819         verifyNoMoreInteractions(mListeners);
4820         verifyNoMoreInteractions(mHistoryManager);
4821     }
4822 
4823     @Test
testDeleteChannelGroupNotifyListener()4824     public void testDeleteChannelGroupNotifyListener() throws Exception {
4825         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4826                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4827         NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
4828         mService.setPreferencesHelper(mPreferencesHelper);
4829         when(mPreferencesHelper.getNotificationChannelGroupWithChannels(
4830                 eq(mPkg), anyInt(), eq(ncg.getId()), anyBoolean()))
4831                 .thenReturn(ncg);
4832         reset(mListeners);
4833         mBinderService.deleteNotificationChannelGroup(mPkg, ncg.getId());
4834         verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg),
4835                 eq(Process.myUserHandle()), eq(ncg),
4836                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
4837     }
4838 
4839     @Test
testDeleteChannelGroupChecksForFgses()4840     public void testDeleteChannelGroupChecksForFgses() throws Exception {
4841         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4842                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4843         CountDownLatch latch = new CountDownLatch(2);
4844         mService.createNotificationChannelGroup(
4845                 mPkg, mUid, new NotificationChannelGroup("group", "group"), true, false);
4846         new Thread(() -> {
4847             NotificationChannel notificationChannel = new NotificationChannel("id", "id",
4848                     NotificationManager.IMPORTANCE_HIGH);
4849             notificationChannel.setGroup("group");
4850             ParceledListSlice<NotificationChannel> pls =
4851                     new ParceledListSlice(ImmutableList.of(notificationChannel));
4852             try {
4853                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
4854             } catch (RemoteException e) {
4855                 throw new RuntimeException(e);
4856             }
4857             latch.countDown();
4858         }).start();
4859         new Thread(() -> {
4860             try {
4861                 synchronized (this) {
4862                     wait(5000);
4863                 }
4864                 mService.createNotificationChannelGroup(mPkg, mUid,
4865                         new NotificationChannelGroup("new", "new group"), true, false);
4866                 NotificationChannel notificationChannel =
4867                         new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
4868                 notificationChannel.setGroup("new");
4869                 ParceledListSlice<NotificationChannel> pls =
4870                         new ParceledListSlice(ImmutableList.of(notificationChannel));
4871                 try {
4872                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
4873                 mBinderService.deleteNotificationChannelGroup(mPkg, "group");
4874                 } catch (RemoteException e) {
4875                     throw new RuntimeException(e);
4876                 }
4877             } catch (Exception e) {
4878                 e.printStackTrace();
4879             }
4880             latch.countDown();
4881         }).start();
4882 
4883         latch.await();
4884         verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString());
4885     }
4886 
setUpChannelsForConversationChannelTest()4887     private void setUpChannelsForConversationChannelTest() throws RemoteException {
4888         when(mPreferencesHelper.getNotificationChannel(
4889                 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(false)))
4890                 .thenReturn(mParentChannel);
4891         when(mPreferencesHelper.getConversationNotificationChannel(
4892                 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(CONVERSATION_ID), eq(false), eq(false)))
4893                 .thenReturn(mConversationChannel);
4894         when(mPackageManager.getPackageUid(mPkg, 0, mUserId)).thenReturn(mUid);
4895     }
4896 
4897     @Test
4898     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_cdm_success()4899     public void createConversationChannelForPkgFromPrivilegedListener_cdm_success() throws Exception {
4900         // Set up cdm
4901         mService.setPreferencesHelper(mPreferencesHelper);
4902         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4903                 .thenReturn(singletonList(mock(AssociationInfo.class)));
4904 
4905         // Set up parent channel
4906         setUpChannelsForConversationChannelTest();
4907         final NotificationChannel parentChannelCopy = mParentChannel.copy();
4908 
4909         NotificationChannel createdChannel =
4910                 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4911                     null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID);
4912 
4913         // Verify that a channel is created and a copied channel is returned.
4914         verify(mPreferencesHelper, times(1)).createNotificationChannel(
4915                 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(),
4916                 eq(mUid), anyBoolean());
4917         assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel);
4918         assertThat(createdChannel).isEqualTo(mConversationChannel);
4919 
4920         // Verify that the channel creation is not directly use the parent channel.
4921         verify(mPreferencesHelper, never()).createNotificationChannel(
4922                 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(),
4923                 anyInt(), anyBoolean());
4924 
4925         // Verify that the content of parent channel is not changed.
4926         assertThat(parentChannelCopy).isEqualTo(mParentChannel);
4927     }
4928 
4929     @Test
4930     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess()4931     public void createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess() throws Exception {
4932         // Set up cdm without access
4933         mService.setPreferencesHelper(mPreferencesHelper);
4934         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4935                 .thenReturn(emptyList());
4936 
4937         // Set up parent channel
4938         setUpChannelsForConversationChannelTest();
4939 
4940         try {
4941             mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4942                 null, mPkg, mUser, "parentId", "conversationId");
4943             fail("listeners that don't have a companion device shouldn't be able to call this");
4944         } catch (SecurityException e) {
4945             // pass
4946         }
4947 
4948         verify(mPreferencesHelper, never()).createNotificationChannel(
4949                 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(),
4950                 anyInt(), anyBoolean());
4951     }
4952 
4953     @Test
4954     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_assistant_success()4955     public void createConversationChannelForPkgFromPrivilegedListener_assistant_success() throws Exception {
4956         // Set up assistant
4957         mService.setPreferencesHelper(mPreferencesHelper);
4958         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4959                 .thenReturn(emptyList());
4960         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
4961 
4962         // Set up parent channel
4963         setUpChannelsForConversationChannelTest();
4964         final NotificationChannel parentChannelCopy = mParentChannel.copy();
4965 
4966         NotificationChannel createdChannel =
4967                 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
4968                     null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID);
4969 
4970         // Verify that a channel is created and a copied channel is returned.
4971         verify(mPreferencesHelper, times(1)).createNotificationChannel(
4972                 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(),
4973                 eq(mUid), anyBoolean());
4974         assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel);
4975         assertThat(createdChannel).isEqualTo(mConversationChannel);
4976 
4977         // Verify that the channel creation is not directly use the parent channel.
4978         verify(mPreferencesHelper, never()).createNotificationChannel(
4979                 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(),
4980                 anyInt(), anyBoolean());
4981 
4982         // Verify that the content of parent channel is not changed.
4983         assertThat(parentChannelCopy).isEqualTo(mParentChannel);
4984     }
4985 
4986     @Test
4987     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess()4988     public void createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess() throws Exception {
4989         // Set up assistant without access
4990         mService.setPreferencesHelper(mPreferencesHelper);
4991         when(mCompanionMgr.getAssociations(mPkg, mUserId))
4992                 .thenReturn(emptyList());
4993         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
4994 
4995         // Set up parent channel
4996         setUpChannelsForConversationChannelTest();
4997 
4998         try {
4999             mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
5000                 null, mPkg, mUser, "parentId", "conversationId");
5001             fail("listeners that don't have a companion device shouldn't be able to call this");
5002         } catch (SecurityException e) {
5003             // pass
5004         }
5005 
5006         verify(mPreferencesHelper, never()).createNotificationChannel(
5007                 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(),
5008                 anyInt(), anyBoolean());
5009     }
5010 
5011     @Test
5012     @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT)
createConversationChannelForPkgFromPrivilegedListener_badUser()5013     public void createConversationChannelForPkgFromPrivilegedListener_badUser() throws Exception {
5014         // Set up bad user
5015         mService.setPreferencesHelper(mPreferencesHelper);
5016         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5017                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5018         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5019         mListener.component = new ComponentName(mPkg, mPkg);
5020         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5021         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5022 
5023         // Set up parent channel
5024         setUpChannelsForConversationChannelTest();
5025 
5026         try {
5027             mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener(
5028                 null, mPkg, mUser, "parentId", "conversationId");
5029             fail("listener getting channels from a user they cannot see");
5030         } catch (SecurityException e) {
5031             // pass
5032         }
5033 
5034         verify(mPreferencesHelper, never()).createNotificationChannel(
5035                 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(),
5036                 anyInt(), anyBoolean());
5037     }
5038 
5039     @Test
updateNotificationChannelFromPrivilegedListener_cdm_success()5040     public void updateNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
5041 
5042         mService.setPreferencesHelper(mPreferencesHelper);
5043         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5044                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5045         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5046                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5047                 .thenReturn(mTestNotificationChannel);
5048 
5049         mBinderService.updateNotificationChannelFromPrivilegedListener(
5050                 null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5051 
5052         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5053                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5054 
5055         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5056                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5057                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5058     }
5059 
5060     @Test
updateNotificationChannelFromPrivilegedListener_cdm_noAccess()5061     public void updateNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
5062         mService.setPreferencesHelper(mPreferencesHelper);
5063         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5064                 .thenReturn(emptyList());
5065 
5066         try {
5067             mBinderService.updateNotificationChannelFromPrivilegedListener(
5068                     null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5069             fail("listeners that don't have a companion device shouldn't be able to call this");
5070         } catch (SecurityException e) {
5071             // pass
5072         }
5073 
5074         verify(mPreferencesHelper, never()).updateNotificationChannel(
5075                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5076 
5077         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5078                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5079                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5080     }
5081 
5082     @Test
updateNotificationChannelFromPrivilegedListener_assistant_success()5083     public void updateNotificationChannelFromPrivilegedListener_assistant_success() throws Exception {
5084         mService.setPreferencesHelper(mPreferencesHelper);
5085         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5086                 .thenReturn(emptyList());
5087         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
5088         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5089                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5090                 .thenReturn(mTestNotificationChannel);
5091 
5092         mBinderService.updateNotificationChannelFromPrivilegedListener(
5093                 null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5094 
5095         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5096                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5097 
5098         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5099                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5100                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5101     }
5102 
5103     @Test
updateNotificationChannelFromPrivilegedListener_assistant_noAccess()5104     public void updateNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception {
5105         mService.setPreferencesHelper(mPreferencesHelper);
5106         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5107                 .thenReturn(emptyList());
5108         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
5109 
5110         try {
5111             mBinderService.updateNotificationChannelFromPrivilegedListener(
5112                     null, mPkg, Process.myUserHandle(), mTestNotificationChannel);
5113             fail("listeners that don't have a companion device shouldn't be able to call this");
5114         } catch (SecurityException e) {
5115             // pass
5116         }
5117 
5118         verify(mPreferencesHelper, never()).updateNotificationChannel(
5119                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5120 
5121         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5122                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5123                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5124     }
5125 
5126     @Test
updateNotificationChannelFromPrivilegedListener_badUser()5127     public void updateNotificationChannelFromPrivilegedListener_badUser() throws Exception {
5128         mService.setPreferencesHelper(mPreferencesHelper);
5129         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5130                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5131         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5132         mListener.component = new ComponentName(mPkg, mPkg);
5133         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5134         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5135 
5136         try {
5137             mBinderService.updateNotificationChannelFromPrivilegedListener(
5138                     null, mPkg, UserHandle.ALL, mTestNotificationChannel);
5139             fail("incorrectly allowed a change to a user listener cannot see");
5140         } catch (SecurityException e) {
5141             // pass
5142         }
5143 
5144         verify(mPreferencesHelper, never()).updateNotificationChannel(
5145                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5146 
5147         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5148                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5149                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5150     }
5151 
5152     @Test
updateNotificationChannelFromPrivilegedListener_noSoundUriPermission()5153     public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
5154             throws Exception {
5155         mService.setPreferencesHelper(mPreferencesHelper);
5156         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5157                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5158         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5159                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5160                 .thenReturn(mTestNotificationChannel);
5161 
5162         final Uri soundUri = Uri.parse("content://media/test/sound/uri");
5163         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
5164                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
5165         updatedNotificationChannel.setSound(soundUri,
5166                 updatedNotificationChannel.getAudioAttributes());
5167 
5168         doThrow(new SecurityException("no access")).when(mUgmInternal)
5169                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
5170                 anyInt(), eq(Process.myUserHandle().getIdentifier()));
5171 
5172         assertThrows(SecurityException.class,
5173                 () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, mPkg,
5174                 Process.myUserHandle(), updatedNotificationChannel));
5175 
5176         verify(mPreferencesHelper, never()).updateNotificationChannel(
5177                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5178 
5179         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5180                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5181                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5182     }
5183 
5184     @Test
updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()5185     public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
5186             throws Exception {
5187         mService.setPreferencesHelper(mPreferencesHelper);
5188         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5189                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5190         when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
5191                 eq(mTestNotificationChannel.getId()), anyBoolean()))
5192                 .thenReturn(mTestNotificationChannel);
5193 
5194         final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
5195         final NotificationChannel updatedNotificationChannel = new NotificationChannel(
5196                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
5197         updatedNotificationChannel.setSound(soundUri,
5198                 updatedNotificationChannel.getAudioAttributes());
5199 
5200         doThrow(new SecurityException("no access")).when(mUgmInternal)
5201                 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
5202                 anyInt(), eq(Process.myUserHandle().getIdentifier()));
5203 
5204         mBinderService.updateNotificationChannelFromPrivilegedListener(
5205                 null, mPkg, Process.myUserHandle(), updatedNotificationChannel);
5206 
5207         verify(mPreferencesHelper, times(1)).updateNotificationChannel(
5208                 anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
5209 
5210         verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
5211                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
5212                 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
5213     }
5214 
5215     @Test
testGetNotificationChannelFromPrivilegedListener_cdm_success()5216     public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
5217         mService.setPreferencesHelper(mPreferencesHelper);
5218         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5219                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5220 
5221         mBinderService.getNotificationChannelsFromPrivilegedListener(
5222                 null, mPkg, Process.myUserHandle());
5223 
5224         verify(mPreferencesHelper, times(1)).getNotificationChannels(
5225                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5226     }
5227 
5228     @Test
testGetNotificationChannelFromPrivilegedListener_cdm_noAccess()5229     public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
5230         mService.setPreferencesHelper(mPreferencesHelper);
5231         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5232                 .thenReturn(emptyList());
5233 
5234         try {
5235             mBinderService.getNotificationChannelsFromPrivilegedListener(
5236                     null, mPkg, Process.myUserHandle());
5237             fail("listeners that don't have a companion device shouldn't be able to call this");
5238         } catch (SecurityException e) {
5239             // pass
5240         }
5241 
5242         verify(mPreferencesHelper, never()).getNotificationChannels(
5243                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5244     }
5245 
5246     @Test
testGetNotificationChannelFromPrivilegedListener_assistant_success()5247     public void testGetNotificationChannelFromPrivilegedListener_assistant_success()
5248             throws Exception {
5249         mService.setPreferencesHelper(mPreferencesHelper);
5250         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5251                 .thenReturn(emptyList());
5252         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
5253 
5254         mBinderService.getNotificationChannelsFromPrivilegedListener(
5255                 null, mPkg, Process.myUserHandle());
5256 
5257         verify(mPreferencesHelper, times(1)).getNotificationChannels(
5258                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5259     }
5260 
5261     @Test
testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()5262     public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()
5263             throws Exception {
5264         mService.setPreferencesHelper(mPreferencesHelper);
5265         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5266                 .thenReturn(emptyList());
5267         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
5268 
5269         try {
5270             mBinderService.getNotificationChannelsFromPrivilegedListener(
5271                     null, mPkg, Process.myUserHandle());
5272             fail("listeners that don't have a companion device shouldn't be able to call this");
5273         } catch (SecurityException e) {
5274             // pass
5275         }
5276 
5277         verify(mPreferencesHelper, never()).getNotificationChannels(
5278                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5279     }
5280 
5281     @Test
testGetNotificationChannelFromPrivilegedListener_badUser()5282     public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception {
5283         mService.setPreferencesHelper(mPreferencesHelper);
5284         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5285                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5286         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5287         mListener.component = new ComponentName(mPkg, mPkg);
5288         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5289         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5290 
5291         try {
5292             mBinderService.getNotificationChannelsFromPrivilegedListener(
5293                     null, mPkg, Process.myUserHandle());
5294             fail("listener getting channels from a user they cannot see");
5295         } catch (SecurityException e) {
5296             // pass
5297         }
5298 
5299         verify(mPreferencesHelper, never()).getNotificationChannels(
5300                 anyString(), anyInt(), anyBoolean(), anyBoolean());
5301     }
5302 
5303     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_success()5304     public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
5305         mService.setPreferencesHelper(mPreferencesHelper);
5306         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5307                 .thenReturn(singletonList(mock(AssociationInfo.class)));
5308 
5309         mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
5310                 null, mPkg, Process.myUserHandle());
5311 
5312         verify(mPreferencesHelper, times(1)).getNotificationChannelGroupsWithoutChannels(
5313                 anyString(), anyInt());
5314     }
5315 
5316     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_noAccess()5317     public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
5318         mService.setPreferencesHelper(mPreferencesHelper);
5319         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5320                 .thenReturn(emptyList());
5321 
5322         try {
5323             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
5324                     null, mPkg, Process.myUserHandle());
5325             fail("listeners that don't have a companion device shouldn't be able to call this");
5326         } catch (SecurityException e) {
5327             // pass
5328         }
5329 
5330         verify(mPreferencesHelper, never()).getNotificationChannelGroupsWithoutChannels(anyString(),
5331                 anyInt());
5332     }
5333 
5334     @Test
testGetNotificationChannelGroupsFromPrivilegedListener_badUser()5335     public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
5336         mService.setPreferencesHelper(mPreferencesHelper);
5337         when(mCompanionMgr.getAssociations(mPkg, mUserId))
5338                 .thenReturn(emptyList());
5339         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5340         mListener.component = new ComponentName(mPkg, mPkg);
5341         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5342         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5343         try {
5344             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
5345                     null, mPkg, Process.myUserHandle());
5346             fail("listeners that don't have a companion device shouldn't be able to call this");
5347         } catch (SecurityException e) {
5348             // pass
5349         }
5350 
5351         verify(mPreferencesHelper, never()).getNotificationChannelGroupsWithoutChannels(anyString(),
5352                 anyInt());
5353     }
5354 
5355     @Test
testGetPackagesWithChannels_blocked()5356     public void testGetPackagesWithChannels_blocked() throws Exception {
5357         // While we mostly rely on the PreferencesHelper implementation of channels, we filter in
5358         // NMS so that we do not return blocked packages.
5359         // Three packages; all under user 1.
5360         // pkg2 is blocked, but pkg1 and pkg3 are not.
5361         String pkg1 = "com.package.one", pkg2 = "com.package.two", pkg3 = "com.package.three";
5362         int uid1 = UserHandle.getUid(1, 111);
5363         int uid2 = UserHandle.getUid(1, 222);
5364         int uid3 = UserHandle.getUid(1, 333);
5365 
5366         when(mPackageManager.getPackageUid(eq(pkg1), anyLong(), anyInt())).thenReturn(uid1);
5367         when(mPackageManager.getPackageUid(eq(pkg2), anyLong(), anyInt())).thenReturn(uid2);
5368         when(mPackageManager.getPackageUid(eq(pkg3), anyLong(), anyInt())).thenReturn(uid3);
5369         when(mPermissionHelper.hasPermission(uid1)).thenReturn(true);
5370         when(mPermissionHelper.hasPermission(uid2)).thenReturn(false);
5371         when(mPermissionHelper.hasPermission(uid3)).thenReturn(true);
5372 
5373         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
5374                 NotificationManager.IMPORTANCE_DEFAULT);
5375         NotificationChannel channel2 = new NotificationChannel("id3", "name3",
5376                 NotificationManager.IMPORTANCE_DEFAULT);
5377         NotificationChannel channel3 = new NotificationChannel("id4", "name3",
5378                 NotificationManager.IMPORTANCE_DEFAULT);
5379         mService.mPreferencesHelper.createNotificationChannel(pkg1, uid1, channel1, true, false,
5380                 uid1, false);
5381         mService.mPreferencesHelper.createNotificationChannel(pkg2, uid2, channel2, true, false,
5382                 uid2, false);
5383         mService.mPreferencesHelper.createNotificationChannel(pkg3, uid3, channel3, true, false,
5384                 uid3, false);
5385 
5386         // Output should contain only the package with notification permissions (1, 3).
5387         enableInteractAcrossUsers();
5388         assertThat(mBinderService.getPackagesWithAnyChannels(1)).containsExactly(pkg1, pkg3);
5389     }
5390 
5391     @Test
testHasCompanionDevice_failure()5392     public void testHasCompanionDevice_failure() throws Exception {
5393         when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
5394                 new IllegalArgumentException());
5395         mService.hasCompanionDevice(mListener);
5396     }
5397 
5398     @Test
testHasCompanionDevice_noService()5399     public void testHasCompanionDevice_noService() {
5400         NotificationManagerService noManService =
5401                 new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
5402                 mNotificationInstanceIdSequence);
5403 
5404         assertFalse(noManService.hasCompanionDevice(mListener));
5405     }
5406 
5407     @Test
testCrossUserSnooze()5408     public void testCrossUserSnooze() {
5409         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
5410         mService.addNotification(r);
5411         NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
5412         mService.addNotification(r2);
5413 
5414         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5415         mListener.component = new ComponentName(mPkg, mPkg);
5416         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
5417         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5418 
5419         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5420                 r.getKey(), 1000, null);
5421 
5422         verify(mWorkerHandler, never()).post(
5423                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5424     }
5425 
5426     @Test
testSameUserSnooze()5427     public void testSameUserSnooze() {
5428         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
5429         mService.addNotification(r);
5430         NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
5431         mService.addNotification(r2);
5432 
5433         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5434         mListener.component = new ComponentName(mPkg, mPkg);
5435         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5436         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5437 
5438         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5439                 r2.getKey(), 1000, null);
5440 
5441         verify(mWorkerHandler).post(
5442                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5443     }
5444 
5445     @Test
snoozeNotificationInt_rapidSnooze_new()5446     public void snoozeNotificationInt_rapidSnooze_new() {
5447         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
5448                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5449 
5450         // Create recent notification.
5451         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5452                 System.currentTimeMillis());
5453         mService.addNotification(nr1);
5454 
5455         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5456         mListener.component = new ComponentName(mPkg, mPkg);
5457         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5458         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5459 
5460         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5461                 nr1.getKey(), 1000, null);
5462 
5463         verify(mWorkerHandler).post(
5464                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5465         // Ensure cancel event is logged.
5466         verify(mAppOpsManager).noteOpNoThrow(
5467                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null,
5468                 null);
5469     }
5470 
5471     @Test
snoozeNotificationInt_rapidSnooze_old()5472     public void snoozeNotificationInt_rapidSnooze_old() {
5473         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
5474                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5475 
5476         // Create old notification.
5477         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5478                 System.currentTimeMillis() - 60000);
5479         mService.addNotification(nr1);
5480 
5481         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5482         mListener.component = new ComponentName(mPkg, mPkg);
5483         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5484         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5485 
5486         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5487                 nr1.getKey(), 1000, null);
5488 
5489         verify(mWorkerHandler).post(
5490                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5491         // Ensure cancel event is not logged.
5492         verify(mAppOpsManager, never()).noteOpNoThrow(
5493                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
5494                 any(), any());
5495     }
5496 
5497     @Test
snoozeNotificationInt_rapidSnooze_new_flagDisabled()5498     public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() {
5499         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
5500                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5501 
5502         // Create recent notification.
5503         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5504                 System.currentTimeMillis());
5505         mService.addNotification(nr1);
5506 
5507         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5508         mListener.component = new ComponentName(mPkg, mPkg);
5509         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5510         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5511 
5512         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5513                 nr1.getKey(), 1000, null);
5514 
5515         verify(mWorkerHandler).post(
5516                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5517         // Ensure cancel event is not logged.
5518         verify(mAppOpsManager, never()).noteOpNoThrow(
5519                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
5520                 any(), any());
5521     }
5522 
5523     @Test
snoozeNotificationInt_rapidSnooze_old_flagDisabled()5524     public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() {
5525         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
5526                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
5527 
5528         // Create old notification.
5529         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
5530                 System.currentTimeMillis() - 60000);
5531         mService.addNotification(nr1);
5532 
5533         mListener = mock(ManagedServices.ManagedServiceInfo.class);
5534         mListener.component = new ComponentName(mPkg, mPkg);
5535         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
5536         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
5537 
5538         mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
5539                 nr1.getKey(), 1000, null);
5540 
5541         verify(mWorkerHandler).post(
5542                 any(NotificationManagerService.SnoozeNotificationRunnable.class));
5543         // Ensure cancel event is not logged.
5544         verify(mAppOpsManager, never()).noteOpNoThrow(
5545                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
5546                 any(), any());
5547     }
5548 
5549     @Test
testSnoozeRunnable_tooManySnoozed_singleNotification()5550     public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
5551         final NotificationRecord notification = generateNotificationRecord(
5552                 mTestNotificationChannel, 1, null, true);
5553         mService.addNotification(notification);
5554 
5555         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5556         when(mSnoozeHelper.canSnooze(1)).thenReturn(false);
5557 
5558         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5559                 mService.new SnoozeNotificationRunnable(
5560                         notification.getKey(), 100, null);
5561         snoozeNotificationRunnable.run();
5562 
5563         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
5564         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
5565     }
5566 
5567     @Test
testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification()5568     public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() {
5569         final NotificationRecord notification = generateNotificationRecord(
5570                 mTestNotificationChannel, 1, "group", true);
5571         final NotificationRecord notificationChild = generateNotificationRecord(
5572                 mTestNotificationChannel, 1, "group", false);
5573         mService.addNotification(notification);
5574         mService.addNotification(notificationChild);
5575 
5576         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5577         when(mSnoozeHelper.canSnooze(2)).thenReturn(false);
5578 
5579         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5580                 mService.new SnoozeNotificationRunnable(
5581                         notificationChild.getKey(), 100, null);
5582         snoozeNotificationRunnable.run();
5583 
5584         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
5585         assertThat(mService.getNotificationRecordCount()).isEqualTo(2);
5586     }
5587 
5588     @Test
testSnoozeRunnable_tooManySnoozed_summaryNotification()5589     public void testSnoozeRunnable_tooManySnoozed_summaryNotification() {
5590         final NotificationRecord notification = generateNotificationRecord(
5591                 mTestNotificationChannel, 1, "group", true);
5592         final NotificationRecord notificationChild = generateNotificationRecord(
5593                 mTestNotificationChannel, 12, "group", false);
5594         final NotificationRecord notificationChild2 = generateNotificationRecord(
5595                 mTestNotificationChannel, 13, "group", false);
5596         mService.addNotification(notification);
5597         mService.addNotification(notificationChild);
5598         mService.addNotification(notificationChild2);
5599 
5600         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5601         when(mSnoozeHelper.canSnooze(3)).thenReturn(false);
5602 
5603         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5604                 mService.new SnoozeNotificationRunnable(
5605                         notification.getKey(), 100, null);
5606         snoozeNotificationRunnable.run();
5607 
5608         verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
5609         assertThat(mService.getNotificationRecordCount()).isEqualTo(3);
5610     }
5611 
5612     @Test
testSnoozeRunnable_reSnoozeASingleSnoozedNotification()5613     public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() {
5614         final NotificationRecord notification = generateNotificationRecord(
5615                 mTestNotificationChannel, 1, null, true);
5616         mService.addNotification(notification);
5617         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
5618         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5619 
5620         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5621                 mService.new SnoozeNotificationRunnable(
5622                 notification.getKey(), 100, null);
5623         snoozeNotificationRunnable.run();
5624         snoozeNotificationRunnable.run();
5625 
5626         // snooze twice
5627         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
5628     }
5629 
5630     @Test
testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey()5631     public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() {
5632         final NotificationRecord notification = generateNotificationRecord(
5633                 mTestNotificationChannel, 1, "group", true);
5634         mService.addNotification(notification);
5635         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
5636         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5637 
5638         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5639                 mService.new SnoozeNotificationRunnable(
5640                 notification.getKey(), 100, null);
5641         snoozeNotificationRunnable.run();
5642         snoozeNotificationRunnable.run();
5643 
5644         // snooze twice
5645         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
5646     }
5647 
5648     @Test
testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey()5649     public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception {
5650         final NotificationRecord notification = generateNotificationRecord(
5651                 mTestNotificationChannel, 1, "group", true);
5652         final NotificationRecord notification2 = generateNotificationRecord(
5653                 mTestNotificationChannel, 2, "group", true);
5654         mService.addNotification(notification);
5655         mService.addNotification(notification2);
5656         when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
5657         when(mSnoozeHelper.getNotifications(
5658                 anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
5659         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5660 
5661         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5662                 mService.new SnoozeNotificationRunnable(
5663                         notification.getKey(), 100, null);
5664         snoozeNotificationRunnable.run();
5665         when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt()))
5666                 .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
5667         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
5668                 mService.new SnoozeNotificationRunnable(
5669                         notification2.getKey(), 100, null);
5670         snoozeNotificationRunnable2.run();
5671 
5672         // snooze twice
5673         verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
5674     }
5675 
5676     @Test
testSnoozeRunnable_snoozeNonGrouped()5677     public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
5678         final NotificationRecord nonGrouped = generateNotificationRecord(
5679                 mTestNotificationChannel, 1, null, false);
5680         final NotificationRecord grouped = generateNotificationRecord(
5681                 mTestNotificationChannel, 2, "group", false);
5682         mService.addNotification(grouped);
5683         mService.addNotification(nonGrouped);
5684         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5685 
5686         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5687                 mService.new SnoozeNotificationRunnable(
5688                         nonGrouped.getKey(), 100, null);
5689         snoozeNotificationRunnable.run();
5690 
5691         // only snooze the one notification
5692         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5693         assertTrue(nonGrouped.getStats().hasSnoozed());
5694 
5695         assertEquals(2, mNotificationRecordLogger.numCalls());
5696         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5697                 mNotificationRecordLogger.event(0));
5698         assertEquals(
5699                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5700                 mNotificationRecordLogger.event(1));
5701     }
5702 
5703     @Test
testSnoozeRunnable_snoozeSummary_withChildren()5704     public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception {
5705         final NotificationRecord parent = generateNotificationRecord(
5706                 mTestNotificationChannel, 1, "group", true);
5707         final NotificationRecord child = generateNotificationRecord(
5708                 mTestNotificationChannel, 2, "group", false);
5709         final NotificationRecord child2 = generateNotificationRecord(
5710                 mTestNotificationChannel, 3, "group", false);
5711         mService.addNotification(parent);
5712         mService.addNotification(child);
5713         mService.addNotification(child2);
5714         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5715 
5716         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5717                 mService.new SnoozeNotificationRunnable(
5718                         parent.getKey(), 100, null);
5719         snoozeNotificationRunnable.run();
5720 
5721         // snooze parent and children
5722         verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong());
5723     }
5724 
5725     @Test
testSnoozeRunnable_snoozeGroupChild_fellowChildren()5726     public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception {
5727         final NotificationRecord parent = generateNotificationRecord(
5728                 mTestNotificationChannel, 1, "group", true);
5729         final NotificationRecord child = generateNotificationRecord(
5730                 mTestNotificationChannel, 2, "group", false);
5731         final NotificationRecord child2 = generateNotificationRecord(
5732                 mTestNotificationChannel, 3, "group", false);
5733         mService.addNotification(parent);
5734         mService.addNotification(child);
5735         mService.addNotification(child2);
5736         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5737 
5738         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5739                 mService.new SnoozeNotificationRunnable(
5740                         child2.getKey(), 100, null);
5741         snoozeNotificationRunnable.run();
5742 
5743         // only snooze the one child
5744         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5745 
5746         assertEquals(2, mNotificationRecordLogger.numCalls());
5747         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5748                 mNotificationRecordLogger.event(0));
5749         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
5750                         .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1));
5751     }
5752 
5753     @Test
testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary()5754     public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception {
5755         final NotificationRecord parent = generateNotificationRecord(
5756                 mTestNotificationChannel, 1, "group", true);
5757         assertTrue(parent.getSbn().getNotification().isGroupSummary());
5758         final NotificationRecord child = generateNotificationRecord(
5759                 mTestNotificationChannel, 2, "group", false);
5760         mService.addNotification(parent);
5761         mService.addNotification(child);
5762         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5763 
5764         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5765                 mService.new SnoozeNotificationRunnable(
5766                         child.getKey(), 100, null);
5767         snoozeNotificationRunnable.run();
5768 
5769         // snooze child and summary
5770         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
5771 
5772         assertEquals(4, mNotificationRecordLogger.numCalls());
5773         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5774                 mNotificationRecordLogger.event(0));
5775         assertEquals(
5776                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5777                 mNotificationRecordLogger.event(1));
5778         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5779                 mNotificationRecordLogger.event(2));
5780         assertEquals(
5781                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5782                 mNotificationRecordLogger.event(3));
5783     }
5784 
5785     @Test
testSnoozeRunnable_snoozeGroupChild_noOthersInGroup()5786     public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception {
5787         final NotificationRecord child = generateNotificationRecord(
5788                 mTestNotificationChannel, 2, "group", false);
5789         mService.addNotification(child);
5790         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5791 
5792         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5793                 mService.new SnoozeNotificationRunnable(
5794                         child.getKey(), 100, null);
5795         snoozeNotificationRunnable.run();
5796 
5797         // snooze child only
5798         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5799 
5800         assertEquals(2, mNotificationRecordLogger.numCalls());
5801         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5802                 mNotificationRecordLogger.event(0));
5803         assertEquals(
5804                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5805                 mNotificationRecordLogger.event(1));
5806     }
5807 
5808     @Test
5809     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed()5810     public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception {
5811         final NotificationRecord parent = generateNotificationRecord(
5812                 mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true);
5813         final NotificationRecord child = generateNotificationRecord(
5814                 mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false);
5815         mService.addNotification(parent);
5816         mService.addNotification(child);
5817         when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
5818 
5819         // snooze child only
5820         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5821                 mService.new SnoozeNotificationRunnable(
5822                         child.getKey(), 100, null);
5823         snoozeNotificationRunnable.run();
5824 
5825         // only child should be snoozed
5826         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
5827 
5828         // both group summary and child should be cancelled
5829         assertNull(mService.getNotificationRecord(parent.getKey()));
5830         assertNull(mService.getNotificationRecord(child.getKey()));
5831 
5832         assertEquals(4, mNotificationRecordLogger.numCalls());
5833         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
5834                 mNotificationRecordLogger.event(0));
5835         assertEquals(
5836                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
5837                 mNotificationRecordLogger.event(1));
5838     }
5839 
5840     @Test
testPostGroupChild_unsnoozeParent()5841     public void testPostGroupChild_unsnoozeParent() throws Exception {
5842         final NotificationRecord child = generateNotificationRecord(
5843                 mTestNotificationChannel, 2, "group", false);
5844 
5845         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing",
5846                 child.getSbn().getId(), child.getSbn().getNotification(),
5847                 child.getSbn().getUserId());
5848         waitForIdle();
5849 
5850         verify(mSnoozeHelper, times(1)).repostGroupSummary(
5851                 anyString(), anyInt(), eq(child.getGroupKey()));
5852     }
5853 
5854     @Test
testPostNonGroup_noUnsnoozing()5855     public void testPostNonGroup_noUnsnoozing() throws Exception {
5856         final NotificationRecord record = generateNotificationRecord(
5857                 mTestNotificationChannel, 2, null, false);
5858 
5859         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing",
5860                 record.getSbn().getId(), record.getSbn().getNotification(),
5861                 record.getSbn().getUserId());
5862         waitForIdle();
5863 
5864         verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
5865     }
5866 
5867     @Test
testPostGroupSummary_noUnsnoozing()5868     public void testPostGroupSummary_noUnsnoozing() throws Exception {
5869         final NotificationRecord parent = generateNotificationRecord(
5870                 mTestNotificationChannel, 2, "group", true);
5871 
5872         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostGroupSummary_noUnsnoozing",
5873                 parent.getSbn().getId(), parent.getSbn().getNotification(),
5874                 parent.getSbn().getUserId());
5875         waitForIdle();
5876 
5877         verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
5878     }
5879 
5880     @Test
testSystemNotificationListenerCanUnsnooze()5881     public void testSystemNotificationListenerCanUnsnooze() throws Exception {
5882         final NotificationRecord nr = generateNotificationRecord(
5883                 mTestNotificationChannel, 2, "group", false);
5884 
5885         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
5886                 "testSystemNotificationListenerCanUnsnooze",
5887                 nr.getSbn().getId(), nr.getSbn().getNotification(),
5888                 nr.getSbn().getUserId());
5889         waitForIdle();
5890         NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
5891                 mService.new SnoozeNotificationRunnable(
5892                         nr.getKey(), 100, null);
5893         snoozeNotificationRunnable.run();
5894 
5895         ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo(
5896                 null, new ComponentName(mPkg, "test_class"), mUid, true, null, 0, 234);
5897         listener.isSystem = true;
5898         when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener);
5899 
5900         mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey());
5901         waitForIdle();
5902         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
5903         assertEquals(1, notifs.length);
5904         assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey()));
5905     }
5906 
5907     @Test
testSetListenerAccessForUser()5908     public void testSetListenerAccessForUser() throws Exception {
5909         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5910         ComponentName c = ComponentName.unflattenFromString("package/Component");
5911         mBinderService.setNotificationListenerAccessGrantedForUser(
5912                 c, user.getIdentifier(), true, true);
5913 
5914 
5915         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
5916         verify(mListeners, times(1)).setPackageOrComponentEnabled(
5917                 c.flattenToString(), user.getIdentifier(), true, true, true);
5918         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5919                 c.flattenToString(), user.getIdentifier(), false, true, true);
5920         verify(mAssistants, never()).setPackageOrComponentEnabled(
5921                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
5922     }
5923 
5924     @Test
testSetListenerAccessForUser_grantWithNameTooLong_throws()5925     public void testSetListenerAccessForUser_grantWithNameTooLong_throws() {
5926         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5927         ComponentName c = new ComponentName("com.example.package",
5928                 com.google.common.base.Strings.repeat("Blah", 150));
5929 
5930         assertThrows(IllegalArgumentException.class,
5931                 () -> mBinderService.setNotificationListenerAccessGrantedForUser(
5932                         c, user.getIdentifier(), /* enabled= */ true, true));
5933     }
5934 
5935     @Test
testSetListenerAccessForUser_revokeWithNameTooLong_okay()5936     public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception {
5937         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5938         ComponentName c = new ComponentName("com.example.package",
5939                 com.google.common.base.Strings.repeat("Blah", 150));
5940 
5941         mBinderService.setNotificationListenerAccessGrantedForUser(
5942                 c, user.getIdentifier(), /* enabled= */ false, true);
5943 
5944         verify(mListeners).setPackageOrComponentEnabled(
5945                 c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
5946     }
5947 
5948     @Test
testSetAssistantAccessForUser()5949     public void testSetAssistantAccessForUser() throws Exception {
5950         UserInfo ui = new UserInfo();
5951         ui.id = mContext.getUserId() + 10;
5952         UserHandle user = UserHandle.of(ui.id);
5953         List<UserInfo> uis = new ArrayList<>();
5954         uis.add(ui);
5955         ComponentName c = ComponentName.unflattenFromString("package/Component");
5956         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
5957 
5958         mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true);
5959 
5960         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
5961         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
5962                 c.flattenToString(), user.getIdentifier(), true, true, true);
5963         verify(mAssistants).setUserSet(ui.id, true);
5964         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
5965                 c.flattenToString(), user.getIdentifier(), false, true);
5966         verify(mListeners, never()).setPackageOrComponentEnabled(
5967                 any(), anyInt(), anyBoolean(), anyBoolean());
5968     }
5969 
5970     @Test
testGetAssistantAllowedForUser()5971     public void testGetAssistantAllowedForUser() throws Exception {
5972         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
5973         try {
5974             mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier());
5975         } catch (IllegalStateException e) {
5976             if (!e.getMessage().contains("At most one NotificationAssistant")) {
5977                 throw e;
5978             }
5979         }
5980         verify(mAssistants, times(1)).getAllowedComponents(user.getIdentifier());
5981     }
5982 
5983     @Test
testGetAssistantAllowed()5984     public void testGetAssistantAllowed() throws Exception {
5985         try {
5986             mBinderService.getAllowedNotificationAssistant();
5987         } catch (IllegalStateException e) {
5988             if (!e.getMessage().contains("At most one NotificationAssistant")) {
5989                 throw e;
5990             }
5991         }
5992         verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId());
5993     }
5994 
5995     @Test
testSetNASMigrationDoneAndResetDefault_enableNAS()5996     public void testSetNASMigrationDoneAndResetDefault_enableNAS() throws Exception {
5997         int userId = 10;
5998         setNASMigrationDone(false, userId);
5999         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
6000 
6001         mBinderService.setNASMigrationDoneAndResetDefault(userId, true);
6002 
6003         assertTrue(mService.isNASMigrationDone(userId));
6004         verify(mAssistants, times(1)).resetDefaultFromConfig();
6005     }
6006 
6007     @Test
testSetNASMigrationDoneAndResetDefault_disableNAS()6008     public void testSetNASMigrationDoneAndResetDefault_disableNAS() throws Exception {
6009         int userId = 10;
6010         setNASMigrationDone(false, userId);
6011         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
6012 
6013         mBinderService.setNASMigrationDoneAndResetDefault(userId, false);
6014 
6015         assertTrue(mService.isNASMigrationDone(userId));
6016         verify(mAssistants, times(1)).clearDefaults();
6017     }
6018 
6019     @Test
testSetNASMigrationDoneAndResetDefault_multiProfile()6020     public void testSetNASMigrationDoneAndResetDefault_multiProfile() throws Exception {
6021         int userId1 = 11;
6022         int userId2 = 12; //work profile
6023         setNASMigrationDone(false, userId1);
6024         setNASMigrationDone(false, userId2);
6025         setUsers(new int[]{userId1, userId2});
6026         when(mUm.isManagedProfile(userId2)).thenReturn(true);
6027         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2});
6028 
6029         mBinderService.setNASMigrationDoneAndResetDefault(userId1, true);
6030         assertTrue(mService.isNASMigrationDone(userId1));
6031         assertTrue(mService.isNASMigrationDone(userId2));
6032     }
6033 
6034     @Test
testSetNASMigrationDoneAndResetDefault_multiUser()6035     public void testSetNASMigrationDoneAndResetDefault_multiUser() throws Exception {
6036         int userId1 = 11;
6037         int userId2 = 12;
6038         setNASMigrationDone(false, userId1);
6039         setNASMigrationDone(false, userId2);
6040         setUsers(new int[]{userId1, userId2});
6041         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1});
6042         when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2});
6043 
6044         mBinderService.setNASMigrationDoneAndResetDefault(userId1, true);
6045         assertTrue(mService.isNASMigrationDone(userId1));
6046         assertFalse(mService.isNASMigrationDone(userId2));
6047     }
6048 
6049     @Test
testSetDndAccessForUser()6050     public void testSetDndAccessForUser() throws Exception {
6051         UserHandle user = UserHandle.of(mContext.getUserId() + 10);
6052         ComponentName c = ComponentName.unflattenFromString("package/Component");
6053         mBinderService.setNotificationPolicyAccessGrantedForUser(
6054                 c.getPackageName(), user.getIdentifier(), true);
6055 
6056         verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
6057         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6058                 c.getPackageName(), user.getIdentifier(), true, true);
6059         verify(mAssistants, never()).setPackageOrComponentEnabled(
6060                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6061         verify(mListeners, never()).setPackageOrComponentEnabled(
6062                 any(), anyInt(), anyBoolean(), anyBoolean());
6063     }
6064 
6065     @Test
testSetListenerAccess()6066     public void testSetListenerAccess() throws Exception {
6067         ComponentName c = ComponentName.unflattenFromString("package/Component");
6068         mBinderService.setNotificationListenerAccessGranted(c, true, true);
6069 
6070         verify(mListeners, times(1)).setPackageOrComponentEnabled(
6071                 c.flattenToString(), mContext.getUserId(), true, true, true);
6072         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6073                 c.flattenToString(), mContext.getUserId(), false, true, true);
6074         verify(mAssistants, never()).setPackageOrComponentEnabled(
6075                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6076     }
6077 
6078     @Test
testSetAssistantAccess()6079     public void testSetAssistantAccess() throws Exception {
6080         List<UserInfo> uis = new ArrayList<>();
6081         UserInfo ui = new UserInfo();
6082         ui.id = mContext.getUserId();
6083         uis.add(ui);
6084         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6085         ComponentName c = ComponentName.unflattenFromString("package/Component");
6086 
6087         mBinderService.setNotificationAssistantAccessGranted(c, true);
6088 
6089         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6090                 c.flattenToString(), ui.id, true, true, true);
6091         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6092                 c.flattenToString(), ui.id, false, true);
6093         verify(mListeners, never()).setPackageOrComponentEnabled(
6094                 any(), anyInt(), anyBoolean(), anyBoolean());
6095     }
6096 
6097     @Test
testSetAssistantAccess_multiProfile()6098     public void testSetAssistantAccess_multiProfile() throws Exception {
6099         List<UserInfo> uis = new ArrayList<>();
6100         UserInfo ui = new UserInfo();
6101         ui.id = mContext.getUserId();
6102         uis.add(ui);
6103         UserInfo ui10 = new UserInfo();
6104         ui10.id = mContext.getUserId() + 10;
6105         uis.add(ui10);
6106         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6107         ComponentName c = ComponentName.unflattenFromString("package/Component");
6108 
6109         mBinderService.setNotificationAssistantAccessGranted(c, true);
6110 
6111         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6112                 c.flattenToString(), ui.id, true, true, true);
6113         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6114                 c.flattenToString(), ui10.id, true, true, true);
6115 
6116         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6117                 c.flattenToString(), ui.id, false, true);
6118         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6119                 c.flattenToString(), ui10.id, false, true);
6120         verify(mListeners, never()).setPackageOrComponentEnabled(
6121                 any(), anyInt(), anyBoolean(), anyBoolean());
6122     }
6123 
6124     @Test
testSetAssistantAccess_nullWithAllowedAssistant()6125     public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception {
6126         ArrayList<ComponentName> componentList = new ArrayList<>();
6127         ComponentName c = ComponentName.unflattenFromString("package/Component");
6128         componentList.add(c);
6129         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
6130         List<UserInfo> uis = new ArrayList<>();
6131         UserInfo ui = new UserInfo();
6132         ui.id = mContext.getUserId();
6133         uis.add(ui);
6134         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6135 
6136         mBinderService.setNotificationAssistantAccessGranted(null, true);
6137 
6138         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6139                 c.flattenToString(), ui.id, true, false, true);
6140         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6141                 c.flattenToString(), ui.id, false,  false);
6142         verify(mListeners, never()).setPackageOrComponentEnabled(
6143                 any(), anyInt(), anyBoolean(), anyBoolean());
6144     }
6145 
6146     @Test
testSetAssistantAccessForUser_nullWithAllowedAssistant()6147     public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception {
6148         List<UserInfo> uis = new ArrayList<>();
6149         UserInfo ui = new UserInfo();
6150         ui.id = mContext.getUserId() + 10;
6151         uis.add(ui);
6152         UserHandle user = ui.getUserHandle();
6153         ArrayList<ComponentName> componentList = new ArrayList<>();
6154         ComponentName c = ComponentName.unflattenFromString("package/Component");
6155         componentList.add(c);
6156         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
6157         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6158 
6159         mBinderService.setNotificationAssistantAccessGrantedForUser(
6160                 null, user.getIdentifier(), true);
6161 
6162         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6163                 c.flattenToString(), user.getIdentifier(), true, false, true);
6164         verify(mAssistants).setUserSet(ui.id, true);
6165         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6166                 c.flattenToString(), user.getIdentifier(), false,  false);
6167         verify(mListeners, never()).setPackageOrComponentEnabled(
6168                 any(), anyInt(), anyBoolean(), anyBoolean());
6169     }
6170 
6171     @Test
testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()6172     public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()
6173             throws Exception {
6174         List<UserInfo> uis = new ArrayList<>();
6175         UserInfo ui = new UserInfo();
6176         ui.id = mContext.getUserId();
6177         uis.add(ui);
6178         UserInfo ui10 = new UserInfo();
6179         ui10.id = mContext.getUserId() + 10;
6180         uis.add(ui10);
6181         UserHandle user = ui.getUserHandle();
6182         ArrayList<ComponentName> componentList = new ArrayList<>();
6183         ComponentName c = ComponentName.unflattenFromString("package/Component");
6184         componentList.add(c);
6185         when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
6186         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6187 
6188         mBinderService.setNotificationAssistantAccessGrantedForUser(
6189                     null, user.getIdentifier(), true);
6190 
6191         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6192                 c.flattenToString(), user.getIdentifier(), true, false, true);
6193         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6194                 c.flattenToString(), ui10.id, true, false, true);
6195         verify(mAssistants).setUserSet(ui.id, true);
6196         verify(mAssistants).setUserSet(ui10.id, true);
6197         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6198                 c.flattenToString(), user.getIdentifier(), false,  false);
6199         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6200                 c.flattenToString(), ui10.id, false,  false);
6201         verify(mListeners, never()).setPackageOrComponentEnabled(
6202                 any(), anyInt(), anyBoolean(), anyBoolean());
6203     }
6204 
6205     @Test
testSetDndAccess()6206     public void testSetDndAccess() throws Exception {
6207         ComponentName c = ComponentName.unflattenFromString("package/Component");
6208 
6209         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
6210 
6211         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6212                 c.getPackageName(), mContext.getUserId(), true, true);
6213         verify(mAssistants, never()).setPackageOrComponentEnabled(
6214                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6215         verify(mListeners, never()).setPackageOrComponentEnabled(
6216                 any(), anyInt(), anyBoolean(), anyBoolean());
6217     }
6218 
6219     @Test
testSetListenerAccess_onLowRam()6220     public void testSetListenerAccess_onLowRam() throws Exception {
6221         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6222         ComponentName c = ComponentName.unflattenFromString("package/Component");
6223         mBinderService.setNotificationListenerAccessGranted(c, true, true);
6224 
6225         verify(mListeners).setPackageOrComponentEnabled(
6226                 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6227         verify(mConditionProviders).setPackageOrComponentEnabled(
6228                 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6229         verify(mAssistants).migrateToXml();
6230         verify(mAssistants).resetDefaultAssistantsIfNecessary();
6231     }
6232 
6233     @Test
testSetAssistantAccess_onLowRam()6234     public void testSetAssistantAccess_onLowRam() throws Exception {
6235         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6236         ComponentName c = ComponentName.unflattenFromString("package/Component");
6237         List<UserInfo> uis = new ArrayList<>();
6238         UserInfo ui = new UserInfo();
6239         ui.id = mContext.getUserId();
6240         uis.add(ui);
6241         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6242 
6243         mBinderService.setNotificationAssistantAccessGranted(c, true);
6244 
6245         verify(mListeners).migrateToXml();
6246         verify(mConditionProviders).setPackageOrComponentEnabled(
6247                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6248         verify(mAssistants).migrateToXml();
6249         verify(mAssistants).resetDefaultAssistantsIfNecessary();
6250     }
6251 
6252     @Test
testSetDndAccess_onLowRam()6253     public void testSetDndAccess_onLowRam() throws Exception {
6254         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6255         ComponentName c = ComponentName.unflattenFromString("package/Component");
6256         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
6257 
6258         verify(mListeners).migrateToXml();
6259         verify(mConditionProviders).setPackageOrComponentEnabled(
6260                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6261         verify(mAssistants).migrateToXml();
6262         verify(mAssistants).resetDefaultAssistantsIfNecessary();
6263     }
6264 
6265     @Test
testSetListenerAccess_doesNothingOnLowRam_exceptWatch()6266     public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
6267         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
6268         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6269         ComponentName c = ComponentName.unflattenFromString("package/Component");
6270 
6271         mBinderService.setNotificationListenerAccessGranted(c, true, true);
6272 
6273         verify(mListeners, times(1)).setPackageOrComponentEnabled(
6274                 c.flattenToString(), mContext.getUserId(), true, true, true);
6275         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6276                 c.flattenToString(), mContext.getUserId(), false, true, true);
6277         verify(mAssistants, never()).setPackageOrComponentEnabled(
6278                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6279     }
6280 
6281     @Test
testSetAssistantAccess_doesNothingOnLowRam_exceptWatch()6282     public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
6283         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
6284         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6285         ComponentName c = ComponentName.unflattenFromString("package/Component");
6286         List<UserInfo> uis = new ArrayList<>();
6287         UserInfo ui = new UserInfo();
6288         ui.id = mContext.getUserId();
6289         uis.add(ui);
6290         when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
6291 
6292         mBinderService.setNotificationAssistantAccessGranted(c, true);
6293 
6294         verify(mListeners, never()).setPackageOrComponentEnabled(
6295                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6296         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6297                 c.flattenToString(), ui.id, false, true);
6298         verify(mAssistants, times(1)).setPackageOrComponentEnabled(
6299                 c.flattenToString(), ui.id, true, true, true);
6300     }
6301 
6302     @Test
testSetDndAccess_doesNothingOnLowRam_exceptWatch()6303     public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
6304         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
6305         when(mActivityManager.isLowRamDevice()).thenReturn(true);
6306         ComponentName c = ComponentName.unflattenFromString("package/Component");
6307 
6308         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
6309 
6310         verify(mListeners, never()).setPackageOrComponentEnabled(
6311                 anyString(), anyInt(), anyBoolean(), anyBoolean());
6312         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
6313                 c.getPackageName(), mContext.getUserId(), true, true);
6314         verify(mAssistants, never()).setPackageOrComponentEnabled(
6315                 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
6316     }
6317 
6318     @Test
testOnlyAutogroupIfNeeded_newNotification_ghUpdate()6319     public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() {
6320         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
6321         mService.addEnqueuedNotification(r);
6322         NotificationManagerService.PostNotificationRunnable runnable =
6323                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
6324                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6325         runnable.run();
6326         waitForIdle();
6327 
6328         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6329     }
6330 
6331     @Test
testOnlyAutogroupIfNeeded_groupChanged_ghUpdate()6332     public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() {
6333         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6334                 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false);
6335         mService.addNotification(r);
6336 
6337         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
6338                 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false);
6339         mService.addEnqueuedNotification(update);
6340         NotificationManagerService.PostNotificationRunnable runnable =
6341                 mService.new PostNotificationRunnable(update.getKey(),
6342                         update.getSbn().getPackageName(), update.getUid(),
6343                         mPostNotificationTrackerFactory.newTracker(null));
6344         runnable.run();
6345         waitForIdle();
6346 
6347         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6348     }
6349 
6350     @Test
testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate()6351     public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() {
6352         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6353                 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false);
6354         mService.addNotification(r);
6355 
6356         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
6357                 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false);
6358         update.getNotification().flags = FLAG_AUTO_CANCEL;
6359         mService.addEnqueuedNotification(update);
6360         NotificationManagerService.PostNotificationRunnable runnable =
6361                 mService.new PostNotificationRunnable(update.getKey(),
6362                         update.getSbn().getPackageName(), update.getUid(),
6363                         mPostNotificationTrackerFactory.newTracker(null));
6364         runnable.run();
6365         waitForIdle();
6366 
6367         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6368     }
6369 
6370     @Test
testOnlyAutogroupIfNeeded_channelChanged_ghUpdate()6371     public void testOnlyAutogroupIfNeeded_channelChanged_ghUpdate() {
6372         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6373                 "testOnlyAutogroupIfNeeded_channelChanged_ghUpdate", null, false);
6374         mService.addNotification(r);
6375 
6376         NotificationRecord update = generateNotificationRecord(mSilentChannel, 0,
6377                 "testOnlyAutogroupIfNeeded_channelChanged_ghUpdate", null, false);
6378         mService.addEnqueuedNotification(update);
6379 
6380         NotificationManagerService.PostNotificationRunnable runnable =
6381                 mService.new PostNotificationRunnable(update.getKey(),
6382                         update.getSbn().getPackageName(), update.getUid(),
6383                         mPostNotificationTrackerFactory.newTracker(null));
6384         runnable.run();
6385         waitForIdle();
6386 
6387         verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
6388     }
6389 
6390     @Test
testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate()6391     public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() {
6392         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0,
6393                 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);
6394         mService.addNotification(r);
6395         NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0,
6396                 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false);
6397         update.getNotification().color = Color.BLACK;
6398         mService.addEnqueuedNotification(update);
6399 
6400         NotificationManagerService.PostNotificationRunnable runnable =
6401                 mService.new PostNotificationRunnable(update.getKey(),
6402                         update.getSbn().getPackageName(),
6403                         update.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6404         runnable.run();
6405         waitForIdle();
6406 
6407         verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
6408     }
6409 
6410     @Test
testDontAutogroupIfCritical()6411     public void testDontAutogroupIfCritical() throws Exception {
6412         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
6413         r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW);
6414         mService.addEnqueuedNotification(r);
6415         NotificationManagerService.PostNotificationRunnable runnable =
6416                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
6417                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6418         runnable.run();
6419 
6420         r = generateNotificationRecord(mTestNotificationChannel, 1, null, false);
6421         r.setCriticality(CriticalNotificationExtractor.CRITICAL);
6422         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
6423                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
6424         mService.addEnqueuedNotification(r);
6425 
6426         runnable.run();
6427         waitForIdle();
6428 
6429         verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
6430     }
6431 
6432     @Test
testNoNotificationDuringSetupPermission()6433     public void testNoNotificationDuringSetupPermission() throws Exception {
6434         mContext.getTestablePermissions().setPermission(
6435                 android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED);
6436         Bundle extras = new Bundle();
6437         extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true);
6438         Notification.Builder nb = new Notification.Builder(mContext,
6439                 mTestNotificationChannel.getId())
6440                 .setContentTitle("foo")
6441                 .addExtras(extras)
6442                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
6443         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
6444                 "testNoNotificationDuringSetupPermission", mUid, 0,
6445                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
6446         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6447 
6448         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
6449                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
6450         waitForIdle();
6451 
6452         NotificationRecord posted = mService.findNotificationLocked(
6453                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
6454 
6455         assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP));
6456     }
6457 
6458     @Test
testNoFakeColorizedPermission()6459     public void testNoFakeColorizedPermission() throws Exception {
6460         mContext.getTestablePermissions().setPermission(
6461                 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED);
6462         Notification.Builder nb = new Notification.Builder(mContext,
6463                 mTestNotificationChannel.getId())
6464                 .setContentTitle("foo")
6465                 .setColorized(true).setColor(Color.WHITE)
6466                 .setFlag(FLAG_CAN_COLORIZE, true)
6467                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
6468         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
6469                 "testNoFakeColorizedPermission", mUid, 0,
6470                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
6471         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6472 
6473         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
6474                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
6475         waitForIdle();
6476 
6477         NotificationRecord posted = mService.findNotificationLocked(
6478                 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
6479 
6480         assertFalse(posted.getNotification().isColorized());
6481     }
6482 
6483     @Test
6484     @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
testMediaStyle_enforceNoClearFlagEnabled()6485     public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
6486         Notification.MediaStyle style = new Notification.MediaStyle();
6487         Notification.Builder nb = new Notification.Builder(mContext,
6488                 mTestNotificationChannel.getId())
6489                 .setStyle(style);
6490 
6491         NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
6492 
6493         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
6494     }
6495 
6496     @Test
6497     @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
testCustomMediaStyle_enforceNoClearFlagEnabled()6498     public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
6499         Notification.DecoratedMediaCustomViewStyle style =
6500                 new Notification.DecoratedMediaCustomViewStyle();
6501         Notification.Builder nb = new Notification.Builder(mContext,
6502                 mTestNotificationChannel.getId())
6503                 .setStyle(style);
6504 
6505         NotificationRecord posted = createAndPostNotification(nb,
6506                 "testCustomMediaStyleSetNoClearFlag");
6507 
6508         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
6509     }
6510 
6511     @Test
6512     @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
testMediaStyle_enforceNoClearFlagDisabled()6513     public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
6514         Notification.MediaStyle style = new Notification.MediaStyle();
6515         Notification.Builder nb = new Notification.Builder(mContext,
6516                 mTestNotificationChannel.getId())
6517                 .setStyle(style);
6518 
6519         NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
6520 
6521         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
6522     }
6523 
6524     @Test
6525     @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
testCustomMediaStyle_enforceNoClearFlagDisabled()6526     public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
6527         Notification.DecoratedMediaCustomViewStyle style =
6528                 new Notification.DecoratedMediaCustomViewStyle();
6529         Notification.Builder nb = new Notification.Builder(mContext,
6530                 mTestNotificationChannel.getId())
6531                 .setStyle(style);
6532 
6533         NotificationRecord posted = createAndPostNotification(nb,
6534                 "testCustomMediaStyleSetNoClearFlag");
6535 
6536         assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
6537     }
6538 
6539     @Test
testMediaStyleRemote_hasPermission()6540     public void testMediaStyleRemote_hasPermission() throws RemoteException {
6541         String deviceName = "device";
6542         mContext.getTestablePermissions().setPermission(
6543                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED);
6544         Notification.MediaStyle style = new Notification.MediaStyle();
6545         style.setRemotePlaybackInfo(deviceName, 0, null);
6546         Notification.Builder nb = new Notification.Builder(mContext,
6547                 mTestNotificationChannel.getId())
6548                 .setStyle(style);
6549 
6550         NotificationRecord posted = createAndPostNotification(nb,
6551                 "testMediaStyleRemoteHasPermission");
6552         Bundle extras = posted.getNotification().extras;
6553 
6554         assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6555         assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6556     }
6557 
6558     @Test
testMediaStyleRemote_noPermission()6559     public void testMediaStyleRemote_noPermission() throws RemoteException {
6560         String deviceName = "device";
6561         mContext.getTestablePermissions().setPermission(
6562                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED);
6563         Notification.MediaStyle style = new Notification.MediaStyle();
6564         style.setRemotePlaybackInfo(deviceName, 0, null);
6565         Notification.Builder nb = new Notification.Builder(mContext,
6566                 mTestNotificationChannel.getId())
6567                 .setStyle(style);
6568 
6569         NotificationRecord posted = createAndPostNotification(nb,
6570                 "testMediaStyleRemoteNoPermission");
6571 
6572         assertFalse(posted.getNotification().extras
6573                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6574         assertFalse(posted.getNotification().extras
6575                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
6576         assertFalse(posted.getNotification().extras
6577                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
6578     }
6579 
6580     @Test
testCustomMediaStyleRemote_noPermission()6581     public void testCustomMediaStyleRemote_noPermission() throws RemoteException {
6582         String deviceName = "device";
6583         when(mPackageManager.checkPermission(
6584                 eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
6585                 .thenReturn(PERMISSION_DENIED);
6586         Notification.DecoratedMediaCustomViewStyle style =
6587                 new Notification.DecoratedMediaCustomViewStyle();
6588         style.setRemotePlaybackInfo(deviceName, 0, null);
6589         Notification.Builder nb = new Notification.Builder(mContext,
6590                 mTestNotificationChannel.getId())
6591                 .setStyle(style);
6592 
6593         NotificationRecord posted = createAndPostNotification(nb,
6594                 "testCustomMediaStyleRemoteNoPermission");
6595 
6596         assertFalse(posted.getNotification().extras
6597                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
6598         assertFalse(posted.getNotification().extras
6599                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
6600         assertFalse(posted.getNotification().extras
6601                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
6602     }
6603 
6604     @Test
testSubstituteAppName_hasPermission()6605     public void testSubstituteAppName_hasPermission() throws RemoteException {
6606         String subName = "Substitute Name";
6607         mContext.getTestablePermissions().setPermission(
6608                 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED);
6609         Bundle extras = new Bundle();
6610         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
6611         Notification.Builder nb = new Notification.Builder(mContext,
6612                 mTestNotificationChannel.getId())
6613                 .addExtras(extras);
6614 
6615         NotificationRecord posted = createAndPostNotification(nb,
6616                 "testSubstituteAppNameHasPermission");
6617 
6618         assertTrue(posted.getNotification().extras
6619                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
6620         assertEquals(posted.getNotification().extras
6621                 .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName);
6622     }
6623 
6624     @Test
testSubstituteAppName_noPermission()6625     public void testSubstituteAppName_noPermission() throws RemoteException {
6626         mContext.getTestablePermissions().setPermission(
6627                 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED);
6628         Bundle extras = new Bundle();
6629         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
6630         Notification.Builder nb = new Notification.Builder(mContext,
6631                 mTestNotificationChannel.getId())
6632                 .addExtras(extras);
6633 
6634         NotificationRecord posted = createAndPostNotification(nb,
6635                 "testSubstituteAppNameNoPermission");
6636 
6637         assertFalse(posted.getNotification().extras
6638                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
6639     }
6640 
6641     @Test
testGetNotificationCountLocked()6642     public void testGetNotificationCountLocked() {
6643         String sampleTagToExclude = null;
6644         int sampleIdToExclude = 0;
6645         for (int i = 0; i < 20; i++) {
6646             NotificationRecord r =
6647                     generateNotificationRecord(mTestNotificationChannel, i, null, false);
6648             mService.addEnqueuedNotification(r);
6649 
6650         }
6651         for (int i = 0; i < 20; i++) {
6652             NotificationRecord r =
6653                     generateNotificationRecord(mTestNotificationChannel, i, null, false);
6654             mService.addNotification(r);
6655             sampleTagToExclude = r.getSbn().getTag();
6656             sampleIdToExclude = i;
6657         }
6658 
6659         // another package
6660         Notification n =
6661                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
6662                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
6663                 .build();
6664 
6665         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0,
6666                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
6667         NotificationRecord otherPackage =
6668                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
6669         mService.addEnqueuedNotification(otherPackage);
6670         mService.addNotification(otherPackage);
6671 
6672         // Same notifications are enqueued as posted, everything counts b/c id and tag don't match
6673         // anything that's currently enqueued or posted
6674         int userId = mUserId;
6675         assertEquals(40,
6676                 mService.getNotificationCount(mPkg, userId, 0, null));
6677         assertEquals(40,
6678                 mService.getNotificationCount(mPkg, userId, 0, "tag2"));
6679 
6680         // return all for package "a" - "banana" tag isn't used
6681         assertEquals(2,
6682                 mService.getNotificationCount("a", userId, 0, "banana"));
6683 
6684         // exclude a known notification - it's excluded from only the posted list, not enqueued
6685         assertEquals(39, mService.getNotificationCount(
6686                 mPkg, userId, sampleIdToExclude, sampleTagToExclude));
6687     }
6688 
6689     @Test
testAddAutogroup_requestsSort()6690     public void testAddAutogroup_requestsSort() throws Exception {
6691         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6692         mService.addNotification(r);
6693         mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true);
6694 
6695         verify(mRankingHandler, times(1)).requestSort();
6696     }
6697 
6698     @Test
testRemoveAutogroup_requestsSort()6699     public void testRemoveAutogroup_requestsSort() throws Exception {
6700         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6701         r.setOverrideGroupKey("TEST");
6702         mService.addNotification(r);
6703         mService.removeAutogroupKeyLocked(r.getKey());
6704 
6705         verify(mRankingHandler, times(1)).requestSort();
6706     }
6707 
6708     @Test
testReaddAutogroup_noSort()6709     public void testReaddAutogroup_noSort() throws Exception {
6710         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6711         r.setOverrideGroupKey("TEST");
6712         mService.addNotification(r);
6713         mService.addAutogroupKeyLocked(r.getKey(), "grpName", true);
6714 
6715         verify(mRankingHandler, never()).requestSort();
6716     }
6717 
6718     @Test
6719     @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST)
testAutogroupSuppressSort_noSort()6720     public void testAutogroupSuppressSort_noSort() throws Exception {
6721         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6722         mService.addNotification(r);
6723         mService.addAutogroupKeyLocked(r.getKey(), "grpName", false);
6724 
6725         verify(mRankingHandler, never()).requestSort();
6726     }
6727 
6728     @Test
6729     @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST)
testAutogroupOnPost_skipManualSort()6730     public void testAutogroupOnPost_skipManualSort() throws Exception {
6731         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6732         mService.addNotification(r);
6733         verify(mRankingHandler, never()).requestSort();
6734     }
6735 
6736     @Test
testHandleRankingSort_sendsUpdateOnSignalExtractorChange()6737     public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception {
6738         mService.setPreferencesHelper(mPreferencesHelper);
6739         NotificationManagerService.WorkerHandler handler = mock(
6740                 NotificationManagerService.WorkerHandler.class);
6741         mService.setHandler(handler);
6742 
6743         Map<String, Answer> answers = getSignalExtractorSideEffects();
6744         for (String message : answers.keySet()) {
6745             mService.clearNotifications();
6746             final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6747             mService.addNotification(r);
6748 
6749             doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r);
6750 
6751             mService.handleRankingSort();
6752         }
6753         verify(handler, times(answers.size())).scheduleSendRankingUpdate();
6754     }
6755 
6756     @Test
testHandleRankingSort_noUpdateWhenNoSignalChange()6757     public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception {
6758         mService.setRankingHelper(mRankingHelper);
6759         NotificationManagerService.WorkerHandler handler = mock(
6760                 NotificationManagerService.WorkerHandler.class);
6761         mService.setHandler(handler);
6762 
6763         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
6764         mService.addNotification(r);
6765 
6766         mService.handleRankingSort();
6767         verify(handler, never()).scheduleSendRankingUpdate();
6768     }
6769 
6770     @Test
testReadPolicyXml_readApprovedServicesFromXml()6771     public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception {
6772         final String upgradeXml = "<notification-policy version=\"1\">"
6773                 + "<ranking></ranking>"
6774                 + "<enabled_listeners>"
6775                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
6776                 + "</enabled_listeners>"
6777                 + "<enabled_assistants>"
6778                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
6779                 + "</enabled_assistants>"
6780                 + "<dnd_apps>"
6781                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
6782                 + "</dnd_apps>"
6783                 + "</notification-policy>";
6784         mService.readPolicyXml(
6785                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
6786                 false,
6787                 UserHandle.USER_ALL, null);
6788         verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
6789         verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
6790         verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
6791 
6792         // numbers are inflated for setup
6793         verify(mListeners, times(1)).migrateToXml();
6794         verify(mConditionProviders, times(1)).migrateToXml();
6795         verify(mAssistants, times(1)).migrateToXml();
6796         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
6797     }
6798 
6799     @Test
testReadPolicyXml_readSnoozedNotificationsFromXml()6800     public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception {
6801         final String upgradeXml = "<notification-policy version=\"1\">"
6802                 + "<snoozed-notifications>></snoozed-notifications>"
6803                 + "</notification-policy>";
6804         mService.readPolicyXml(
6805                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
6806                 false,
6807                 UserHandle.USER_ALL, null);
6808         verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong());
6809     }
6810 
6811     @Test
testReadPolicyXml_readApprovedServicesFromSettings()6812     public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
6813         final String preupgradeXml = "<notification-policy version=\"1\">"
6814                 + "<ranking></ranking>"
6815                 + "</notification-policy>";
6816         mService.readPolicyXml(
6817                 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
6818                 false,
6819                 UserHandle.USER_ALL, null);
6820         verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt());
6821         verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt());
6822         verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt());
6823 
6824         // numbers are inflated for setup
6825         verify(mListeners, times(2)).migrateToXml();
6826         verify(mConditionProviders, times(2)).migrateToXml();
6827         verify(mAssistants, times(2)).migrateToXml();
6828         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
6829     }
6830 
6831     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser()6832     public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception {
6833         final String policyXml = "<notification-policy version=\"1\">"
6834                 + "<ranking></ranking>"
6835                 + "<enabled_listeners>"
6836                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6837                 + "</enabled_listeners>"
6838                 + "<enabled_assistants>"
6839                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6840                 + "</enabled_assistants>"
6841                 + "<dnd_apps>"
6842                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6843                 + "</dnd_apps>"
6844                 + "</notification-policy>";
6845         UserInfo ui = new UserInfo(10, "Clone", UserInfo.FLAG_PROFILE);
6846         ui.userType = USER_TYPE_PROFILE_CLONE;
6847         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6848         mService.readPolicyXml(
6849                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6850                 true,
6851                 10, null);
6852         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
6853         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
6854         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
6855     }
6856 
6857     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser()6858     public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception {
6859         final String policyXml = "<notification-policy version=\"1\">"
6860                 + "<ranking></ranking>"
6861                 + "<enabled_listeners>"
6862                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6863                 + "</enabled_listeners>"
6864                 + "<enabled_assistants>"
6865                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6866                 + "</enabled_assistants>"
6867                 + "<dnd_apps>"
6868                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6869                 + "</dnd_apps>"
6870                 + "</notification-policy>";
6871         UserInfo ui = new UserInfo(10, "Work", UserInfo.FLAG_PROFILE);
6872         ui.userType = USER_TYPE_PROFILE_MANAGED;
6873         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6874         mService.readPolicyXml(
6875                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6876                 true,
6877                 10, null);
6878         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
6879         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
6880         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
6881     }
6882 
6883     @Test
testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser()6884     public void testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser() throws Exception {
6885         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
6886                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
6887         final String policyXml = "<notification-policy version=\"1\">"
6888                 + "<ranking></ranking>"
6889                 + "<enabled_listeners>"
6890                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6891                 + "</enabled_listeners>"
6892                 + "<enabled_assistants>"
6893                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6894                 + "</enabled_assistants>"
6895                 + "<dnd_apps>"
6896                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6897                 + "</dnd_apps>"
6898                 + "</notification-policy>";
6899         UserInfo ui = new UserInfo(10, "Private", UserInfo.FLAG_PROFILE);
6900         ui.userType = USER_TYPE_PROFILE_PRIVATE;
6901         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6902         mService.readPolicyXml(
6903                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6904                 true,
6905                 10, null);
6906         verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
6907         verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
6908         verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
6909     }
6910 
6911     @Test
testReadPolicyXml_restoresManagedServicesForNonManagedUser()6912     public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception {
6913         final String policyXml = "<notification-policy version=\"1\">"
6914                 + "<ranking></ranking>"
6915                 + "<enabled_listeners>"
6916                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6917                 + "</enabled_listeners>"
6918                 + "<enabled_assistants>"
6919                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6920                 + "</enabled_assistants>"
6921                 + "<dnd_apps>"
6922                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
6923                 + "</dnd_apps>"
6924                 + "</notification-policy>";
6925         UserInfo ui = new UserInfo();
6926         ui.id = 10;
6927         ui.userType = USER_TYPE_FULL_SECONDARY;
6928         when(mUmInternal.getUserInfo(10)).thenReturn(ui);
6929         mService.readPolicyXml(
6930                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
6931                 true,
6932                 10, null);
6933         verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10));
6934         verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10));
6935         verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10));
6936     }
6937 
6938     @Test
6939     @EnableFlags(android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING)
testReadPolicyXml_backupRestoreLogging()6940     public void testReadPolicyXml_backupRestoreLogging() throws Exception {
6941         BackupRestoreEventLogger logger = mock(BackupRestoreEventLogger.class);
6942 
6943         if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
6944             // By default, the ZenModeHelper only has a configuration for the system user.
6945             // If the current user is not the system user, the user must be updated.
6946             mService.mZenModeHelper.onUserSwitched(ActivityManager.getCurrentUser());
6947         }
6948         UserInfo ui = new UserInfo(ActivityManager.getCurrentUser(), "Clone", UserInfo.FLAG_FULL);
6949         ui.userType = USER_TYPE_FULL_SYSTEM;
6950         when(mUmInternal.getUserInfo(ActivityManager.getCurrentUser())).thenReturn(ui);
6951         when(mPermissionHelper.getNotificationPermissionValues(ActivityManager.getCurrentUser()))
6952                 .thenReturn(new ArrayMap<>());
6953         TypedXmlSerializer serializer = Xml.newFastSerializer();
6954         ByteArrayOutputStream baos = new ByteArrayOutputStream();
6955         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
6956         serializer.startDocument(null, true);
6957         mService.writePolicyXml(baos, true, ActivityManager.getCurrentUser(), logger);
6958         serializer.flush();
6959 
6960         mService.readPolicyXml(
6961                 new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
6962                 true, ActivityManager.getCurrentUser(), logger);
6963 
6964         verify(logger).logItemsBackedUp(DATA_TYPE_ZEN_CONFIG, 1);
6965         verify(logger, never())
6966                 .logItemsBackupFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString());
6967 
6968         verify(logger).logItemsRestored(DATA_TYPE_ZEN_CONFIG, 1);
6969         verify(logger, never())
6970                 .logItemsRestoreFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString());
6971     }
6972 
6973     @Test
testLocaleChangedCallsUpdateDefaultZenModeRules()6974     public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception {
6975         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
6976         mService.mZenModeHelper = mZenModeHelper;
6977         mService.mLocaleChangeReceiver.onReceive(mContext,
6978                 new Intent(Intent.ACTION_LOCALE_CHANGED));
6979 
6980         verify(mZenModeHelper).updateZenRulesOnLocaleChange();
6981     }
6982 
simulateNotificationTimeout(String notificationKey)6983     private void simulateNotificationTimeout(String notificationKey) {
6984         if (Flags.allNotifsNeedTtl()) {
6985             mService.mNotificationManagerPrivate.timeoutNotification(notificationKey);
6986         } else {
6987             final Bundle extras = new Bundle();
6988             extras.putString(EXTRA_KEY, notificationKey);
6989             final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT);
6990             intent.putExtras(extras);
6991             mNotificationTimeoutReceiver.onReceive(getContext(), intent);
6992         }
6993     }
6994 
6995     @Test
testTimeout_CancelsNotification()6996     public void testTimeout_CancelsNotification() throws Exception {
6997         final NotificationRecord notif = generateNotificationRecord(
6998                 mTestNotificationChannel, 1, null, false);
6999         mService.addNotification(notif);
7000 
7001         simulateNotificationTimeout(notif.getKey());
7002         waitForIdle();
7003 
7004         // Check that the notification was cancelled.
7005         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
7006         assertThat(notifsAfter.length).isEqualTo(0);
7007         assertThat(mService.getNotificationRecord(notif.getKey())).isNull();
7008     }
7009 
7010     @Test
testTimeout_NoCancelForegroundServiceNotification()7011     public void testTimeout_NoCancelForegroundServiceNotification() throws Exception {
7012         // Creates a notification with FLAG_FOREGROUND_SERVICE
7013         final NotificationRecord notif = generateNotificationRecord(null);
7014         notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
7015         mService.addNotification(notif);
7016 
7017         simulateNotificationTimeout(notif.getKey());
7018         waitForIdle();
7019 
7020         // Check that the notification was not cancelled.
7021         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
7022         assertThat(notifsAfter.length).isEqualTo(1);
7023         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
7024     }
7025 
7026     @Test
testTimeout_NoCancelUserInitJobNotification()7027     public void testTimeout_NoCancelUserInitJobNotification() throws Exception {
7028         // Create a notification with FLAG_USER_INITIATED_JOB
7029         final NotificationRecord notif = generateNotificationRecord(null);
7030         notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB;
7031         mService.addNotification(notif);
7032 
7033         simulateNotificationTimeout(notif.getKey());
7034         waitForIdle();
7035 
7036         // Check that the notification was not cancelled.
7037         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
7038         assertThat(notifsAfter.length).isEqualTo(1);
7039         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
7040     }
7041 
7042     @Test
7043     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testTimeout_NoCancelLifetimeExtensionNotification()7044     public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception {
7045         // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY
7046         final NotificationRecord notif = generateNotificationRecord(null);
7047         notif.getSbn().getNotification().flags =
7048                 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7049         mService.addNotification(notif);
7050 
7051         simulateNotificationTimeout(notif.getKey());
7052         waitForIdle();
7053 
7054         // Check that the notification was not cancelled.
7055         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
7056         assertThat(notifsAfter.length).isEqualTo(1);
7057         assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
7058 
7059         // Checks that a post update is sent.
7060         verify(mWorkerHandler, times(1))
7061                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
7062         ArgumentCaptor<NotificationRecord> captor =
7063                 ArgumentCaptor.forClass(NotificationRecord.class);
7064         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
7065                 anyBoolean());
7066         assertThat(captor.getValue().getNotification().flags
7067                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
7068                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
7069     }
7070 
7071     @Test
testBumpFGImportance_channelChangePreOApp()7072     public void testBumpFGImportance_channelChangePreOApp() throws Exception {
7073         Notification.Builder nb = new Notification.Builder(mContext,
7074                 NotificationChannel.DEFAULT_CHANNEL_ID)
7075                 .setContentTitle("foo")
7076                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7077                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
7078                 .setPriority(Notification.PRIORITY_MIN);
7079 
7080         StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9,
7081                 "testBumpFGImportance_channelChangePreOApp",
7082                 Binder.getCallingUid(), 0, nb.build(),
7083                 UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
7084 
7085         mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
7086                 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
7087         waitForIdle();
7088 
7089         assertEquals(IMPORTANCE_LOW,
7090                 mService.getNotificationRecord(sbn.getKey()).getImportance());
7091         assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance(
7092                 sbn.getPackageName()));
7093 
7094         nb = new Notification.Builder(mContext)
7095                 .setContentTitle("foo")
7096                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7097                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
7098                 .setPriority(Notification.PRIORITY_MIN);
7099 
7100         sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9,
7101                 "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(),
7102                 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
7103 
7104         mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1,
7105                 "testBumpFGImportance_channelChangePreOApp",
7106                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
7107         waitForIdle();
7108         assertEquals(IMPORTANCE_LOW,
7109                 mService.getNotificationRecord(sbn.getKey()).getImportance());
7110 
7111         NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
7112                 PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID);
7113         assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance());
7114     }
7115 
7116     @Test
testStats_updatedOnDirectReply()7117     public void testStats_updatedOnDirectReply() throws Exception {
7118         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7119         mService.addNotification(r);
7120 
7121         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7122         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied());
7123         verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r));
7124 
7125         assertEquals(1, mNotificationRecordLogger.numCalls());
7126         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
7127                 mNotificationRecordLogger.event(0));
7128     }
7129 
7130     @Test
7131     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate()7132     public void testStats_DirectReplyLifetimeExtendedPostsUpdate() throws Exception {
7133         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7134         // Marks the notification as having already been lifetime extended and canceled.
7135         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7136         r.setCanceledAfterLifetimeExtension(true);
7137         r.setPostSilently(true);
7138         mService.addNotification(r);
7139 
7140         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7141         waitForIdle();
7142 
7143         // At the moment prepareNotifyPostedLocked is called on the listeners,
7144         // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial
7145         // values.
7146         doAnswer(
7147                 invocation -> {
7148                     int flags = ((NotificationRecord) invocation.getArgument(0))
7149                             .getSbn().getNotification().flags;
7150                     assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
7151                     boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0))
7152                             .shouldPostSilently();
7153                     assertThat(shouldPostSilently).isTrue();
7154                     return null;
7155                 }
7156         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
7157 
7158         // Checks that the record gets marked as a direct reply having occurred.
7159         assertThat(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied())
7160                 .isTrue();
7161         // Checks that a post update is sent.
7162         verify(mWorkerHandler, times(1))
7163                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
7164         ArgumentCaptor<NotificationRecord> captor =
7165                 ArgumentCaptor.forClass(NotificationRecord.class);
7166         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
7167                 anyBoolean());
7168         assertThat(captor.getValue().getNotification().flags
7169                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
7170                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
7171         // FLAG_ONLY_ALERT_ONCE was not present on the original notification, so it's not here.
7172         assertThat(captor.getValue().getNotification().flags
7173                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0);
7174         assertThat(captor.getValue().shouldPostSilently()).isTrue();
7175         assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isTrue();
7176     }
7177 
7178     @Test
7179     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently()7180     public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently()
7181             throws Exception {
7182         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7183         // Marks the notification as having already been lifetime extended and canceled.
7184         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7185         r.setPostSilently(false);
7186         mService.addNotification(r);
7187 
7188         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7189         waitForIdle();
7190 
7191         // Checks that a post update is sent with shouldPostSilently set to true.
7192         doAnswer(
7193                 invocation -> {
7194                     boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0))
7195                             .shouldPostSilently();
7196                     assertThat(shouldPostSilently).isTrue();
7197                     return null;
7198                 }
7199         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
7200 
7201         // Checks that shouldPostSilently is restored to its false state afterward.
7202         assertThat(mService.getNotificationRecord(r.getKey()).shouldPostSilently()).isFalse();
7203     }
7204 
7205     @Test
7206     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag()7207     public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag()
7208             throws Exception {
7209         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7210         // Marks the notification as having already been lifetime extended and canceled.
7211         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7212         mService.addNotification(r);
7213 
7214         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
7215         waitForIdle();
7216 
7217         // Checks that a post update is sent with FLAG_ONLY_ALERT_ONCE set to true.
7218         doAnswer(
7219                 invocation -> {
7220                     int flags = ((NotificationRecord) invocation.getArgument(0))
7221                             .getSbn().getNotification().flags;
7222                     assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
7223                     return null;
7224                 }
7225         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
7226 
7227         // Checks that the flag is removed afterward.
7228         assertThat(mService.getNotificationRecord(r.getKey()).getSbn().getNotification().flags
7229                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0);
7230     }
7231 
7232     @Test
7233     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds()7234     public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception {
7235         // Creates a lifetime extended notification.
7236         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
7237         original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
7238         mService.addNotification(original);
7239 
7240         // Post an update for that notification.
7241         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
7242                 original.getSbn().getTag(), mUid, 0,
7243                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
7244                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
7245                         .setContentTitle("new title").build(),
7246                 UserHandle.getUserHandleForUid(mUid), null, 0);
7247         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7248         mService.addEnqueuedNotification(update);
7249 
7250         NotificationManagerService.PostNotificationRunnable runnable =
7251                 mService.new PostNotificationRunnable(update.getKey(),
7252                         update.getSbn().getPackageName(),
7253                         update.getUid(),
7254                         mPostNotificationTrackerFactory.newTracker(null));
7255         runnable.run();
7256         waitForIdle();
7257 
7258         // Checks the update was sent, and that update contains the new title, and does not contain
7259         // the lifetime extension flag.
7260         ArgumentCaptor<NotificationRecord> captor =
7261                 ArgumentCaptor.forClass(NotificationRecord.class);
7262         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
7263                 anyBoolean());
7264         assertThat(captor.getValue().getNotification().flags
7265                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
7266         assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isFalse();
7267         assertThat(captor.getValue()
7268                 .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString())
7269                 .isEqualTo("new title");
7270     }
7271 
7272     @Test
testStats_updatedOnUserExpansion()7273     public void testStats_updatedOnUserExpansion() throws Exception {
7274         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7275         mService.addNotification(r);
7276 
7277         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true,
7278                 NOTIFICATION_LOCATION_UNKNOWN);
7279         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
7280                 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true)));
7281         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7282 
7283         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false,
7284                 NOTIFICATION_LOCATION_UNKNOWN);
7285         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
7286                 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false)));
7287         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7288 
7289         assertEquals(2, mNotificationRecordLogger.numCalls());
7290         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER,
7291                 mNotificationRecordLogger.event(0));
7292         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER,
7293                 mNotificationRecordLogger.event(1));
7294     }
7295 
7296     @Test
testStats_notUpdatedOnAutoExpansion()7297     public void testStats_notUpdatedOnAutoExpansion() throws Exception {
7298         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7299         mService.addNotification(r);
7300 
7301         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
7302                 NOTIFICATION_LOCATION_UNKNOWN);
7303         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7304         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
7305                 eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true)));
7306 
7307         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false,
7308                 NOTIFICATION_LOCATION_UNKNOWN);
7309         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
7310         verify(mAssistants).notifyAssistantExpansionChangedLocked(
7311                 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false)));
7312     }
7313 
7314     @Test
testStats_updatedOnViewSettings()7315     public void testStats_updatedOnViewSettings() throws Exception {
7316         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7317         mService.addNotification(r);
7318 
7319         mService.mNotificationDelegate.onNotificationSettingsViewed(r.getKey());
7320         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasViewedSettings());
7321     }
7322 
7323     @Test
testStats_updatedOnVisibilityChanged()7324     public void testStats_updatedOnVisibilityChanged() throws Exception {
7325         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7326         mService.addNotification(r);
7327 
7328         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true);
7329         mService.mNotificationDelegate.onNotificationVisibilityChanged(
7330                 new NotificationVisibility[] {nv}, new NotificationVisibility[]{});
7331         verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true));
7332         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
7333         mService.mNotificationDelegate.onNotificationVisibilityChanged(
7334                 new NotificationVisibility[] {}, new NotificationVisibility[]{nv});
7335         verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false));
7336         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
7337     }
7338 
7339     @Test
testStats_dismissalSurface()7340     public void testStats_dismissalSurface() throws Exception {
7341         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7342         r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7343         mService.addNotification(r);
7344 
7345         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
7346         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(),
7347                 r.getKey(), NotificationStats.DISMISSAL_AOD,
7348                 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv);
7349         waitForIdle();
7350 
7351         assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface());
7352 
7353         // Using mService.addNotification() does not generate a NotificationRecordLogger log,
7354         // so we only get the cancel notification.
7355         assertEquals(1, mNotificationRecordLogger.numCalls());
7356 
7357         assertEquals(
7358                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
7359                 mNotificationRecordLogger.event(0));
7360         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
7361     }
7362 
7363     @Test
testStats_dismissalSentiment()7364     public void testStats_dismissalSentiment() throws Exception {
7365         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7366         mService.addNotification(r);
7367 
7368         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
7369         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(),
7370                 r.getKey(), NotificationStats.DISMISSAL_AOD,
7371                 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv);
7372         waitForIdle();
7373 
7374         assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE,
7375                 r.getStats().getDismissalSentiment());
7376     }
7377 
7378     @Test
testTextChangedSet_forNewNotifs()7379     public void testTextChangedSet_forNewNotifs() throws Exception {
7380         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
7381         mService.addEnqueuedNotification(original);
7382 
7383         NotificationManagerService.PostNotificationRunnable runnable =
7384                 mService.new PostNotificationRunnable(original.getKey(),
7385                         original.getSbn().getPackageName(),
7386                         original.getUid(),
7387                         mPostNotificationTrackerFactory.newTracker(null));
7388         runnable.run();
7389         waitForIdle();
7390 
7391         assertTrue(original.isTextChanged());
7392     }
7393 
7394     @Test
testVisuallyInterruptive_notSeen()7395     public void testVisuallyInterruptive_notSeen() throws Exception {
7396         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
7397         mService.addNotification(original);
7398 
7399         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
7400                 original.getSbn().getTag(), mUid, 0,
7401                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
7402                         .setContentTitle("new title").build(),
7403                 UserHandle.getUserHandleForUid(mUid), null, 0);
7404         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
7405         mService.addEnqueuedNotification(update);
7406 
7407         NotificationManagerService.PostNotificationRunnable runnable =
7408                 mService.new PostNotificationRunnable(update.getKey(),
7409                         update.getSbn().getPackageName(),
7410                         update.getUid(),
7411                         mPostNotificationTrackerFactory.newTracker(null));
7412         runnable.run();
7413         waitForIdle();
7414 
7415         assertFalse(update.isInterruptive());
7416     }
7417 
7418     @Test
testApplyAdjustmentMultiUser()7419     public void testApplyAdjustmentMultiUser() throws Exception {
7420         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7421         mService.addNotification(r);
7422         NotificationManagerService.WorkerHandler handler = mock(
7423                 NotificationManagerService.WorkerHandler.class);
7424         mService.setHandler(handler);
7425 
7426         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false);
7427 
7428         Bundle signals = new Bundle();
7429         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7430                 USER_SENTIMENT_NEGATIVE);
7431         Adjustment adjustment = new Adjustment(
7432                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7433         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
7434 
7435         waitForIdle();
7436 
7437         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
7438     }
7439 
7440     @Test
testAssistantBlockingTriggersCancel()7441     public void testAssistantBlockingTriggersCancel() throws Exception {
7442         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7443         mService.addNotification(r);
7444         NotificationManagerService.WorkerHandler handler = mock(
7445                 NotificationManagerService.WorkerHandler.class);
7446         mService.setHandler(handler);
7447 
7448         Bundle signals = new Bundle();
7449         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE);
7450         Adjustment adjustment = new Adjustment(
7451                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7452         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
7453         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
7454 
7455         waitForIdle();
7456 
7457         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
7458         verify(handler, times(1)).scheduleCancelNotification(any(), eq(0));
7459     }
7460 
7461     @Test
testApplyEnqueuedAdjustmentFromAssistant_singleUser()7462     public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception {
7463         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7464         mService.addEnqueuedNotification(r);
7465         NotificationManagerService.WorkerHandler handler = mock(
7466                 NotificationManagerService.WorkerHandler.class);
7467         mService.setHandler(handler);
7468         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7469 
7470         Bundle signals = new Bundle();
7471         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7472                 USER_SENTIMENT_NEGATIVE);
7473         Adjustment adjustment = new Adjustment(
7474                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7475         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7476 
7477         assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
7478     }
7479 
7480     @Test
testApplyEnqueuedAdjustmentFromAssistant_importance()7481     public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception {
7482         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7483         mService.addEnqueuedNotification(r);
7484         NotificationManagerService.WorkerHandler handler = mock(
7485                 NotificationManagerService.WorkerHandler.class);
7486         mService.setHandler(handler);
7487         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7488 
7489         Bundle signals = new Bundle();
7490         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
7491         Adjustment adjustment = new Adjustment(
7492                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7493         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7494 
7495         assertEquals(IMPORTANCE_LOW, r.getImportance());
7496     }
7497 
7498     @Test
testApplyEnqueuedAdjustmentFromAssistant_crossUser()7499     public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception {
7500         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7501         mService.addEnqueuedNotification(r);
7502         NotificationManagerService.WorkerHandler handler = mock(
7503                 NotificationManagerService.WorkerHandler.class);
7504         mService.setHandler(handler);
7505         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false);
7506 
7507         Bundle signals = new Bundle();
7508         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7509                 USER_SENTIMENT_NEGATIVE);
7510         Adjustment adjustment = new Adjustment(
7511                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7512         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7513 
7514         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
7515 
7516         waitForIdle();
7517 
7518         verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
7519     }
7520 
7521     @Test
testUserSentimentChangeTriggersUpdate()7522     public void testUserSentimentChangeTriggersUpdate() throws Exception {
7523         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7524         mService.addNotification(r);
7525         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7526 
7527         Bundle signals = new Bundle();
7528         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7529                 USER_SENTIMENT_NEGATIVE);
7530         Adjustment adjustment = new Adjustment(
7531                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7532         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
7533 
7534         waitForIdle();
7535 
7536         verify(mRankingHandler, timeout(300).times(1)).requestSort();
7537     }
7538 
7539     @Test
testTooLateAdjustmentTriggersUpdate()7540     public void testTooLateAdjustmentTriggersUpdate() throws Exception {
7541         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7542         mService.addNotification(r);
7543         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7544 
7545         Bundle signals = new Bundle();
7546         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7547                 USER_SENTIMENT_NEGATIVE);
7548         Adjustment adjustment = new Adjustment(
7549                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7550         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7551 
7552         waitForIdle();
7553 
7554         verify(mRankingHandler, times(1)).requestSort();
7555     }
7556 
7557     @Test
testApplyAdjustmentsLogged()7558     public void testApplyAdjustmentsLogged() throws Exception {
7559         NotificationManagerService.WorkerHandler handler = mock(
7560                 NotificationManagerService.WorkerHandler.class);
7561         mService.setHandler(handler);
7562         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7563 
7564         // Set up notifications that will be adjusted
7565         final NotificationRecord r1 = generateNotificationRecord(
7566                 mTestNotificationChannel, 1, null, true);
7567         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7568         mService.addNotification(r1);
7569         final NotificationRecord r2 = generateNotificationRecord(
7570                 mTestNotificationChannel, 2, null, true);
7571         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7572         mService.addNotification(r2);
7573 
7574         // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously
7575         // logged.
7576         final NotificationRecord r3 = generateNotificationRecord(
7577                 mTestNotificationChannel, 3, null, true);
7578         r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7579         mService.addNotification(r3);
7580 
7581         List<Adjustment> adjustments = new ArrayList<>();
7582 
7583         // Test an adjustment that's associated with a ranking change and one that's not
7584         Bundle signals1 = new Bundle();
7585         signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH);
7586         Adjustment adjustment1 = new Adjustment(
7587                 r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
7588                 r1.getUser().getIdentifier());
7589         adjustments.add(adjustment1);
7590 
7591         // This one wouldn't trigger a ranking change, but should still trigger a log.
7592         Bundle signals2 = new Bundle();
7593         signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f);
7594         Adjustment adjustment2 = new Adjustment(
7595                 r2.getSbn().getPackageName(), r2.getKey(), signals2, "",
7596                 r2.getUser().getIdentifier());
7597         adjustments.add(adjustment2);
7598 
7599         mBinderService.applyAdjustmentsFromAssistant(null, adjustments);
7600         verify(mRankingHandler, times(1)).requestSort();
7601 
7602         // Actually apply the adjustments & recalculate importance when run
7603         doAnswer(invocationOnMock -> {
7604             ((NotificationRecord) invocationOnMock.getArguments()[0])
7605                     .applyAdjustments();
7606             ((NotificationRecord) invocationOnMock.getArguments()[0])
7607                     .calculateImportance();
7608             return null;
7609         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
7610 
7611         // Now make sure that when the sort happens, we actually log the changes.
7612         mService.handleRankingSort();
7613 
7614         // Even though the ranking score change is not meant to trigger a ranking update,
7615         // during this process the package visibility & canShowBadge values are changing
7616         // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead
7617         // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed
7618         // accordingly to confirm the adjustments happened to the 2 relevant notifications.
7619         verify(handler, times(3)).scheduleSendRankingUpdate();
7620         assertEquals(IMPORTANCE_HIGH, r1.getImportance());
7621         assertTrue(r2.rankingScoreMatches(-0.5f));
7622         assertEquals(2, mNotificationRecordLogger.numCalls());
7623         assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(0));
7624         assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(1));
7625         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
7626         assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId());
7627     }
7628 
7629     @Test
testSensitiveAdjustmentsLogged()7630     public void testSensitiveAdjustmentsLogged() throws Exception {
7631         NotificationManagerService.WorkerHandler handler = mock(
7632                 NotificationManagerService.WorkerHandler.class);
7633         mService.setHandler(handler);
7634         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
7635         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
7636 
7637         // Set up notifications that will be adjusted
7638         final NotificationRecord r1 = spy(generateNotificationRecord(
7639                 mTestNotificationChannel, 1, null, true));
7640         when(r1.getLifespanMs(anyLong())).thenReturn(1);
7641 
7642         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7643         mService.addEnqueuedNotification(r1);
7644 
7645         // Test an adjustment for an enqueued notification
7646         Bundle signals = new Bundle();
7647         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true);
7648         Adjustment adjustment1 = new Adjustment(
7649                 r1.getSbn().getPackageName(), r1.getKey(), signals, "",
7650                 r1.getUser().getIdentifier());
7651         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1);
7652         assertTrue(mService.checkLastSensitiveLog(false, true, 1));
7653 
7654         // Set up notifications that will be adjusted
7655         final NotificationRecord r2 = spy(generateNotificationRecord(
7656                 mTestNotificationChannel, 1, null, true));
7657         when(r2.getLifespanMs(anyLong())).thenReturn(2);
7658 
7659         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7660         mService.addNotification(r2);
7661         Adjustment adjustment2 = new Adjustment(
7662                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7663                 r2.getUser().getIdentifier());
7664         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2);
7665         assertTrue(mService.checkLastSensitiveLog(true, true, 2));
7666 
7667         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, false);
7668         Adjustment adjustment3 = new Adjustment(
7669                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7670                 r2.getUser().getIdentifier());
7671         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3);
7672         assertTrue(mService.checkLastSensitiveLog(true, false, 2));
7673     }
7674 
7675     @Test
7676     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testClassificationChannelAdjustmentsLogged()7677     public void testClassificationChannelAdjustmentsLogged() throws Exception {
7678         NotificationManagerService.WorkerHandler handler = mock(
7679                 NotificationManagerService.WorkerHandler.class);
7680         mService.setHandler(handler);
7681         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
7682         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
7683         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
7684         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
7685 
7686         // Set up notifications that will be adjusted
7687         final NotificationRecord r1 = spy(generateNotificationRecord(
7688                 mTestNotificationChannel, 1, null, true));
7689         when(r1.getLifespanMs(anyLong())).thenReturn(234);
7690 
7691         InstanceId instanceId1 = mNotificationInstanceIdSequence.newInstanceId();
7692         r1.getSbn().setInstanceId(instanceId1);
7693         // Enqueues the notification to be posted, so hasPosted will be false.
7694         mService.addEnqueuedNotification(r1);
7695 
7696         // Test an adjustment for an enqueued notification
7697         Bundle signals = new Bundle();
7698         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
7699         Adjustment adjustment1 = new Adjustment(
7700                 r1.getSbn().getPackageName(), r1.getKey(), signals, "",
7701                 r1.getUser().getIdentifier());
7702         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1);
7703         assertTrue(mService.checkLastClassificationChannelLog(false /*=hasPosted*/,
7704                 true /*=isAlerting*/, Adjustment.TYPE_NEWS, 234,
7705                 NOTIFICATION_ADJUSTED.getId(),
7706                 instanceId1.getId(), r1.getUid()));
7707 
7708         // Set up notifications that will be adjusted
7709         // This notification starts on a low importance channel, so isAlerting is false.
7710         NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel(
7711                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW);
7712         final NotificationRecord r2 = spy(generateNotificationRecord(
7713                 mLowImportanceNotificationChannel, 1, null, true));
7714         when(r2.getLifespanMs(anyLong())).thenReturn(345);
7715 
7716         InstanceId instanceId2 = mNotificationInstanceIdSequence.newInstanceId();
7717         r2.getSbn().setInstanceId(instanceId2);
7718         // Adds the notification as already posted, so hasPosted will be true.
7719         mService.addNotification(r2);
7720         // The signal is removed when used so it has to be readded.
7721         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
7722         Adjustment adjustment2 = new Adjustment(
7723                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7724                 r2.getUser().getIdentifier());
7725         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2);
7726         assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/,
7727                 false /*isAlerting*/, Adjustment.TYPE_NEWS, 345,
7728                 NOTIFICATION_ADJUSTED.getId(),
7729                 instanceId2.getId() /*instance_id*/, r2.getUid()));
7730 
7731         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION);
7732         Adjustment adjustment3 = new Adjustment(
7733                 r2.getSbn().getPackageName(), r2.getKey(), signals, "",
7734                 r2.getUser().getIdentifier());
7735         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3);
7736         assertTrue(mService.checkLastClassificationChannelLog(true /*=hasPosted*/,
7737                 false /*=isAlerting*/, Adjustment.TYPE_PROMOTION, 345,
7738                 NOTIFICATION_ADJUSTED.getId(),
7739                 instanceId2.getId() /*instance_id*/, r2.getUid()));
7740     }
7741 
7742     @Test
testAdjustmentToImportanceNone_cancelsNotification()7743     public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception {
7744         NotificationManagerService.WorkerHandler handler = mock(
7745                 NotificationManagerService.WorkerHandler.class);
7746         mService.setHandler(handler);
7747         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7748         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
7749 
7750         // Set up notifications: r1 is adjusted, r2 is not
7751         final NotificationRecord r1 = generateNotificationRecord(
7752                 mTestNotificationChannel, 1, null, true);
7753         r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7754         mService.addNotification(r1);
7755         final NotificationRecord r2 = generateNotificationRecord(
7756                 mTestNotificationChannel, 2, null, true);
7757         r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
7758         mService.addNotification(r2);
7759 
7760         // Test an adjustment that sets importance to none (meaning it's cancelling)
7761         Bundle signals1 = new Bundle();
7762         signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
7763         Adjustment adjustment1 = new Adjustment(
7764                 r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
7765                 r1.getUser().getIdentifier());
7766 
7767         mBinderService.applyAdjustmentFromAssistant(null, adjustment1);
7768 
7769         // Actually apply the adjustments & recalculate importance when run
7770         doAnswer(invocationOnMock -> {
7771             ((NotificationRecord) invocationOnMock.getArguments()[0])
7772                     .applyAdjustments();
7773             ((NotificationRecord) invocationOnMock.getArguments()[0])
7774                     .calculateImportance();
7775             return null;
7776         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
7777 
7778         // run the CancelNotificationRunnable when it happens
7779         ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor =
7780                 ArgumentCaptor.forClass(
7781                         NotificationManagerService.CancelNotificationRunnable.class);
7782 
7783         verify(handler, times(1)).scheduleCancelNotification(
7784                 captor.capture(), eq(0));
7785 
7786         // Run the runnable given to the cancel notification, and see if it logs properly
7787         NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue();
7788         runnable.run();
7789         assertEquals(1, mNotificationRecordLogger.numCalls());
7790         assertEquals(
7791                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT,
7792                 mNotificationRecordLogger.event(0));
7793     }
7794 
7795     @Test
testEnqueuedAdjustmentAppliesAdjustments()7796     public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
7797         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
7798         mService.addEnqueuedNotification(r);
7799         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7800 
7801         Bundle signals = new Bundle();
7802         signals.putInt(Adjustment.KEY_USER_SENTIMENT,
7803                 USER_SENTIMENT_NEGATIVE);
7804         Adjustment adjustment = new Adjustment(
7805                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
7806         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7807 
7808         assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
7809     }
7810 
7811     @Test
testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications()7812     public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception {
7813         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel);
7814         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel);
7815         mService.addEnqueuedNotification(r1);
7816         mService.addEnqueuedNotification(r2);
7817         when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
7818 
7819         Bundle signals = new Bundle();
7820         signals.putInt(Adjustment.KEY_IMPORTANCE,
7821                 IMPORTANCE_HIGH);
7822         Adjustment adjustment = new Adjustment(
7823                 r1.getSbn().getPackageName(), r1.getKey(), signals,
7824                 "", r1.getUser().getIdentifier());
7825 
7826         mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
7827 
7828         assertEquals(IMPORTANCE_HIGH, r1.getImportance());
7829         assertEquals(IMPORTANCE_HIGH, r2.getImportance());
7830     }
7831 
7832     @Test
testRestore()7833     public void testRestore() throws Exception {
7834         int systemChecks = mService.countSystemChecks;
7835         mBinderService.applyRestore(null, USER_SYSTEM);
7836         assertEquals(1, mService.countSystemChecks - systemChecks);
7837     }
7838 
7839     @Test
testBackupEmptySound()7840     public void testBackupEmptySound() throws Exception {
7841         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
7842         channel.setSound(Uri.EMPTY, null);
7843 
7844         TypedXmlSerializer serializer = Xml.newFastSerializer();
7845         ByteArrayOutputStream baos = new ByteArrayOutputStream();
7846         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
7847         channel.writeXmlForBackup(serializer, getContext());
7848 
7849         TypedXmlPullParser parser = Xml.newFastPullParser();
7850         parser.setInput(new BufferedInputStream(
7851                 new ByteArrayInputStream(baos.toByteArray())), null);
7852         NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
7853         restored.populateFromXmlForRestore(parser, true, getContext());
7854 
7855         assertNull(restored.getSound());
7856     }
7857 
7858     @Test
testBackup()7859     public void testBackup() throws Exception {
7860         mService.setPreferencesHelper(mPreferencesHelper);
7861         int systemChecks = mService.countSystemChecks;
7862         when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
7863                 .thenReturn(new ArraySet<>());
7864         mBinderService.getBackupPayload(1);
7865         assertEquals(1, mService.countSystemChecks - systemChecks);
7866     }
7867 
7868     @Test
testEmptyVibration_noException()7869     public void testEmptyVibration_noException() throws Exception {
7870         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
7871         channel.setVibrationPattern(new long[0]);
7872 
7873         TypedXmlSerializer serializer = Xml.newFastSerializer();
7874         ByteArrayOutputStream baos = new ByteArrayOutputStream();
7875         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
7876         channel.writeXml(serializer);
7877     }
7878 
7879     @Test
updateUriPermissions_update()7880     public void updateUriPermissions_update() throws Exception {
7881         NotificationChannel c = new NotificationChannel(
7882                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
7883         c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
7884         Message message1 = new Message("", 0, "");
7885         message1.setData("",
7886                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1));
7887         Message message2 = new Message("", 1, "");
7888         message2.setData("",
7889                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2));
7890 
7891         Notification.Builder nbA = new Notification.Builder(mContext, c.getId())
7892                 .setContentTitle("foo")
7893                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7894                 .setStyle(new Notification.MessagingStyle("")
7895                         .addMessage(message1)
7896                         .addMessage(message2));
7897         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
7898                 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
7899                 null, 0), c);
7900 
7901         // First post means we grant access to both
7902         reset(mUgm);
7903         reset(mUgmInternal);
7904         when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
7905         mService.updateUriPermissions(recordA, null, mContext.getPackageName(),
7906                 USER_SYSTEM);
7907         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
7908                 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
7909         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
7910                 eq(message2.getDataUri()), anyInt(), anyInt(), anyInt());
7911 
7912         Notification.Builder nbB = new Notification.Builder(mContext, c.getId())
7913                 .setContentTitle("foo")
7914                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7915                 .setStyle(new Notification.MessagingStyle("").addMessage(message2));
7916         NotificationRecord recordB =
7917                 new NotificationRecord(
7918                         mContext,
7919                         new StatusBarNotification(
7920                                 mPkg,
7921                                 mPkg,
7922                                 0,
7923                                 "tag",
7924                                 mUid,
7925                                 0,
7926                                 nbB.build(),
7927                                 UserHandle.getUserHandleForUid(mUid),
7928                                 null,
7929                                 0),
7930                         c);
7931 
7932         // Update means we drop access to first
7933         reset(mUgmInternal);
7934         mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(),
7935                 USER_SYSTEM);
7936         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(),
7937                 eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1));
7938 
7939         // Update back means we grant access to first again
7940         reset(mUgm);
7941         mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(),
7942                 USER_SYSTEM);
7943         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
7944                 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
7945 
7946         // And update to empty means we drop everything
7947         reset(mUgmInternal);
7948         mService.updateUriPermissions(null, recordB, mContext.getPackageName(),
7949                 USER_SYSTEM);
7950         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null),
7951                 anyInt(), anyInt());
7952     }
7953 
7954     @Test
updateUriPermissions_posterDoesNotOwnUri()7955     public void updateUriPermissions_posterDoesNotOwnUri() throws Exception {
7956         NotificationChannel c = new NotificationChannel(
7957                 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
7958         c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
7959         Message message1 = new Message("", 0, "");
7960         message1.setData("",
7961                 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1));
7962 
7963         Notification.Builder nbA = new Notification.Builder(mContext, c.getId())
7964                 .setContentTitle("foo")
7965                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
7966                 .setStyle(new Notification.MessagingStyle("")
7967                         .addMessage(message1));
7968         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
7969                 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
7970                 null, 0), c);
7971 
7972         doThrow(new SecurityException("no access")).when(mUgm)
7973                 .grantUriPermissionFromOwner(
7974                         any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt());
7975 
7976         when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
7977         mService.updateUriPermissions(recordA, null, mContext.getPackageName(),  USER_SYSTEM);
7978 
7979         // yay, no crash
7980     }
7981 
7982     @Test
testVisitUris()7983     public void testVisitUris() throws Exception {
7984         final Uri audioContents = Uri.parse("content://com.example/audio");
7985         final Uri backgroundImage = Uri.parse("content://com.example/background");
7986         final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon");
7987         final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon");
7988         final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
7989         final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
7990         final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
7991         final Person person1 = new Person.Builder()
7992                 .setName("Messaging Person")
7993                 .setIcon(personIcon1)
7994                 .build();
7995         final Person person2 = new Person.Builder()
7996                 .setName("People List Person 1")
7997                 .setIcon(personIcon2)
7998                 .build();
7999         final Person person3 = new Person.Builder()
8000                 .setName("People List Person 2")
8001                 .setIcon(personIcon3)
8002                 .build();
8003         final Uri historyUri1 = Uri.parse("content://com.example/history1");
8004         final Uri historyUri2 = Uri.parse("content://com.example/history2");
8005         final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1,
8006                 "a");
8007         final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2,
8008                 "b");
8009 
8010         Bundle extras = new Bundle();
8011         extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents);
8012         extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString());
8013         extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1);
8014         extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST,
8015                 new ArrayList<>(Arrays.asList(person2, person3)));
8016         extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
8017                 new RemoteInputHistoryItem[]{historyItem1, historyItem2});
8018 
8019         Notification n = new Notification.Builder(mContext, "a")
8020                 .setContentTitle("notification with uris")
8021                 .setSmallIcon(smallIcon)
8022                 .setLargeIcon(largeIcon)
8023                 .addExtras(extras)
8024                 .build();
8025 
8026         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8027         n.visitUris(visitor);
8028         verify(visitor, times(1)).accept(eq(audioContents));
8029         verify(visitor, times(1)).accept(eq(backgroundImage));
8030         verify(visitor, times(1)).accept(eq(smallIcon.getUri()));
8031         verify(visitor, times(1)).accept(eq(largeIcon.getUri()));
8032         verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
8033         verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
8034         verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
8035         verify(visitor, times(1)).accept(eq(historyUri1));
8036         verify(visitor, times(1)).accept(eq(historyUri2));
8037     }
8038 
8039     @Test
testVisitUris_publicVersion()8040     public void testVisitUris_publicVersion() throws Exception {
8041         final Icon smallIconPublic = Icon.createWithContentUri("content://media/small/icon");
8042         final Icon largeIconPrivate = Icon.createWithContentUri("content://media/large/icon");
8043 
8044         Notification publicVersion = new Notification.Builder(mContext, "a")
8045                 .setContentTitle("notification with uris")
8046                 .setSmallIcon(smallIconPublic)
8047                 .build();
8048         Notification n = new Notification.Builder(mContext, "a")
8049                 .setLargeIcon(largeIconPrivate)
8050                 .setPublicVersion(publicVersion)
8051                 .build();
8052 
8053         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8054         n.visitUris(visitor);
8055         verify(visitor, times(1)).accept(eq(smallIconPublic.getUri()));
8056         verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri()));
8057     }
8058 
8059     @Test
testVisitUris_audioContentsString()8060     public void testVisitUris_audioContentsString() throws Exception {
8061         final Uri audioContents = Uri.parse("content://com.example/audio");
8062 
8063         Bundle extras = new Bundle();
8064         extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString());
8065 
8066         Notification n = new Notification.Builder(mContext, "a")
8067                 .setContentTitle("notification with uris")
8068                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
8069                 .addExtras(extras)
8070                 .build();
8071 
8072         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8073         n.visitUris(visitor);
8074         verify(visitor, times(1)).accept(eq(audioContents));
8075     }
8076 
8077     @Test
testVisitUris_messagingStyle()8078     public void testVisitUris_messagingStyle() {
8079         final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
8080         final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
8081         final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
8082         final Person person1 = new Person.Builder()
8083                 .setName("Messaging Person 1")
8084                 .setIcon(personIcon1)
8085                 .build();
8086         final Person person2 = new Person.Builder()
8087                 .setName("Messaging Person 2")
8088                 .setIcon(personIcon2)
8089                 .build();
8090         final Person person3 = new Person.Builder()
8091                 .setName("Messaging Person 3")
8092                 .setIcon(personIcon3)
8093                 .build();
8094         Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut");
8095 
8096         Notification.Builder builder = new Notification.Builder(mContext, "a")
8097                 .setCategory(Notification.CATEGORY_MESSAGE)
8098                 .setContentTitle("new message!")
8099                 .setContentText("Conversation Notification")
8100                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8101         Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message(
8102                 "Marco?", System.currentTimeMillis(), person2);
8103         Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message(
8104                 "Polo!", System.currentTimeMillis(), person3);
8105         Notification.MessagingStyle style = new Notification.MessagingStyle(person1)
8106                 .addMessage(message1)
8107                 .addMessage(message2)
8108                 .setShortcutIcon(shortcutIcon);
8109         builder.setStyle(style);
8110         Notification n = builder.build();
8111 
8112         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8113         n.visitUris(visitor);
8114 
8115         verify(visitor, times(1)).accept(eq(shortcutIcon.getUri()));
8116         verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
8117         verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
8118         verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
8119     }
8120 
8121     @Test
testVisitUris_callStyle()8122     public void testVisitUris_callStyle() {
8123         Icon personIcon = Icon.createWithContentUri("content://media/person");
8124         Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
8125         Person callingPerson = new Person.Builder().setName("Someone")
8126                 .setIcon(personIcon)
8127                 .build();
8128         PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
8129                 PendingIntent.FLAG_IMMUTABLE);
8130         Notification n = new Notification.Builder(mContext, "a")
8131                 .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
8132                         .setVerificationIcon(verificationIcon))
8133                 .setContentTitle("Calling...")
8134                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
8135                 .build();
8136 
8137         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8138         n.visitUris(visitor);
8139 
8140         verify(visitor, times(1)).accept(eq(personIcon.getUri()));
8141         verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
8142         hangUpIntent.cancel();
8143     }
8144 
8145     @Test
testVisitUris_styleExtrasWithoutStyle()8146     public void testVisitUris_styleExtrasWithoutStyle() {
8147         Notification.Builder notification = new Notification.Builder(mContext, "a")
8148                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8149 
8150         Bundle messagingExtras = new Bundle();
8151         messagingExtras.putParcelable(Notification.EXTRA_MESSAGING_PERSON,
8152                 personWithIcon("content://user"));
8153         messagingExtras.putParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES,
8154                 new Bundle[] { new Notification.MessagingStyle.Message("Heyhey!",
8155                         System.currentTimeMillis() - 100,
8156                         personWithIcon("content://historicalMessenger")).toBundle()});
8157         messagingExtras.putParcelableArray(Notification.EXTRA_MESSAGES,
8158                 new Bundle[] { new Notification.MessagingStyle.Message("Are you there?",
8159                         System.currentTimeMillis(),
8160                         personWithIcon("content://messenger")).toBundle()});
8161         messagingExtras.putParcelable(Notification.EXTRA_CONVERSATION_ICON,
8162                 Icon.createWithContentUri("content://conversationShortcut"));
8163         notification.addExtras(messagingExtras);
8164 
8165         Bundle callExtras = new Bundle();
8166         callExtras.putParcelable(Notification.EXTRA_CALL_PERSON,
8167                 personWithIcon("content://caller"));
8168         callExtras.putParcelable(Notification.EXTRA_VERIFICATION_ICON,
8169                 Icon.createWithContentUri("content://callVerification"));
8170         notification.addExtras(callExtras);
8171 
8172         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8173         notification.build().visitUris(visitor);
8174 
8175         verify(visitor).accept(eq(Uri.parse("content://user")));
8176         verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
8177         verify(visitor).accept(eq(Uri.parse("content://messenger")));
8178         verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
8179         verify(visitor).accept(eq(Uri.parse("content://caller")));
8180         verify(visitor).accept(eq(Uri.parse("content://callVerification")));
8181     }
8182 
personWithIcon(String iconUri)8183     private static Person personWithIcon(String iconUri) {
8184         return new Person.Builder()
8185                 .setName("Mr " + iconUri)
8186                 .setIcon(Icon.createWithContentUri(iconUri))
8187                 .build();
8188     }
8189 
8190     @Test
testVisitUris_wearableExtender()8191     public void testVisitUris_wearableExtender() {
8192         Icon actionIcon = Icon.createWithContentUri("content://media/action");
8193         Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
8194         PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
8195                 PendingIntent.FLAG_IMMUTABLE);
8196         Notification n = new Notification.Builder(mContext, "a")
8197                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
8198                 .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
8199                 .extend(new Notification.WearableExtender().addAction(
8200                         new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
8201                 .build();
8202 
8203         Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
8204         n.visitUris(visitor);
8205 
8206         verify(visitor).accept(eq(actionIcon.getUri()));
8207         verify(visitor).accept(eq(wearActionIcon.getUri()));
8208     }
8209 
8210     @Test
testSetNotificationPolicy_preP_setOldFields()8211     public void testSetNotificationPolicy_preP_setOldFields() {
8212         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8213         mService.mZenModeHelper = mZenModeHelper;
8214         NotificationManager.Policy userPolicy =
8215                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8216         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8217 
8218         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8219                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
8220 
8221         int expected = SUPPRESSED_EFFECT_BADGE
8222                 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
8223                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS
8224                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8225         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
8226 
8227         assertEquals(expected, actual);
8228     }
8229 
8230     @Test
testSetNotificationPolicy_preP_setNewFields()8231     public void testSetNotificationPolicy_preP_setNewFields() {
8232         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8233         mService.mZenModeHelper = mZenModeHelper;
8234         NotificationManager.Policy userPolicy =
8235                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8236         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8237 
8238         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8239                 SUPPRESSED_EFFECT_NOTIFICATION_LIST);
8240 
8241         int expected = SUPPRESSED_EFFECT_BADGE;
8242         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
8243 
8244         assertEquals(expected, actual);
8245     }
8246 
8247     @Test
testSetNotificationPolicy_preP_setOldNewFields()8248     public void testSetNotificationPolicy_preP_setOldNewFields() {
8249         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8250         mService.mZenModeHelper = mZenModeHelper;
8251         NotificationManager.Policy userPolicy =
8252                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8253         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8254 
8255         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8256                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
8257 
8258         int expected =
8259                 SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
8260         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
8261 
8262         assertEquals(expected, actual);
8263     }
8264 
8265     @Test
testSetNotificationPolicy_P_setOldFields()8266     public void testSetNotificationPolicy_P_setOldFields() {
8267         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8268         mService.mZenModeHelper = mZenModeHelper;
8269         NotificationManager.Policy userPolicy =
8270                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8271         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8272 
8273         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8274                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
8275 
8276         int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
8277                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
8278                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8279         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8280 
8281         assertEquals(expected, actual);
8282     }
8283 
8284     @Test
testSetNotificationPolicy_P_setNewFields()8285     public void testSetNotificationPolicy_P_setNewFields() {
8286         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8287         mService.mZenModeHelper = mZenModeHelper;
8288         NotificationManager.Policy userPolicy =
8289                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8290         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8291 
8292         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8293                 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
8294                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
8295 
8296         int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
8297                 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
8298                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8299         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8300 
8301         assertEquals(expected, actual);
8302     }
8303 
8304     @Test
testSetNotificationPolicy_P_setOldNewFields()8305     public void testSetNotificationPolicy_P_setOldNewFields() {
8306         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
8307         mService.mZenModeHelper = mZenModeHelper;
8308         NotificationManager.Policy userPolicy =
8309                 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
8310         when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy);
8311 
8312         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
8313                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
8314 
8315         int expected =  SUPPRESSED_EFFECT_STATUS_BAR;
8316         int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8317 
8318         assertEquals(expected, actual);
8319 
8320         appPolicy = new NotificationManager.Policy(0, 0, 0,
8321                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
8322                         | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
8323 
8324         expected =  SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
8325                 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
8326         actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
8327 
8328         assertEquals(expected, actual);
8329     }
8330 
8331     @Test
testVisualDifference_foreground()8332     public void testVisualDifference_foreground() {
8333         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8334                 .setContentTitle("foo");
8335         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8336                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8337         NotificationRecord r1 =
8338                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8339 
8340         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8341                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
8342                 .setContentTitle("bar");
8343         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8344                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8345         NotificationRecord r2 =
8346                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8347 
8348         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8349     }
8350 
8351     @Test
testVisualDifference_diffTitle()8352     public void testVisualDifference_diffTitle() {
8353         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8354                 .setContentTitle("foo");
8355         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8356                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8357         NotificationRecord r1 =
8358                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8359 
8360         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8361                 .setContentTitle("bar");
8362         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8363                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8364         NotificationRecord r2 =
8365                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8366 
8367         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8368     }
8369 
8370     @Test
testVisualDifference_inboxStyle()8371     public void testVisualDifference_inboxStyle() {
8372         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8373                 .setStyle(new Notification.InboxStyle()
8374                     .addLine("line1").addLine("line2"));
8375         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8376                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8377         NotificationRecord r1 =
8378                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8379 
8380         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8381                 .setStyle(new Notification.InboxStyle()
8382                         .addLine("line1").addLine("line2_changed"));
8383         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8384                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8385         NotificationRecord r2 =
8386                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8387 
8388         assertTrue(mService.isVisuallyInterruptive(r1, r2)); // line 2 changed unnoticed
8389 
8390         Notification.Builder nb3 = new Notification.Builder(mContext, "")
8391                 .setStyle(new Notification.InboxStyle()
8392                         .addLine("line1"));
8393         StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8394                 nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8395         NotificationRecord r3 =
8396                 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class));
8397 
8398         assertTrue(mService.isVisuallyInterruptive(r1, r3)); // line 2 removed unnoticed
8399 
8400         Notification.Builder nb4 = new Notification.Builder(mContext, "")
8401                 .setStyle(new Notification.InboxStyle()
8402                         .addLine("line1").addLine("line2").addLine("line3"));
8403         StatusBarNotification sbn4 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8404                 nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8405         NotificationRecord r4 =
8406                 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class));
8407 
8408         assertTrue(mService.isVisuallyInterruptive(r1, r4)); // line 3 added unnoticed
8409 
8410         Notification.Builder nb5 = new Notification.Builder(mContext, "")
8411             .setContentText("not an inbox");
8412         StatusBarNotification sbn5 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8413                 nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8414         NotificationRecord r5 =
8415                 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class));
8416 
8417         assertTrue(mService.isVisuallyInterruptive(r1, r5)); // changed Styles, went unnoticed
8418     }
8419 
8420     @Test
testVisualDifference_diffText()8421     public void testVisualDifference_diffText() {
8422         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8423                 .setContentText("foo");
8424         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8425                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8426         NotificationRecord r1 =
8427                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8428 
8429         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8430                 .setContentText("bar");
8431         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8432                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8433         NotificationRecord r2 =
8434                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8435 
8436         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8437     }
8438 
8439     @Test
testVisualDifference_sameText()8440     public void testVisualDifference_sameText() {
8441         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8442                 .setContentText("foo");
8443         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8444                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8445         NotificationRecord r1 =
8446                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8447 
8448         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8449                 .setContentText("foo");
8450         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8451                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8452         NotificationRecord r2 =
8453                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8454 
8455         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8456     }
8457 
8458     @Test
testVisualDifference_sameTextButStyled()8459     public void testVisualDifference_sameTextButStyled() {
8460         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8461                 .setContentText(Html.fromHtml("<b>foo</b>"));
8462         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8463                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8464         NotificationRecord r1 =
8465                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8466 
8467         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8468                 .setContentText(Html.fromHtml("<b>foo</b>"));
8469         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8470                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8471         NotificationRecord r2 =
8472                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8473 
8474         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8475     }
8476 
8477     @Test
testVisualDifference_diffTextButStyled()8478     public void testVisualDifference_diffTextButStyled() {
8479         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8480                 .setContentText(Html.fromHtml("<b>foo</b>"));
8481         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8482                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8483         NotificationRecord r1 =
8484                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8485 
8486         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8487                 .setContentText(Html.fromHtml("<b>bar</b>"));
8488         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8489                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8490         NotificationRecord r2 =
8491                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8492 
8493         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8494     }
8495 
8496     @Test
testVisualDifference_diffProgress()8497     public void testVisualDifference_diffProgress() {
8498         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8499                 .setProgress(100, 90, false);
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                 .setProgress(100, 100, false);
8507         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8508                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8509         NotificationRecord r2 =
8510                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8511 
8512         assertTrue(mService.isVisuallyInterruptive(r1, r2));
8513     }
8514 
8515     @Test
testVisualDifference_diffProgressNotDone()8516     public void testVisualDifference_diffProgressNotDone() {
8517         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8518                 .setProgress(100, 90, false);
8519         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8520                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8521         NotificationRecord r1 =
8522                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8523 
8524         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8525                 .setProgress(100, 91, false);
8526         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8527                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8528         NotificationRecord r2 =
8529                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8530 
8531         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8532     }
8533 
8534     @Test
testVisualDifference_sameProgressStillDone()8535     public void testVisualDifference_sameProgressStillDone() {
8536         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8537                 .setProgress(100, 100, false);
8538         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8539                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8540         NotificationRecord r1 =
8541                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8542 
8543         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8544                 .setProgress(100, 100, false);
8545         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8546                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8547         NotificationRecord r2 =
8548                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8549 
8550         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8551     }
8552 
8553     @Test
testVisualDifference_summary()8554     public void testVisualDifference_summary() {
8555         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8556                 .setGroup("bananas")
8557                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
8558                 .setContentText("foo");
8559         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8560                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8561         NotificationRecord r1 =
8562                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8563 
8564         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8565                 .setGroup("bananas")
8566                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
8567                 .setContentText("bar");
8568         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8569                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8570         NotificationRecord r2 =
8571                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8572 
8573         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8574     }
8575 
8576     @Test
testVisualDifference_summaryNewNotification()8577     public void testVisualDifference_summaryNewNotification() {
8578         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8579                 .setGroup("bananas")
8580                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
8581                 .setContentText("bar");
8582         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8583                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8584         NotificationRecord r2 =
8585                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8586 
8587         assertFalse(mService.isVisuallyInterruptive(null, r2));
8588     }
8589 
8590     @Test
testVisualDifference_sameImages()8591     public void testVisualDifference_sameImages() {
8592         Icon large = Icon.createWithResource(mContext, 1);
8593         Notification n1 = new Notification.Builder(mContext, "channel")
8594                 .setSmallIcon(1).setLargeIcon(large).build();
8595         Notification n2 = new Notification.Builder(mContext, "channel")
8596                 .setSmallIcon(1).setLargeIcon(large).build();
8597 
8598         NotificationRecord r1 = notificationToRecord(n1);
8599         NotificationRecord r2 = notificationToRecord(n2);
8600 
8601         assertThat(mService.isVisuallyInterruptive(r1, r2)).isFalse();
8602     }
8603 
8604     @Test
testVisualDifference_differentSmallImage()8605     public void testVisualDifference_differentSmallImage() {
8606         Icon large = Icon.createWithResource(mContext, 1);
8607         Notification n1 = new Notification.Builder(mContext, "channel")
8608                 .setSmallIcon(1).setLargeIcon(large).build();
8609         Notification n2 = new Notification.Builder(mContext, "channel")
8610                 .setSmallIcon(2).setLargeIcon(large).build();
8611 
8612         NotificationRecord r1 = notificationToRecord(n1);
8613         NotificationRecord r2 = notificationToRecord(n2);
8614 
8615         assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue();
8616     }
8617 
8618     @Test
testVisualDifference_differentLargeImage()8619     public void testVisualDifference_differentLargeImage() {
8620         Icon large1 = Icon.createWithResource(mContext, 1);
8621         Icon large2 = Icon.createWithResource(mContext, 2);
8622         Notification n1 = new Notification.Builder(mContext, "channel")
8623                 .setSmallIcon(1).setLargeIcon(large1).build();
8624         Notification n2 = new Notification.Builder(mContext, "channel")
8625                 .setSmallIcon(1).setLargeIcon(large2).build();
8626 
8627         NotificationRecord r1 = notificationToRecord(n1);
8628         NotificationRecord r2 = notificationToRecord(n2);
8629 
8630         assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue();
8631     }
8632 
8633     @Test
8634     @EnableFlags({android.app.Flags.FLAG_SORT_SECTION_BY_TIME})
testVisualDifference_userInitiatedJob()8635     public void testVisualDifference_userInitiatedJob() {
8636         Notification.Builder nb1 = new Notification.Builder(mContext, "")
8637                 .setContentTitle("foo");
8638         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8639                 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8640         NotificationRecord r1 =
8641                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
8642 
8643         Notification.Builder nb2 = new Notification.Builder(mContext, "")
8644                 .setFlag(FLAG_USER_INITIATED_JOB, true)
8645                 .setContentTitle("bar");
8646         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0,
8647                 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
8648         NotificationRecord r2 =
8649                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
8650 
8651         assertFalse(mService.isVisuallyInterruptive(r1, r2));
8652     }
8653 
notificationToRecord(Notification n)8654     private NotificationRecord notificationToRecord(Notification n) {
8655         return new NotificationRecord(
8656                 mContext,
8657                 new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, n,
8658                         UserHandle.getUserHandleForUid(mUid), null, 0),
8659                 mock(NotificationChannel.class));
8660     }
8661 
8662     @Test
testHideAndUnhideNotificationsOnSuspendedPackageBroadcast()8663     public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
8664         // post 2 notification from this package
8665         final NotificationRecord notif1 = generateNotificationRecord(
8666                 mTestNotificationChannel, 1, null, true);
8667         final NotificationRecord notif2 = generateNotificationRecord(
8668                 mTestNotificationChannel, 2, null, false);
8669         mService.addNotification(notif1);
8670         mService.addNotification(notif2);
8671 
8672         // on broadcast, hide the 2 notifications
8673         simulatePackageSuspendBroadcast(true, mPkg, notif1.getUid());
8674         ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class);
8675         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
8676         assertEquals(2, captorHide.getValue().size());
8677 
8678         // on broadcast, unhide the 2 notifications
8679         simulatePackageSuspendBroadcast(false, mPkg, notif1.getUid());
8680         ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class);
8681         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
8682         assertEquals(2, captorUnhide.getValue().size());
8683     }
8684 
8685     @Test
testNoNotificationsHiddenOnSuspendedPackageBroadcast()8686     public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() {
8687         // post 2 notification from this package
8688         final NotificationRecord notif1 = generateNotificationRecord(
8689                 mTestNotificationChannel, 1, null, true);
8690         final NotificationRecord notif2 = generateNotificationRecord(
8691                 mTestNotificationChannel, 2, null, false);
8692         mService.addNotification(notif1);
8693         mService.addNotification(notif2);
8694 
8695         // on broadcast, nothing is hidden since no notifications are of package "test_package"
8696         simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid());
8697         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
8698         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
8699         assertEquals(0, captor.getValue().size());
8700     }
8701 
8702     @Test
testNotificationFromDifferentUserHidden()8703     public void testNotificationFromDifferentUserHidden() {
8704         // post 2 notification from this package
8705         final NotificationRecord notif1 = generateNotificationRecord(
8706                 mTestNotificationChannel, 1, null, true);
8707         final NotificationRecord notif2 = generateNotificationRecord(
8708                 mTestNotificationChannel, 2, null, false);
8709         mService.addNotification(notif1);
8710         mService.addNotification(notif2);
8711 
8712         // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG
8713         simulatePackageSuspendBroadcast(true, mPkg, 10);
8714         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
8715         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
8716         assertEquals(0, captor.getValue().size());
8717     }
8718 
8719     @Test
testHideAndUnhideNotificationsOnDistractingPackageBroadcast()8720     public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() {
8721         // Post 2 notifications from 2 packages
8722         NotificationRecord pkgA = new NotificationRecord(mContext,
8723                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
8724         mService.addNotification(pkgA);
8725         NotificationRecord pkgB = new NotificationRecord(mContext,
8726                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
8727         mService.addNotification(pkgB);
8728 
8729         // on broadcast, hide one of the packages
8730         simulatePackageDistractionBroadcast(
8731                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"},
8732                 new int[] {1000});
8733         ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
8734         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
8735         assertEquals(1, captorHide.getValue().size());
8736         assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
8737 
8738         // on broadcast, unhide the package
8739         simulatePackageDistractionBroadcast(
8740                 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"},
8741                 new int[] {1000});
8742         ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
8743         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
8744         assertEquals(1, captorUnhide.getValue().size());
8745         assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName());
8746     }
8747 
8748     @Test
testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg()8749     public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() {
8750         // Post 2 notifications from 2 packages
8751         NotificationRecord pkgA = new NotificationRecord(mContext,
8752                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
8753         mService.addNotification(pkgA);
8754         NotificationRecord pkgB = new NotificationRecord(mContext,
8755                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
8756         mService.addNotification(pkgB);
8757 
8758         // on broadcast, hide one of the packages
8759         simulatePackageDistractionBroadcast(
8760                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"},
8761                 new int[] {1000, 1001});
8762         ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
8763 
8764         // should be called only once.
8765         verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
8766         assertEquals(2, captorHide.getValue().size());
8767         assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
8768         assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName());
8769 
8770         // on broadcast, unhide the package
8771         simulatePackageDistractionBroadcast(
8772                 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"},
8773                 new int[] {1000, 1001});
8774         ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
8775 
8776         // should be called only once.
8777         verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
8778         assertEquals(2, captorUnhide.getValue().size());
8779         assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName());
8780         assertEquals("b", captorUnhide.getValue().get(1).getSbn().getPackageName());
8781     }
8782 
8783     @Test
testNoNotificationsHiddenOnDistractingPackageBroadcast()8784     public void testNoNotificationsHiddenOnDistractingPackageBroadcast() {
8785         // post notification from this package
8786         final NotificationRecord notif1 = generateNotificationRecord(
8787                 mTestNotificationChannel, 1, null, true);
8788         mService.addNotification(notif1);
8789 
8790         // on broadcast, nothing is hidden since no notifications are of package "test_package"
8791         simulatePackageDistractionBroadcast(
8792                 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"},
8793                 new int[]{notif1.getUid()});
8794         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
8795         verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
8796         assertEquals(0, captor.getValue().size());
8797     }
8798 
8799     @Test
testCanUseManagedServicesNullPkg()8800     public void testCanUseManagedServicesNullPkg() {
8801         assertEquals(true, mService.canUseManagedServices(null, 0, null));
8802     }
8803 
8804 
8805     @Test
testCanUseManagedServicesNoValidPkg()8806     public void testCanUseManagedServicesNoValidPkg() {
8807         assertEquals(true, mService.canUseManagedServices("d", 0, null));
8808     }
8809 
8810     @Test
testCanUseManagedServices_hasPermission()8811     public void testCanUseManagedServices_hasPermission() throws Exception {
8812         when(mPackageManager.checkPermission("perm", "pkg", 0))
8813                 .thenReturn(PackageManager.PERMISSION_GRANTED);
8814 
8815         assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm"));
8816     }
8817 
8818     @Test
testCanUseManagedServices_noPermission()8819     public void testCanUseManagedServices_noPermission() throws Exception {
8820         when(mPackageManager.checkPermission("perm", "pkg", 0))
8821                 .thenReturn(PackageManager.PERMISSION_DENIED);
8822 
8823         assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm"));
8824     }
8825 
8826     @Test
testCanUseManagedServices_permDoesNotMatter()8827     public void testCanUseManagedServices_permDoesNotMatter() {
8828         assertEquals(true, mService.canUseManagedServices("pkg", 0, null));
8829     }
8830 
8831     @Test
testOnNotificationVisibilityChanged_triggersInterruptionUsageStat()8832     public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() {
8833         final NotificationRecord r = generateNotificationRecord(
8834                 mTestNotificationChannel, 1, null, true);
8835         r.setTextChanged(true);
8836         mService.addNotification(r);
8837 
8838         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
8839                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
8840                 new NotificationVisibility[]{});
8841 
8842         verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
8843     }
8844 
8845     @Test
testOnNotificationVisibilityChanged_triggersVisibilityLog()8846     public void testOnNotificationVisibilityChanged_triggersVisibilityLog() {
8847         final NotificationRecord r = generateNotificationRecord(
8848                 mTestNotificationChannel, 1, null, true);
8849         r.setTextChanged(true);
8850         r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
8851         mService.addNotification(r);
8852 
8853         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
8854                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
8855                 new NotificationVisibility[]{});
8856 
8857         assertEquals(1, mNotificationRecordLogger.numCalls());
8858         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN,
8859                 mNotificationRecordLogger.event(0));
8860         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
8861 
8862         mService.mNotificationDelegate.onNotificationVisibilityChanged(
8863                 new NotificationVisibility[]{},
8864                 new NotificationVisibility[]
8865                         {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}
8866         );
8867 
8868         assertEquals(2, mNotificationRecordLogger.numCalls());
8869         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE,
8870                 mNotificationRecordLogger.event(1));
8871         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
8872     }
8873 
8874     @Test
testSetNotificationsShownFromListener_triggersInterruptionUsageStat()8875     public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat()
8876             throws RemoteException {
8877         final NotificationRecord r = generateNotificationRecord(
8878                 mTestNotificationChannel, 1, null, true);
8879         r.setTextChanged(true);
8880         mService.addNotification(r);
8881 
8882         mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
8883 
8884         verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
8885     }
8886 
8887     @Test
testSetNotificationsShownFromListener_protectsCrossUserInformation()8888     public void testSetNotificationsShownFromListener_protectsCrossUserInformation()
8889             throws RemoteException {
8890         Notification.Builder nb = new Notification.Builder(
8891                 mContext, mTestNotificationChannel.getId())
8892                 .setContentTitle("foo")
8893                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8894         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
8895                 "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
8896                 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
8897                 null, 0);
8898         final NotificationRecord r =
8899                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8900         r.setTextChanged(true);
8901         mService.addNotification(r);
8902 
8903         // no security exception!
8904         mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
8905 
8906         verify(mAppUsageStats, never()).reportInterruptiveNotification(
8907                 anyString(), anyString(), anyInt());
8908     }
8909 
8910     @Test
testCancelNotificationsFromListener_protectsCrossUserInformation()8911     public void testCancelNotificationsFromListener_protectsCrossUserInformation()
8912             throws RemoteException {
8913         Notification.Builder nb = new Notification.Builder(
8914                 mContext, mTestNotificationChannel.getId())
8915                 .setContentTitle("foo")
8916                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
8917         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
8918                 "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
8919                 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
8920                 null, 0);
8921         final NotificationRecord r =
8922                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
8923         r.setTextChanged(true);
8924         mService.addNotification(r);
8925 
8926         // no security exception!
8927         mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()});
8928 
8929         waitForIdle();
8930         assertEquals(1, mService.getNotificationRecordCount());
8931     }
8932 
8933     @Test
testMaybeRecordInterruptionLocked_doesNotRecordTwice()8934     public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
8935             throws RemoteException {
8936         final NotificationRecord r = generateNotificationRecord(
8937                 mTestNotificationChannel, 1, null, true);
8938         r.setInterruptive(true);
8939         mService.addNotification(r);
8940 
8941         mService.maybeRecordInterruptionLocked(r);
8942         mService.maybeRecordInterruptionLocked(r);
8943 
8944         verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
8945                 anyString(), anyString(), anyInt());
8946         verify(mHistoryManager, times(1)).addNotification(any());
8947     }
8948 
8949     @Test
testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()8950     public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()
8951             throws RemoteException {
8952         final NotificationRecord r = generateNotificationRecord(
8953                 mTestNotificationChannel, 1, null, true);
8954         r.setInterruptive(true);
8955         r.getSbn().getNotification().setSmallIcon(null);
8956         mService.addNotification(r);
8957 
8958         mService.maybeRecordInterruptionLocked(r);
8959 
8960         verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
8961                 anyString(), anyString(), anyInt());
8962         verify(mHistoryManager, never()).addNotification(any());
8963     }
8964 
8965     @Test
testBubble()8966     public void testBubble() throws Exception {
8967         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE);
8968         assertFalse(mBinderService.areBubblesAllowed(mPkg));
8969         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
8970                 BUBBLE_PREFERENCE_NONE);
8971     }
8972 
8973     @Test
testUserApprovedBubblesForPackageSelected()8974     public void testUserApprovedBubblesForPackageSelected() throws Exception {
8975         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_SELECTED);
8976         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
8977                 BUBBLE_PREFERENCE_SELECTED);
8978     }
8979 
8980     @Test
testUserApprovedBubblesForPackageAll()8981     public void testUserApprovedBubblesForPackageAll() throws Exception {
8982         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_ALL);
8983         assertTrue(mBinderService.areBubblesAllowed(mPkg));
8984         assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid),
8985                 BUBBLE_PREFERENCE_ALL);
8986     }
8987 
8988     @Test
testUserRejectsBubblesForPackage()8989     public void testUserRejectsBubblesForPackage() throws Exception {
8990         mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE);
8991         assertFalse(mBinderService.areBubblesAllowed(mPkg));
8992     }
8993 
8994     @Test
testAreBubblesEnabled()8995     public void testAreBubblesEnabled() throws Exception {
8996         Settings.Secure.putInt(mContext.getContentResolver(),
8997                 Settings.Secure.NOTIFICATION_BUBBLES, 1);
8998         mService.mPreferencesHelper.updateBubblesEnabled();
8999         assertTrue(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
9000     }
9001 
9002     @Test
testAreBubblesEnabled_false()9003     public void testAreBubblesEnabled_false() throws Exception {
9004         Settings.Secure.putIntForUser(mContext.getContentResolver(),
9005                 Settings.Secure.NOTIFICATION_BUBBLES, 0, UserHandle.getUserId(mUid));
9006         mService.mPreferencesHelper.updateBubblesEnabled();
9007         assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
9008     }
9009 
9010     @Test
testAreBubblesEnabled_exception()9011     public void testAreBubblesEnabled_exception() throws Exception {
9012         try {
9013             assertTrue(mBinderService.areBubblesEnabled(
9014                     UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE)));
9015             fail("Cannot call cross user without permission");
9016         } catch (SecurityException e) {
9017             // pass
9018         }
9019         // cross user, with permission, no problem
9020         enableInteractAcrossUsers();
9021         assertTrue(mBinderService.areBubblesEnabled(
9022                 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE)));
9023     }
9024 
9025     @Test
testIsCallerInstantApp_primaryUser()9026     public void testIsCallerInstantApp_primaryUser() throws Exception {
9027         ApplicationInfo info = new ApplicationInfo();
9028         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
9029         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
9030         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
9031 
9032         assertTrue(mService.isCallerInstantApp(45770, 0));
9033 
9034         info.privateFlags = 0;
9035         assertFalse(mService.isCallerInstantApp(575370, 0));
9036     }
9037 
9038     @Test
testIsCallerInstantApp_secondaryUser()9039     public void testIsCallerInstantApp_secondaryUser() throws Exception {
9040         ApplicationInfo info = new ApplicationInfo();
9041         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
9042         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
9043         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
9044         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
9045 
9046         assertTrue(mService.isCallerInstantApp(68638450, 10));
9047     }
9048 
9049     @Test
testIsCallerInstantApp_userAllNotification()9050     public void testIsCallerInstantApp_userAllNotification() throws Exception {
9051         ApplicationInfo info = new ApplicationInfo();
9052         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
9053         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM)))
9054                 .thenReturn(info);
9055         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
9056 
9057         assertTrue(mService.isCallerInstantApp(45770, UserHandle.USER_ALL));
9058 
9059         info.privateFlags = 0;
9060         assertFalse(mService.isCallerInstantApp(575370, UserHandle.USER_ALL ));
9061     }
9062 
9063     @Test
testResolveNotificationUid_sameApp_nonSystemUser()9064     public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception {
9065         ApplicationInfo info = new ApplicationInfo();
9066         info.uid = Binder.getCallingUid();
9067         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
9068         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
9069 
9070         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10);
9071 
9072         assertEquals(info.uid, actualUid);
9073     }
9074 
9075     @Test
testResolveNotificationUid_sameApp()9076     public void testResolveNotificationUid_sameApp() throws Exception {
9077         ApplicationInfo info = new ApplicationInfo();
9078         info.uid = Binder.getCallingUid();
9079         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
9080 
9081         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
9082 
9083         assertEquals(info.uid, actualUid);
9084     }
9085 
9086     @Test
testResolveNotificationUid_sameAppDiffPackage()9087     public void testResolveNotificationUid_sameAppDiffPackage() throws Exception {
9088         ApplicationInfo info = new ApplicationInfo();
9089         info.uid = Binder.getCallingUid();
9090         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
9091 
9092         int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0);
9093 
9094         assertEquals(info.uid, actualUid);
9095     }
9096 
9097     @Test
testResolveNotificationUid_sameAppWrongUid()9098     public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
9099         ApplicationInfo info = new ApplicationInfo();
9100         info.uid = 1356347;
9101         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info);
9102 
9103         try {
9104             mService.resolveNotificationUid("caller", "caller", 9, 0);
9105             fail("Incorrect uid didn't throw security exception");
9106         } catch (SecurityException e) {
9107             // yay
9108         }
9109     }
9110 
9111     @Test
testResolveNotificationUid_delegateAllowed()9112     public void testResolveNotificationUid_delegateAllowed() throws Exception {
9113         int expectedUid = 123;
9114 
9115         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
9116         mService.setPreferencesHelper(mPreferencesHelper);
9117         when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt()))
9118                 .thenReturn(true);
9119 
9120         assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0));
9121     }
9122 
9123     @Test
testResolveNotificationUid_androidAllowed()9124     public void testResolveNotificationUid_androidAllowed() throws Exception {
9125         int expectedUid = 123;
9126 
9127         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
9128         // no delegate
9129 
9130         assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0));
9131     }
9132 
9133     @Test
testPostFromAndroidForNonExistentPackage()9134     public void testPostFromAndroidForNonExistentPackage() throws Exception {
9135         final String notReal = "NOT REAL";
9136         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow(
9137                 PackageManager.NameNotFoundException.class);
9138         ApplicationInfo ai = new ApplicationInfo();
9139         ai.uid = -1;
9140         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
9141 
9142         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
9143         try {
9144             mInternalService.enqueueNotification(notReal, "android", 0, 0,
9145                     "testPostFromAndroidForNonExistentPackage",
9146                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
9147             fail("can't post notifications for nonexistent packages, even if you exist");
9148         } catch (SecurityException e) {
9149             // yay
9150         }
9151     }
9152 
9153     @Test
testCancelFromAndroidForNonExistentPackage()9154     public void testCancelFromAndroidForNonExistentPackage() throws Exception {
9155         final String notReal = "NOT REAL";
9156         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
9157                 PackageManager.NameNotFoundException.class);
9158         ApplicationInfo ai = new ApplicationInfo();
9159         ai.uid = -1;
9160         when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
9161 
9162         // unlike the post case, ignore instead of throwing
9163         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
9164 
9165         mInternalService.cancelNotification(notReal, "android", 0, 0, "tag",
9166                 sbn.getId(), sbn.getUserId());
9167     }
9168 
9169     @Test
testResolveNotificationUid_delegateNotAllowed()9170     public void testResolveNotificationUid_delegateNotAllowed() throws Exception {
9171         when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123);
9172         // no delegate
9173 
9174         try {
9175             mService.resolveNotificationUid("caller", "target", 9, 0);
9176             fail("Incorrect uid didn't throw security exception");
9177         } catch (SecurityException e) {
9178             // yay
9179         }
9180     }
9181 
9182     @Test
testRemoveForegroundServiceFlagFromNotification_enqueued()9183     public void testRemoveForegroundServiceFlagFromNotification_enqueued() {
9184         when(mAmi.applyForegroundServiceNotification(
9185                 any(), anyString(), anyInt(), anyString(), anyInt()))
9186                 .thenReturn(SHOW_IMMEDIATELY);
9187         Notification n = new Notification.Builder(mContext, "").build();
9188         n.flags |= FLAG_FOREGROUND_SERVICE;
9189 
9190         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
9191                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9192         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9193 
9194         mService.addEnqueuedNotification(r);
9195 
9196         mInternalService.removeForegroundServiceFlagFromNotification(
9197                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9198 
9199         waitForIdle();
9200 
9201         verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
9202     }
9203 
9204     @Test
testRemoveForegroundServiceFlagFromNotification_posted()9205     public void testRemoveForegroundServiceFlagFromNotification_posted() {
9206         when(mAmi.applyForegroundServiceNotification(
9207                 any(), anyString(), anyInt(), anyString(), anyInt()))
9208                 .thenReturn(SHOW_IMMEDIATELY);
9209         Notification n = new Notification.Builder(mContext, "").build();
9210         n.flags |= FLAG_FOREGROUND_SERVICE;
9211 
9212         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
9213                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9214         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9215 
9216         mService.addNotification(r);
9217 
9218         mInternalService.removeForegroundServiceFlagFromNotification(
9219                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9220 
9221         waitForIdle();
9222 
9223         ArgumentCaptor<NotificationRecord> captor =
9224                 ArgumentCaptor.forClass(NotificationRecord.class);
9225         verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
9226 
9227         assertEquals(0, captor.getValue().getNotification().flags);
9228     }
9229 
9230     @Test
testCannotRemoveForegroundFlagWhenOverLimit_enqueued()9231     public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() {
9232         when(mAmi.applyForegroundServiceNotification(
9233                 any(), anyString(), anyInt(), anyString(), anyInt()))
9234                 .thenReturn(SHOW_IMMEDIATELY);
9235         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
9236             Notification n = new Notification.Builder(mContext, "").build();
9237             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
9238                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
9239             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9240             mService.addEnqueuedNotification(r);
9241         }
9242         Notification n = new Notification.Builder(mContext, "").build();
9243         n.flags |= FLAG_FOREGROUND_SERVICE;
9244 
9245         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
9246                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
9247                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9248         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9249 
9250         mService.addEnqueuedNotification(r);
9251 
9252         mInternalService.removeForegroundServiceFlagFromNotification(
9253                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9254 
9255         waitForIdle();
9256 
9257         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
9258                 mService.getNotificationRecordCount());
9259     }
9260 
9261     @Test
testCannotRemoveForegroundFlagWhenOverLimit_posted()9262     public void testCannotRemoveForegroundFlagWhenOverLimit_posted() {
9263         when(mAmi.applyForegroundServiceNotification(
9264                 any(), anyString(), anyInt(), anyString(), anyInt()))
9265                 .thenReturn(SHOW_IMMEDIATELY);
9266         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
9267             Notification n = new Notification.Builder(mContext, "").build();
9268             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
9269                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
9270             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9271             mService.addNotification(r);
9272         }
9273         Notification n = new Notification.Builder(mContext, "").build();
9274         n.flags |= FLAG_FOREGROUND_SERVICE;
9275 
9276         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
9277                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
9278                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
9279         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
9280 
9281         mService.addNotification(r);
9282 
9283         mInternalService.removeForegroundServiceFlagFromNotification(
9284                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
9285 
9286         waitForIdle();
9287 
9288         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
9289                 mService.getNotificationRecordCount());
9290     }
9291 
9292     @Test
testAllowForegroundCustomToasts()9293     public void testAllowForegroundCustomToasts() throws Exception {
9294         final String testPackage = "testPackageName";
9295         assertEquals(0, mService.mToastQueue.size());
9296         mService.isSystemUid = false;
9297         mService.isSystemAppId = false;
9298         setToastRateIsWithinQuota(true);
9299         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9300 
9301         // package is not suspended
9302         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9303                 .thenReturn(false);
9304 
9305         // notifications from this package are blocked by the user
9306         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
9307 
9308         setAppInForegroundForToasts(mUid, true);
9309 
9310         // enqueue toast -> toast should still enqueue
9311         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9312         assertEquals(1, mService.mToastQueue.size());
9313         assertThat(wasEnqueued).isTrue();
9314     }
9315 
9316     @Test
testDisallowBackgroundCustomToasts()9317     public void testDisallowBackgroundCustomToasts() throws Exception {
9318         final String testPackage = "testPackageName";
9319         assertEquals(0, mService.mToastQueue.size());
9320         mService.isSystemUid = false;
9321         mService.isSystemAppId = false;
9322         setToastRateIsWithinQuota(true);
9323         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9324 
9325         // package is not suspended
9326         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9327                 .thenReturn(false);
9328 
9329         setAppInForegroundForToasts(mUid, false);
9330 
9331         // enqueue toast -> no toasts enqueued
9332         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9333         assertEquals(0, mService.mToastQueue.size());
9334         assertThat(wasEnqueued).isFalse();
9335     }
9336 
9337     @Test
testDontCallShowToastAgainOnTheSameCustomToast()9338     public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception {
9339         final String testPackage = "testPackageName";
9340         assertEquals(0, mService.mToastQueue.size());
9341         mService.isSystemUid = false;
9342         mService.isSystemAppId = false;
9343         setToastRateIsWithinQuota(true);
9344         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9345 
9346         // package is not suspended
9347         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9348                 .thenReturn(false);
9349 
9350         setAppInForegroundForToasts(mUid, true);
9351 
9352         Binder token = new Binder();
9353         ITransientNotification callback = mock(ITransientNotification.class);
9354         INotificationManager nmService = (INotificationManager) mService.mService;
9355 
9356         // first time trying to show the toast, showToast gets called
9357         enqueueToast(nmService, testPackage, token, callback);
9358         verify(callback, times(1)).show(any());
9359 
9360         // second time trying to show the same toast, showToast isn't called again (total number of
9361         // invocations stays at one)
9362         enqueueToast(nmService, testPackage, token, callback);
9363         verify(callback, times(1)).show(any());
9364     }
9365 
9366     @Test
testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()9367     public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()
9368             throws Exception {
9369         final String testPackage = "testPackageName";
9370         assertEquals(0, mService.mToastQueue.size());
9371         mService.isSystemUid = false;
9372         mService.isSystemAppId = false;
9373         setToastRateIsWithinQuota(false); // rate limit reached
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         Binder token = new Binder();
9383         ITransientNotification callback = mock(ITransientNotification.class);
9384         INotificationManager nmService = (INotificationManager) mService.mService;
9385 
9386         enqueueToast(nmService, testPackage, token, callback);
9387         verify(callback, times(1)).show(any());
9388     }
9389 
9390     @Test
testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()9391     public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()
9392             throws Exception {
9393         final String testPackage = "testPackageName";
9394         assertEquals(0, mService.mToastQueue.size());
9395         mService.isSystemUid = false;
9396         mService.isSystemAppId = false;
9397         setToastRateIsWithinQuota(true);
9398         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9399 
9400         // package is not suspended
9401         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9402                 .thenReturn(false);
9403 
9404         setAppInForegroundForToasts(mUid, true);
9405 
9406         Binder token1 = new Binder();
9407         Binder token2 = new Binder();
9408         ITransientNotification callback1 = mock(ITransientNotification.class);
9409         ITransientNotification callback2 = mock(ITransientNotification.class);
9410         INotificationManager nmService = (INotificationManager) mService.mService;
9411 
9412         enqueueToast(nmService, testPackage, token1, callback1);
9413         enqueueToast(nmService, testPackage, token2, callback2);
9414 
9415         assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued.
9416         verify(callback1, times(1)).show(any()); // First toast shown.
9417 
9418         setAppInForegroundForToasts(mUid, false);
9419 
9420         mService.cancelToastLocked(0); // Remove the first toast, and show next.
9421 
9422         assertEquals(0, mService.mToastQueue.size()); // Both toasts processed.
9423         verify(callback2, never()).show(any()); // Second toast was never shown.
9424     }
9425 
9426     @Test
testAllowForegroundTextToasts()9427     public void testAllowForegroundTextToasts() throws Exception {
9428         final String testPackage = "testPackageName";
9429         assertEquals(0, mService.mToastQueue.size());
9430         mService.isSystemUid = false;
9431         mService.isSystemAppId = false;
9432         setToastRateIsWithinQuota(true);
9433         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9434 
9435         // package is not suspended
9436         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9437                 .thenReturn(false);
9438 
9439         setAppInForegroundForToasts(mUid, true);
9440 
9441         // enqueue toast -> toast should still enqueue
9442         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9443         assertEquals(1, mService.mToastQueue.size());
9444         assertThat(wasEnqueued).isTrue();
9445     }
9446 
9447     @Test
testAllowBackgroundTextToasts()9448     public void testAllowBackgroundTextToasts() throws Exception {
9449         final String testPackage = "testPackageName";
9450         assertEquals(0, mService.mToastQueue.size());
9451         mService.isSystemUid = false;
9452         mService.isSystemAppId = false;
9453         setToastRateIsWithinQuota(true);
9454         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9455 
9456         // package is not suspended
9457         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9458                 .thenReturn(false);
9459 
9460         setAppInForegroundForToasts(mUid, false);
9461 
9462         // enqueue toast -> toast should still enqueue
9463         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9464         assertEquals(1, mService.mToastQueue.size());
9465         assertThat(wasEnqueued).isTrue();
9466     }
9467 
9468     @Test
testDontCallShowToastAgainOnTheSameTextToast()9469     public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception {
9470         final String testPackage = "testPackageName";
9471         assertEquals(0, mService.mToastQueue.size());
9472         mService.isSystemUid = false;
9473         mService.isSystemAppId = false;
9474         setToastRateIsWithinQuota(true);
9475         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9476 
9477         // package is not suspended
9478         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9479                 .thenReturn(false);
9480 
9481         setAppInForegroundForToasts(mUid, true);
9482 
9483         Binder token = new Binder();
9484         INotificationManager nmService = (INotificationManager) mService.mService;
9485 
9486         // first time trying to show the toast, showToast gets called
9487         enqueueTextToast(testPackage, "Text");
9488         verify(mStatusBar, times(1))
9489                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9490 
9491         // second time trying to show the same toast, showToast isn't called again (total number of
9492         // invocations stays at one)
9493         enqueueTextToast(testPackage, "Text");
9494         verify(mStatusBar, times(1))
9495                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9496     }
9497 
9498     @Test
testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()9499     public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()
9500             throws Exception {
9501         final String testPackage = "testPackageName";
9502         assertEquals(0, mService.mToastQueue.size());
9503         mService.isSystemUid = false;
9504         mService.isSystemAppId = false;
9505         setToastRateIsWithinQuota(false); // rate limit reached
9506         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9507         setAppInForegroundForToasts(mUid, false);
9508 
9509         // package is not suspended
9510         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9511                 .thenReturn(false);
9512 
9513         Binder token = new Binder();
9514         INotificationManager nmService = (INotificationManager) mService.mService;
9515 
9516         enqueueTextToast(testPackage, "Text");
9517         verify(mStatusBar, times(0))
9518                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9519     }
9520 
9521     @Test
testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()9522     public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()
9523             throws Exception {
9524         final String testPackage = "testPackageName";
9525         assertEquals(0, mService.mToastQueue.size());
9526         mService.isSystemUid = false;
9527         mService.isSystemAppId = false;
9528         setToastRateIsWithinQuota(false); // rate limit reached
9529         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9530         setAppInForegroundForToasts(mUid, true);
9531 
9532         // package is not suspended
9533         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9534                 .thenReturn(false);
9535 
9536         Binder token = new Binder();
9537         INotificationManager nmService = (INotificationManager) mService.mService;
9538 
9539         enqueueTextToast(testPackage, "Text");
9540         verify(mStatusBar, times(1))
9541                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9542     }
9543 
9544     @Test
testTextToastRateLimiterAllowsLimitAvoidanceWithPermission()9545     public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception {
9546         final String testPackage = "testPackageName";
9547         assertEquals(0, mService.mToastQueue.size());
9548         mService.isSystemUid = false;
9549         mService.isSystemAppId = false;
9550         setToastRateIsWithinQuota(false); // rate limit reached
9551         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true);
9552         setAppInForegroundForToasts(mUid, false);
9553 
9554         // package is not suspended
9555         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9556                 .thenReturn(false);
9557 
9558         Binder token = new Binder();
9559         INotificationManager nmService = (INotificationManager) mService.mService;
9560 
9561         enqueueTextToast(testPackage, "Text");
9562         verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
9563                 anyInt());
9564     }
9565 
9566     @Test
testRateLimitedToasts_windowsRemoved()9567     public void testRateLimitedToasts_windowsRemoved() throws Exception {
9568         final String testPackage = "testPackageName";
9569         assertEquals(0, mService.mToastQueue.size());
9570         mService.isSystemUid = false;
9571         mService.isSystemAppId = false;
9572         setToastRateIsWithinQuota(false); // rate limit reached
9573         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9574         setAppInForegroundForToasts(mUid, false);
9575 
9576         // package is not suspended
9577         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9578                 .thenReturn(false);
9579 
9580         Binder token = new Binder();
9581         INotificationManager nmService = (INotificationManager) mService.mService;
9582 
9583         enqueueTextToast(testPackage, "Text");
9584 
9585         // window token was added when enqueued
9586         ArgumentCaptor<Binder> binderCaptor =
9587                 ArgumentCaptor.forClass(Binder.class);
9588         verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(),
9589                 eq(TYPE_TOAST), anyInt(), eq(null));
9590 
9591         // but never shown
9592         verify(mStatusBar, times(0))
9593                 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
9594 
9595         // and removed when rate limited
9596         verify(mWindowManagerInternal)
9597                 .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt());
9598     }
9599 
9600     @Test
backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast()9601     public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
9602             Exception {
9603         final String testPackage = "testPackageName";
9604         assertEquals(0, mService.mToastQueue.size());
9605         mService.isSystemUid = true;
9606         setToastRateIsWithinQuota(true);
9607         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9608 
9609         // package is not suspended
9610         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9611                 .thenReturn(false);
9612 
9613         // notifications from this package are blocked by the user
9614         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
9615 
9616         setAppInForegroundForToasts(mUid, false);
9617 
9618         // enqueue toast -> toast should still enqueue
9619         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9620         assertEquals(1, mService.mToastQueue.size());
9621         assertThat(wasEnqueued).isTrue();
9622         verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any());
9623     }
9624 
9625     @Test
foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9626     public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws
9627             Exception {
9628         final String testPackage = "testPackageName";
9629         assertEquals(0, mService.mToastQueue.size());
9630         mService.isSystemUid = false;
9631         mService.isSystemAppId = false;
9632         setToastRateIsWithinQuota(true);
9633         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9634 
9635         // package is not suspended
9636         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9637                 .thenReturn(false);
9638 
9639         setAppInForegroundForToasts(mUid, true);
9640 
9641         // enqueue toast -> toast should still enqueue
9642         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9643         assertEquals(1, mService.mToastQueue.size());
9644         assertThat(wasEnqueued).isTrue();
9645         verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());
9646     }
9647 
9648     @Test
backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9649     public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws
9650             Exception {
9651         final String testPackage = "testPackageName";
9652         assertEquals(0, mService.mToastQueue.size());
9653         mService.isSystemUid = false;
9654         mService.isSystemAppId = false;
9655         setToastRateIsWithinQuota(true);
9656         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9657 
9658         // package is not suspended
9659         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9660                 .thenReturn(false);
9661 
9662         setAppInForegroundForToasts(mUid, false);
9663 
9664         // enqueue toast -> toast should still enqueue
9665         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9666         assertEquals(1, mService.mToastQueue.size());
9667         assertThat(wasEnqueued).isTrue();
9668         verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());
9669     }
9670 
9671     @Test
testTextToastsCallStatusBar()9672     public void testTextToastsCallStatusBar() throws Exception {
9673         allowTestPackageToToast();
9674 
9675         // enqueue toast -> no toasts enqueued
9676         boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text");
9677         assertThat(wasEnqueued).isTrue();
9678 
9679         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
9680     }
9681 
9682     @Test
testTextToastsCallStatusBar_nonUiContext_defaultDisplay()9683     public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay()
9684             throws Exception {
9685         allowTestPackageToToast();
9686 
9687         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY);
9688 
9689         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
9690     }
9691 
9692     @Test
testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()9693     public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()
9694             throws Exception {
9695         allowTestPackageToToast();
9696         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9697 
9698         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID);
9699 
9700         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9701     }
9702 
9703     @Test
testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()9704     public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()
9705             throws Exception {
9706         mockIsVisibleBackgroundUsersSupported(true);
9707         mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID);
9708         allowTestPackageToToast();
9709 
9710         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY);
9711 
9712         verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);
9713 
9714     }
9715 
9716     @Test
testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()9717     public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()
9718             throws Exception {
9719         mockIsVisibleBackgroundUsersSupported(true);
9720         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9721         mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used
9722         allowTestPackageToToast();
9723 
9724         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID);
9725 
9726         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9727     }
9728 
9729     @Test
testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()9730     public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()
9731             throws Exception {
9732         mockIsVisibleBackgroundUsersSupported(true);
9733         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9734         mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID);
9735         allowTestPackageToToast();
9736 
9737         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY);
9738 
9739         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9740     }
9741 
9742     @Test
testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()9743     public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()
9744             throws Exception {
9745         mockIsVisibleBackgroundUsersSupported(true);
9746         mockIsUserVisible(SECONDARY_DISPLAY_ID, true);
9747         mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used
9748         allowTestPackageToToast();
9749 
9750         enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID);
9751 
9752         verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID);
9753     }
9754 
9755     @Test
testTextToastsCallStatusBar_userNotVisibleOnDisplay()9756     public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception {
9757         final String testPackage = "testPackageName";
9758         assertEquals(0, mService.mToastQueue.size());
9759         mService.isSystemUid = false;
9760         mService.isSystemAppId = false;
9761         setToastRateIsWithinQuota(true);
9762         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9763         mockIsUserVisible(DEFAULT_DISPLAY, false);
9764 
9765         // package is not suspended
9766         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
9767                 .thenReturn(false);
9768 
9769         // enqueue toast -> no toasts enqueued
9770         boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9771         verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
9772                 anyInt());
9773         assertEquals(0, mService.mToastQueue.size());
9774         assertThat(wasEnqueued).isFalse();
9775     }
9776 
9777     @Test
testDisallowToastsFromSuspendedPackages()9778     public void testDisallowToastsFromSuspendedPackages() throws Exception {
9779         final String testPackage = "testPackageName";
9780         assertEquals(0, mService.mToastQueue.size());
9781         mService.isSystemUid = false;
9782         mService.isSystemAppId = false;
9783         setToastRateIsWithinQuota(true);
9784         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9785 
9786         // package is suspended
9787         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9788                 .thenReturn(true);
9789 
9790         // notifications from this package are NOT blocked by the user
9791         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
9792 
9793         // enqueue toast -> no toasts enqueued
9794         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9795         verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
9796                 anyInt());
9797         assertEquals(0, mService.mToastQueue.size());
9798         assertThat(wasEnqueued).isFalse();
9799     }
9800 
9801     @Test
testDisallowToastsFromBlockedApps()9802     public void testDisallowToastsFromBlockedApps() throws Exception {
9803         final String testPackage = "testPackageName";
9804         assertEquals(0, mService.mToastQueue.size());
9805         mService.isSystemUid = false;
9806         mService.isSystemAppId = false;
9807         setToastRateIsWithinQuota(true);
9808         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9809 
9810         // package is not suspended
9811         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9812                 .thenReturn(false);
9813 
9814         // notifications from this package are blocked by the user
9815         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
9816 
9817         setAppInForegroundForToasts(mUid, false);
9818 
9819         // enqueue toast -> no toasts enqueued
9820         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9821         assertEquals(0, mService.mToastQueue.size());
9822         assertThat(wasEnqueued).isFalse();
9823     }
9824 
9825     @Test
testAlwaysAllowSystemToasts()9826     public void testAlwaysAllowSystemToasts() throws Exception {
9827         final String testPackage = "testPackageName";
9828         assertEquals(0, mService.mToastQueue.size());
9829         mService.isSystemUid = true;
9830         setToastRateIsWithinQuota(true);
9831         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9832 
9833         // package is suspended
9834         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9835                 .thenReturn(true);
9836 
9837         // notifications from this package ARE blocked by the user
9838         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
9839 
9840         setAppInForegroundForToasts(mUid, false);
9841 
9842         // enqueue toast -> system toast can still be enqueued
9843         boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());
9844         assertEquals(1, mService.mToastQueue.size());
9845         assertThat(wasEnqueued).isTrue();
9846     }
9847 
9848     @Test
testLimitNumberOfQueuedToastsFromPackage()9849     public void testLimitNumberOfQueuedToastsFromPackage() throws Exception {
9850         final String testPackage = "testPackageName";
9851         assertEquals(0, mService.mToastQueue.size());
9852         mService.isSystemUid = false;
9853         mService.isSystemAppId = false;
9854         setToastRateIsWithinQuota(true);
9855         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9856 
9857         // package is not suspended
9858         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9859                 .thenReturn(false);
9860 
9861         INotificationManager nmService = (INotificationManager) mService.mService;
9862 
9863         // Trying to quickly enqueue more toast than allowed.
9864         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) {
9865             boolean wasEnqueued = enqueueTextToast(testPackage, "Text");
9866             if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) {
9867                 assertThat(wasEnqueued).isTrue();
9868             } else {
9869                 assertThat(wasEnqueued).isFalse();
9870             }
9871         }
9872         // Only allowed number enqueued, rest ignored.
9873         assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size());
9874     }
9875 
9876     @Test
testPrioritizeSystemToasts()9877     public void testPrioritizeSystemToasts() throws Exception {
9878         // Insert non-system toasts
9879         final String testPackage = "testPackageName";
9880         assertEquals(0, mService.mToastQueue.size());
9881         mService.isSystemUid = false;
9882         mService.isSystemAppId = false;
9883         setToastRateIsWithinQuota(true);
9884         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
9885 
9886         // package is not suspended
9887         when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId))
9888                 .thenReturn(false);
9889 
9890         INotificationManager nmService = (INotificationManager) mService.mService;
9891 
9892         // Enqueue maximum number of toasts for test package
9893         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
9894             enqueueTextToast(testPackage, "Text");
9895         }
9896 
9897         // Enqueue system toast
9898         final String testPackageSystem = "testPackageNameSystem";
9899         mService.isSystemUid = true;
9900         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false);
9901         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, mUserId))
9902                 .thenReturn(false);
9903 
9904         enqueueToast(testPackageSystem, new TestableToastCallback());
9905 
9906         // System toast is inserted at the front of the queue, behind current showing toast
9907         assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg);
9908     }
9909 
9910     @Test
testPrioritizeSystemToasts_enqueueAfterExistingSystemToast()9911     public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception {
9912         // Insert system toasts
9913         final String testPackageSystem1 = "testPackageNameSystem1";
9914         assertEquals(0, mService.mToastQueue.size());
9915         mService.isSystemUid = true;
9916         setToastRateIsWithinQuota(true);
9917         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false);
9918 
9919         // package is not suspended
9920         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, mUserId))
9921                 .thenReturn(false);
9922 
9923         INotificationManager nmService = (INotificationManager) mService.mService;
9924 
9925         // Enqueue maximum number of toasts for test package
9926         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
9927             enqueueTextToast(testPackageSystem1, "Text");
9928         }
9929 
9930         // Enqueue another system toast
9931         final String testPackageSystem2 = "testPackageNameSystem2";
9932         mService.isSystemUid = true;
9933         setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false);
9934         when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, mUserId))
9935                 .thenReturn(false);
9936 
9937         enqueueToast(testPackageSystem2, new TestableToastCallback());
9938 
9939         // System toast is inserted at the back of the queue, after the other system toasts
9940         assertEquals(testPackageSystem2,
9941                 mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg);
9942     }
9943 
setAppInForegroundForToasts(int uid, boolean inForeground)9944     private void setAppInForegroundForToasts(int uid, boolean inForeground) {
9945         int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE;
9946         when(mActivityManager.getUidImportance(mUid)).thenReturn(importance);
9947         when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground);
9948     }
9949 
setToastRateIsWithinQuota(boolean isWithinQuota)9950     private void setToastRateIsWithinQuota(boolean isWithinQuota) {
9951         when(mToastRateLimiter.isWithinQuota(
9952                 anyInt(),
9953                 anyString(),
9954                 eq(NotificationManagerService.TOAST_QUOTA_TAG)))
9955                 .thenReturn(isWithinQuota);
9956     }
9957 
setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission)9958     private void setIfPackageHasPermissionToAvoidToastRateLimiting(
9959             String pkg, boolean hasPermission) throws Exception {
9960         when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS,
9961                 pkg, mUserId))
9962                 .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED);
9963     }
9964 
9965     @Test
testOnPanelRevealedAndHidden()9966     public void testOnPanelRevealedAndHidden() {
9967         int items = 5;
9968         mService.mNotificationDelegate.onPanelRevealed(false, items);
9969         verify(mAssistants, times(1)).onPanelRevealed(eq(items));
9970 
9971         mService.mNotificationDelegate.onPanelHidden();
9972         verify(mAssistants, times(1)).onPanelHidden();
9973 
9974         assertEquals(2, mNotificationRecordLogger.numCalls());
9975         assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN,
9976                 mNotificationRecordLogger.event(0));
9977         assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE,
9978                 mNotificationRecordLogger.event(1));
9979     }
9980 
9981     @Test
9982     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testOnNotificationSmartReplySent()9983     public void testOnNotificationSmartReplySent() {
9984         final int replyIndex = 2;
9985         final String reply = "Hello";
9986         final boolean modifiedBeforeSending = true;
9987         final boolean generatedByAssistant = true;
9988 
9989         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
9990         r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
9991         mService.addNotification(r);
9992 
9993         mService.mNotificationDelegate.onNotificationSmartReplySent(
9994                 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
9995                 modifiedBeforeSending);
9996         verify(mAssistants).notifyAssistantSuggestedReplySent(
9997                 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant));
9998         assertEquals(1, mNotificationRecordLogger.numCalls());
9999         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
10000                 mNotificationRecordLogger.event(0));
10001         // Check that r.recordSmartReplied was called.
10002         assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
10003                 .isGreaterThan(0);
10004         assertThat(r.getStats().hasSmartReplied()).isTrue();
10005     }
10006 
10007     @Test
10008     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate()10009     public void testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate() throws Exception {
10010         final int replyIndex = 2;
10011         final String reply = "Hello";
10012         final boolean modifiedBeforeSending = true;
10013 
10014         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10015         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10016         r.getSbn().getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
10017         r.setSuggestionsGeneratedByAssistant(true);
10018         r.setCanceledAfterLifetimeExtension(true);
10019         r.setPostSilently(true);
10020         mService.addNotification(r);
10021 
10022         mService.mNotificationDelegate.onNotificationSmartReplySent(
10023                 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
10024                 modifiedBeforeSending);
10025         waitForIdle();
10026 
10027         // At the moment prepareNotifyPostedLocked is called on the listeners,
10028         // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial
10029         // values.
10030         doAnswer(
10031                 invocation -> {
10032                     int flags = ((NotificationRecord) invocation.getArgument(0))
10033                             .getSbn().getNotification().flags;
10034                     assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
10035                     boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0))
10036                             .shouldPostSilently();
10037                     assertThat(shouldPostSilently).isTrue();
10038                     return null;
10039                 }
10040         ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean());
10041 
10042         // Checks that a post update is sent.
10043         verify(mWorkerHandler, times(1))
10044                 .post(any(NotificationManagerService.PostNotificationRunnable.class));
10045         ArgumentCaptor<NotificationRecord> captor =
10046                 ArgumentCaptor.forClass(NotificationRecord.class);
10047         verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
10048                 anyBoolean());
10049         assertThat(captor.getValue().getNotification().flags
10050                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
10051                 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
10052         // Flag was present before, so it's set afterward
10053         assertThat(captor.getValue().getNotification().flags
10054                 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
10055         // Should post silently was set before, so it's set afterward.
10056         assertThat(captor.getValue().shouldPostSilently()).isTrue();
10057     }
10058 
10059     @Test
testOnNotificationActionClick()10060     public void testOnNotificationActionClick() {
10061         final int actionIndex = 2;
10062         final Notification.Action action =
10063                 new Notification.Action.Builder(null, "text", mActivityIntent).build();
10064         final boolean generatedByAssistant = false;
10065 
10066         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10067         mService.addNotification(r);
10068 
10069         NotificationVisibility notificationVisibility =
10070                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10071         mService.mNotificationDelegate.onNotificationActionClick(
10072                 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
10073                 generatedByAssistant);
10074         verify(mAssistants).notifyAssistantActionClicked(
10075                 eq(r), eq(action), eq(generatedByAssistant));
10076 
10077         assertEquals(1, mNotificationRecordLogger.numCalls());
10078         assertEquals(
10079                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2,
10080                 mNotificationRecordLogger.event(0));
10081     }
10082 
10083     @Test
10084     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testActionClickLifetimeExtendedCancel()10085     public void testActionClickLifetimeExtendedCancel() throws Exception {
10086         final Notification.Action action =
10087                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
10088                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
10089 
10090         // Creates a notification marked as being lifetime extended.
10091         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10092         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10093         mService.addNotification(r);
10094 
10095         StatusBarNotification[] notifs =
10096                 mBinderService.getActiveNotifications(mPkg);
10097         assertThat(notifs.length).isEqualTo(1);
10098         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10099 
10100         // Call on action click.
10101         NotificationVisibility notificationVisibility =
10102                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10103         mService.mNotificationDelegate.onNotificationActionClick(
10104                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
10105                 /*generatedByAssistant=*/false);
10106 
10107         // Lifetime extended flag persists.
10108         assertThat(r.getSbn().getNotification().flags
10109                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
10110 
10111         mTestableLooper.moveTimeForward(210);
10112         waitForIdle();
10113         verify(mWorkerHandler, times(1))
10114                 .scheduleCancelNotification(
10115                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
10116 
10117         // Check that the cancelation occurred and the notification is gone.
10118         notifs = mBinderService.getActiveNotifications(mPkg);
10119         assertThat(notifs.length).isEqualTo(0);
10120         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
10121     }
10122 
10123     @Test
10124     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testActionClickLifetimeExtendedCancel_PreventByNoDismiss()10125     public void testActionClickLifetimeExtendedCancel_PreventByNoDismiss() throws Exception {
10126         final Notification.Action action =
10127                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
10128                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
10129 
10130         // Creates a notification marked as being lifetime extended.
10131         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10132         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10133         // Make the notification non-dismissable
10134         r.getSbn().getNotification().flags |= FLAG_NO_DISMISS;
10135         mService.addNotification(r);
10136 
10137         StatusBarNotification[] notifs =
10138                 mBinderService.getActiveNotifications(mPkg);
10139         assertThat(notifs.length).isEqualTo(1);
10140         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10141 
10142         // Call on action click.
10143         NotificationVisibility notificationVisibility =
10144                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10145         mService.mNotificationDelegate.onNotificationActionClick(
10146                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
10147                 /*generatedByAssistant=*/false);
10148 
10149         // Lifetime extended flag persists.
10150         assertThat(r.getSbn().getNotification().flags
10151                 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
10152 
10153         mTestableLooper.moveTimeForward(210);
10154         waitForIdle();
10155         verify(mWorkerHandler, times(1))
10156                 .scheduleCancelNotification(
10157                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
10158 
10159         // The cancellation is dropped and the notification is still present, with the update.
10160         notifs = mBinderService.getActiveNotifications(mPkg);
10161         assertThat(notifs.length).isEqualTo(1);
10162         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10163     }
10164 
10165     @Test
10166     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
testUpdateOnActionClickDropsLifetimeExtendedCancel()10167     public void testUpdateOnActionClickDropsLifetimeExtendedCancel() throws Exception {
10168         final Notification.Action action =
10169                 new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
10170                         mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
10171 
10172         // Creates a notification marked as being lifetime extended.
10173         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10174         r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
10175         mService.addNotification(r);
10176 
10177         StatusBarNotification[] notifs =
10178                 mBinderService.getActiveNotifications(mPkg);
10179         assertThat(notifs.length).isEqualTo(1);
10180         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10181 
10182         // Call on action click.
10183         NotificationVisibility notificationVisibility =
10184                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10185         mService.mNotificationDelegate.onNotificationActionClick(
10186                 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility,
10187                 /*generatedByAssistant=*/false);
10188 
10189         // The "app" sends an update of the notification in response.
10190         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
10191                 r.getSbn().getId(), r.getSbn().getNotification(), r.getSbn().getUserId());
10192 
10193         mTestableLooper.moveTimeForward(210);
10194         waitForIdle();
10195         verify(mWorkerHandler, times(1))
10196                 .scheduleCancelNotification(
10197                         any(NotificationManagerService.CancelNotificationRunnable.class), eq(200));
10198 
10199         // The cancellation is dropped and the notification is still present, with the update.
10200         notifs = mBinderService.getActiveNotifications(mPkg);
10201         assertThat(notifs.length).isEqualTo(1);
10202         assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
10203     }
10204 
10205     @Test
testOnAssistantNotificationActionClick()10206     public void testOnAssistantNotificationActionClick() {
10207         final int actionIndex = 1;
10208         final Notification.Action action =
10209                 new Notification.Action.Builder(null, "text", mActivityIntent).build();
10210         final boolean generatedByAssistant = true;
10211 
10212         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10213         mService.addNotification(r);
10214 
10215         NotificationVisibility notificationVisibility =
10216                 NotificationVisibility.obtain(r.getKey(), 1, 2, true);
10217         mService.mNotificationDelegate.onNotificationActionClick(
10218                 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
10219                 generatedByAssistant);
10220         verify(mAssistants).notifyAssistantActionClicked(
10221                 eq(r), eq(action), eq(generatedByAssistant));
10222 
10223         assertEquals(1, mNotificationRecordLogger.numCalls());
10224         assertEquals(
10225                 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1,
10226                 mNotificationRecordLogger.event(0));
10227     }
10228 
10229 
10230     @Test
testLogSmartSuggestionsVisible_triggerOnExpandAndVisible()10231     public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() {
10232         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10233         mService.addNotification(r);
10234 
10235         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
10236                 NOTIFICATION_LOCATION_UNKNOWN);
10237         NotificationVisibility[] notificationVisibility = new NotificationVisibility[] {
10238                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
10239         };
10240         mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
10241                 new NotificationVisibility[0]);
10242 
10243         assertEquals(1, mService.countLogSmartSuggestionsVisible);
10244     }
10245 
10246     @Test
testLogSmartSuggestionsVisible_noTriggerOnExpand()10247     public void testLogSmartSuggestionsVisible_noTriggerOnExpand() {
10248         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10249         mService.addNotification(r);
10250 
10251         mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
10252                 NOTIFICATION_LOCATION_UNKNOWN);
10253 
10254         assertEquals(0, mService.countLogSmartSuggestionsVisible);
10255     }
10256 
10257     @Test
testLogSmartSuggestionsVisible_noTriggerOnVisible()10258     public void testLogSmartSuggestionsVisible_noTriggerOnVisible() {
10259         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10260         mService.addNotification(r);
10261 
10262         NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{
10263                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
10264         };
10265         mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
10266                 new NotificationVisibility[0]);
10267 
10268         assertEquals(0, mService.countLogSmartSuggestionsVisible);
10269     }
10270 
10271     @Test
testReportSeen_delegated()10272     public void testReportSeen_delegated() {
10273         Notification.Builder nb =
10274                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
10275                         .setContentTitle("foo")
10276                         .setSmallIcon(android.R.drawable.sym_def_app_icon);
10277 
10278         StatusBarNotification sbn = new StatusBarNotification(mPkg, "opPkg", 0, "tag", mUid, 0,
10279                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10280         NotificationRecord r =  new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10281 
10282         mService.reportSeen(r);
10283         verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt());
10284 
10285     }
10286 
10287     @Test
testReportSeen_notDelegated()10288     public void testReportSeen_notDelegated() {
10289         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10290 
10291         mService.reportSeen(r);
10292         verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt());
10293     }
10294 
10295     @Test
testNotificationStats_notificationError()10296     public void testNotificationStats_notificationError() {
10297         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10298         mService.addNotification(r);
10299 
10300         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, r.getSbn().getId(),
10301                 r.getSbn().getTag(), mUid, 0,
10302                 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(),
10303                 UserHandle.getUserHandleForUid(mUid), null, 0);
10304         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10305         mService.addEnqueuedNotification(update);
10306         assertNull(update.getSbn().getNotification().getSmallIcon());
10307 
10308         NotificationManagerService.PostNotificationRunnable runnable =
10309                 mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(),
10310                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
10311         runnable.run();
10312         waitForIdle();
10313 
10314         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
10315         verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture());
10316         assertNotNull(captor.getValue());
10317     }
10318 
10319     @Test
testCanNotifyAsUser_crossUser()10320     public void testCanNotifyAsUser_crossUser() throws Exception {
10321         // same user no problem
10322         mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId());
10323 
10324         // cross user, no permission, problem
10325         try {
10326             mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
10327             fail("Should not be callable cross user without cross user permission");
10328         } catch (SecurityException e) {
10329             // good
10330         }
10331 
10332         // cross user, with permission, no problem
10333         enableInteractAcrossUsers();
10334         mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
10335     }
10336 
10337     @Test
testGetNotificationChannels_crossUser()10338     public void testGetNotificationChannels_crossUser() throws Exception {
10339         // same user no problem
10340         mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
10341 
10342         // cross user, no permission, problem
10343         try {
10344             mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
10345             fail("Should not be callable cross user without cross user permission");
10346         } catch (SecurityException e) {
10347             // good
10348         }
10349 
10350         // cross user, with permission, no problem
10351         enableInteractAcrossUsers();
10352         mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
10353     }
10354 
10355     @Test
setDefaultAssistantForUser_fromConfigXml()10356     public void setDefaultAssistantForUser_fromConfigXml() {
10357         ComponentName xmlConfig = new ComponentName("config", "xml");
10358         ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(xmlConfig));
10359         when(mResources
10360                 .getString(
10361                         com.android.internal.R.string.config_defaultAssistantAccessComponent))
10362                 .thenReturn(xmlConfig.flattenToString());
10363         when(mContext.getResources()).thenReturn(mResources);
10364         when(mAssistants.queryPackageForServices(eq(null), anyInt(), anyInt()))
10365                 .thenReturn(components);
10366         when(mAssistants.getDefaultComponents())
10367                 .thenReturn(components);
10368         mService.setNotificationAssistantAccessGrantedCallback(
10369                 mNotificationAssistantAccessGrantedCallback);
10370 
10371 
10372         mService.setDefaultAssistantForUser(0);
10373 
10374         verify(mNotificationAssistantAccessGrantedCallback)
10375                 .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
10376     }
10377 
10378     @Test
clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne()10379     public void clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne() throws RemoteException {
10380         ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
10381                 generateResetComponentValues();
10382         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners);
10383         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
10384         ComponentName deviceConfig1 = new ComponentName("device", "config1");
10385         ComponentName deviceConfig2 = new ComponentName("device", "config2");
10386         changes.put(true, new ArrayList(Arrays.asList(deviceConfig1, deviceConfig2)));
10387         changes.put(false, new ArrayList());
10388         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes);
10389         mService.getBinderService().clearData("device", 0, false);
10390         verify(mAssistants, times(1))
10391                 .setPackageOrComponentEnabled(
10392                         eq("device/config2"),
10393                         eq(0), eq(true), eq(false));
10394         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
10395                 eq("device"), eq(0), eq(false), eq(true));
10396     }
10397 
10398     @Test
testNASSettingUpgrade_userSetNull()10399     public void testNASSettingUpgrade_userSetNull() throws RemoteException {
10400         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component1");
10401         TestableNotificationManagerService service = spy(mService);
10402         int userId = 11;
10403         setUsers(new int[]{userId});
10404         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
10405         setNASMigrationDone(false, userId);
10406         when(mAssistants.getDefaultFromConfig())
10407                 .thenReturn(newDefaultComponent);
10408         when(mAssistants.getAllowedComponents(anyInt()))
10409                 .thenReturn(new ArrayList<>());
10410         when(mAssistants.hasUserSet(userId)).thenReturn(true);
10411 
10412         service.migrateDefaultNAS();
10413         assertTrue(service.isNASMigrationDone(userId));
10414         verify(mAssistants, times(1)).clearDefaults();
10415     }
10416 
10417     @Test
testNASSettingUpgrade_userSet()10418     public void testNASSettingUpgrade_userSet() throws RemoteException {
10419         ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1");
10420         TestableNotificationManagerService service = spy(mService);
10421         int userId = 11;
10422         setUsers(new int[]{userId});
10423         when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId});
10424         setNASMigrationDone(false, userId);
10425         when(mAssistants.getDefaultFromConfig())
10426                 .thenReturn(defaultComponent);
10427         when(mAssistants.getAllowedComponents(anyInt()))
10428                 .thenReturn(new ArrayList(Arrays.asList(defaultComponent)));
10429         when(mAssistants.hasUserSet(userId)).thenReturn(true);
10430 
10431         service.migrateDefaultNAS();
10432         verify(mAssistants, times(1)).setUserSet(userId, false);
10433         //resetDefaultAssistantsIfNecessary should invoke from readPolicyXml() and migration
10434         verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
10435     }
10436 
10437     @Test
testNASSettingUpgrade_multiUser()10438     public void testNASSettingUpgrade_multiUser() throws RemoteException {
10439         ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
10440         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
10441         TestableNotificationManagerService service = spy(mService);
10442         int userId1 = 11;
10443         int userId2 = 12;
10444         setUsers(new int[]{userId1, userId2});
10445         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1});
10446         when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2});
10447 
10448         setNASMigrationDone(false, userId1);
10449         setNASMigrationDone(false, userId2);
10450         when(mAssistants.getDefaultComponents())
10451                 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)));
10452         when(mAssistants.getDefaultFromConfig())
10453                 .thenReturn(newDefaultComponent);
10454         //User1: set different NAS
10455         when(mAssistants.getAllowedComponents(userId1))
10456                 .thenReturn(Arrays.asList(oldDefaultComponent));
10457         //User2: set to none
10458         when(mAssistants.getAllowedComponents(userId2))
10459                 .thenReturn(new ArrayList<>());
10460 
10461         when(mAssistants.hasUserSet(userId1)).thenReturn(true);
10462         when(mAssistants.hasUserSet(userId2)).thenReturn(true);
10463 
10464         service.migrateDefaultNAS();
10465         // user1's setting get reset
10466         verify(mAssistants, times(1)).setUserSet(userId1, false);
10467         verify(mAssistants, times(0)).setUserSet(eq(userId2), anyBoolean());
10468         assertTrue(service.isNASMigrationDone(userId2));
10469 
10470     }
10471 
10472     @Test
testNASSettingUpgrade_multiProfile()10473     public void testNASSettingUpgrade_multiProfile() throws RemoteException {
10474         ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
10475         ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
10476         TestableNotificationManagerService service = spy(mService);
10477         int userId1 = 11;
10478         int userId2 = 12; //work profile
10479         setUsers(new int[]{userId1, userId2});
10480         when(mUm.isManagedProfile(userId2)).thenReturn(true);
10481         when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2});
10482 
10483         setNASMigrationDone(false, userId1);
10484         setNASMigrationDone(false, userId2);
10485         when(mAssistants.getDefaultComponents())
10486                 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)));
10487         when(mAssistants.getDefaultFromConfig())
10488                 .thenReturn(newDefaultComponent);
10489         //Both profiles: set different NAS
10490         when(mAssistants.getAllowedComponents(userId1))
10491                 .thenReturn(Arrays.asList(oldDefaultComponent));
10492         when(mAssistants.getAllowedComponents(userId2))
10493                 .thenReturn(Arrays.asList(oldDefaultComponent));
10494 
10495         when(mAssistants.hasUserSet(userId1)).thenReturn(true);
10496         when(mAssistants.hasUserSet(userId2)).thenReturn(true);
10497 
10498         service.migrateDefaultNAS();
10499         assertFalse(service.isNASMigrationDone(userId1));
10500         assertFalse(service.isNASMigrationDone(userId2));
10501     }
10502 
10503 
10504 
10505     @Test
testNASSettingUpgrade_clearDataAfterMigrationIsDone()10506     public void testNASSettingUpgrade_clearDataAfterMigrationIsDone() throws RemoteException {
10507         ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component");
10508         TestableNotificationManagerService service = spy(mService);
10509         int userId = 12;
10510         setUsers(new int[]{userId});
10511         when(mAssistants.getDefaultComponents())
10512                 .thenReturn(new ArraySet<>(Arrays.asList(defaultComponent)));
10513         when(mAssistants.hasUserSet(userId)).thenReturn(true);
10514         setNASMigrationDone(true, userId);
10515 
10516         //Test User clear data
10517         ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners =
10518                 generateResetComponentValues();
10519         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners);
10520         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
10521         changes.put(true, new ArrayList(Arrays.asList(defaultComponent)));
10522         changes.put(false, new ArrayList());
10523         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes);
10524 
10525         //Clear data
10526         service.getBinderService().clearData("package", userId, false);
10527         //Test migrate flow again
10528         service.migrateDefaultNAS();
10529 
10530         //Migration should not happen again
10531         verify(mAssistants, times(0)).setUserSet(userId, false);
10532         verify(mAssistants, times(0)).clearDefaults();
10533         //resetDefaultAssistantsIfNecessary should only invoke once from readPolicyXml()
10534         verify(mAssistants, times(1)).resetDefaultAssistantsIfNecessary();
10535 
10536     }
10537 
setNASMigrationDone(boolean done, int userId)10538     private void setNASMigrationDone(boolean done, int userId) {
10539         Settings.Secure.putIntForUser(mContext.getContentResolver(),
10540                 Settings.Secure.NAS_SETTINGS_UPDATED, done ? 1 : 0, userId);
10541     }
10542 
setUsers(int[] userIds)10543     private void setUsers(int[] userIds) {
10544         List<UserInfo> users = new ArrayList<>();
10545         for (int id: userIds) {
10546             users.add(new UserInfo(id, String.valueOf(id), 0));
10547         }
10548         for (UserInfo user : users) {
10549             when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
10550         }
10551         when(mUm.getUsers()).thenReturn(users);
10552     }
10553 
10554     @Test
clearDefaultListenersPackageShouldEnableIt()10555     public void clearDefaultListenersPackageShouldEnableIt() throws RemoteException {
10556         ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants =
10557                 generateResetComponentValues();
10558         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changedAssistants);
10559         ComponentName deviceConfig = new ComponentName("device", "config");
10560         ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
10561         changes.put(true, new ArrayList(Arrays.asList(deviceConfig)));
10562         changes.put(false, new ArrayList());
10563         when(mListeners.resetComponents(anyString(), anyInt()))
10564             .thenReturn(changes);
10565         mService.getBinderService().clearData("device", 0, false);
10566         verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
10567                 eq("device"), eq(0), eq(false), eq(true));
10568     }
10569 
10570     @Test
clearDefaultDnDPackageShouldEnableIt()10571     public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException {
10572         ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues();
10573         when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed);
10574         when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed);
10575         mService.getBinderService().clearData("pkgName", 0, false);
10576         verify(mConditionProviders, times(1)).resetPackage(
10577                         eq("pkgName"), eq(0));
10578     }
10579 
10580     @Test
testFlagBubble()10581     public void testFlagBubble() throws RemoteException {
10582         setUpPrefsForBubbles(mPkg, mUid,
10583                 true /* global */,
10584                 BUBBLE_PREFERENCE_ALL /* app */,
10585                 true /* channel */);
10586 
10587         NotificationRecord nr =
10588                 generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble");
10589 
10590         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10591                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10592         waitForIdle();
10593 
10594         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10595         assertEquals(1, notifs.length);
10596         assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0);
10597         assertTrue(mService.getNotificationRecord(
10598                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10599     }
10600 
10601     @Test
testFlagBubble_noFlag_appNotAllowed()10602     public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException {
10603         setUpPrefsForBubbles(mPkg, mUid,
10604                 true /* global */,
10605                 BUBBLE_PREFERENCE_NONE /* app */,
10606                 true /* channel */);
10607 
10608         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10609                         "testFlagBubble_noFlag_appNotAllowed");
10610 
10611         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10612                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10613         waitForIdle();
10614 
10615         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10616         assertEquals(1, notifs.length);
10617         assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0);
10618         assertFalse(mService.getNotificationRecord(
10619                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10620     }
10621 
10622     @Test
testFlagBubbleNotifs_noFlag_whenAppForeground()10623     public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException {
10624         setUpPrefsForBubbles(mPkg, mUid,
10625                 true /* global */,
10626                 BUBBLE_PREFERENCE_ALL /* app */,
10627                 true /* channel */);
10628 
10629         // Notif with bubble metadata but not our other misc requirements
10630         Notification.Builder nb = new Notification.Builder(mContext,
10631                 mTestNotificationChannel.getId())
10632                 .setContentTitle("foo")
10633                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
10634                 .setBubbleMetadata(getBubbleMetadata());
10635         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 0,
10636                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10637         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10638 
10639         // Say we're foreground
10640         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
10641                 IMPORTANCE_FOREGROUND);
10642         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10643                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10644         waitForIdle();
10645 
10646         // if notif isn't configured properly it doesn't get to bubble just because app is
10647         // foreground.
10648         assertFalse(mService.getNotificationRecord(
10649                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10650     }
10651 
10652     @Test
testFlagBubbleNotifs_flag_messaging()10653     public void testFlagBubbleNotifs_flag_messaging() throws RemoteException {
10654         setUpPrefsForBubbles(mPkg, mUid,
10655                 true /* global */,
10656                 BUBBLE_PREFERENCE_ALL /* app */,
10657                 true /* channel */);
10658 
10659         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10660                 "testFlagBubbleNotifs_flag_messaging");
10661 
10662         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10663                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10664         waitForIdle();
10665 
10666         // yes allowed, yes messaging, yes bubble
10667         assertTrue(mService.getNotificationRecord(
10668                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10669     }
10670 
10671     @Test
testFlagBubbleNotifs_noFlag_noShortcut()10672     public void testFlagBubbleNotifs_noFlag_noShortcut() throws RemoteException {
10673         setUpPrefsForBubbles(mPkg, mUid,
10674                 true /* global */,
10675                 BUBBLE_PREFERENCE_ALL /* app */,
10676                 true /* channel */);
10677 
10678         Notification.Builder nb = getMessageStyleNotifBuilder(true, null, false, true);
10679         nb.setShortcutId(null);
10680         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
10681                 null, mUid, 0,
10682                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10683 
10684         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
10685                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
10686         waitForIdle();
10687 
10688         // no shortcut no bubble
10689         assertFalse(mService.getNotificationRecord(
10690                 sbn.getKey()).getNotification().isBubbleNotification());
10691     }
10692 
10693     @Test
testFlagBubbleNotifs_noFlag_messaging_appNotAllowed()10694     public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException {
10695         setUpPrefsForBubbles(mPkg, mUid,
10696                 true /* global */,
10697                 BUBBLE_PREFERENCE_NONE /* app */,
10698                 true /* channel */);
10699 
10700         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10701                 "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed");
10702 
10703         // Post the notification
10704         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10705                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10706         waitForIdle();
10707 
10708         // not allowed, no bubble
10709         assertFalse(mService.getNotificationRecord(
10710                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10711     }
10712 
10713     @Test
testFlagBubbleNotifs_noFlag_notBubble()10714     public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException {
10715         setUpPrefsForBubbles(mPkg, mUid,
10716                 true /* global */,
10717                 BUBBLE_PREFERENCE_ALL /* app */,
10718                 true /* channel */);
10719 
10720         // Messaging notif WITHOUT bubble metadata
10721         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */,
10722                 null /* groupKey */, false /* isSummary */, true);
10723 
10724         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
10725                 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0,
10726                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
10727         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
10728 
10729         // Post the notification
10730         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10731                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10732         waitForIdle();
10733 
10734         // no bubble metadata, no bubble
10735         assertFalse(mService.getNotificationRecord(
10736                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10737     }
10738 
10739     @Test
testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed()10740     public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException {
10741         setUpPrefsForBubbles(mPkg, mUid,
10742                 true /* global */,
10743                 BUBBLE_PREFERENCE_ALL /* app */,
10744                 false /* channel */);
10745 
10746         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
10747                 "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed");
10748         nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE);
10749 
10750         // Post the notification
10751         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10752                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10753         waitForIdle();
10754 
10755         // channel not allowed, no bubble
10756         assertFalse(mService.getNotificationRecord(
10757                 nr.getSbn().getKey()).getNotification().isBubbleNotification());
10758     }
10759 
10760     @Test
testCancelNotificationsFromApp_cancelsBubbles()10761     public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception {
10762         final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
10763         nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
10764 
10765         // Post the notification
10766         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
10767                 "testAppCancelNotifications_cancelsBubbles",
10768                 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(),
10769                 nrBubble.getSbn().getUserId());
10770         waitForIdle();
10771 
10772         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10773         assertEquals(1, notifs.length);
10774         assertEquals(1, mService.getNotificationRecordCount());
10775 
10776         mBinderService.cancelNotificationWithTag(mPkg, mPkg,
10777                 "testAppCancelNotifications_cancelsBubbles", nrBubble.getSbn().getId(),
10778                 nrBubble.getSbn().getUserId());
10779         waitForIdle();
10780 
10781         StatusBarNotification[] notifs2 = mBinderService.getActiveNotifications(mPkg);
10782         assertEquals(0, notifs2.length);
10783         assertEquals(0, mService.getNotificationRecordCount());
10784     }
10785 
10786     @Test
testCancelAllNotificationsFromApp_cancelsBubble()10787     public void testCancelAllNotificationsFromApp_cancelsBubble() throws Exception {
10788         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10789         nr.getSbn().getNotification().flags |= FLAG_BUBBLE;
10790         mService.addNotification(nr);
10791 
10792         mBinderService.cancelAllNotifications(mPkg, nr.getSbn().getUserId());
10793         waitForIdle();
10794 
10795         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10796         assertEquals(0, notifs.length);
10797         assertEquals(0, mService.getNotificationRecordCount());
10798     }
10799 
10800     @Test
testCancelAllNotificationsFromListener_ignoresBubbles()10801     public void testCancelAllNotificationsFromListener_ignoresBubbles() throws Exception {
10802         final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel);
10803         final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
10804         nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
10805 
10806         mService.addNotification(nrNormal);
10807         mService.addNotification(nrBubble);
10808 
10809         mService.getBinderService().cancelNotificationsFromListener(null, null);
10810         waitForIdle();
10811 
10812         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10813         assertEquals(1, notifs.length);
10814         assertEquals(1, mService.getNotificationRecordCount());
10815     }
10816 
10817     @Test
testCancelNotificationsFromListener_cancelsNonBubble()10818     public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception {
10819         // Add non-bubble notif
10820         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10821         mService.addNotification(nr);
10822 
10823         // Cancel via listener
10824         String[] keys = {nr.getSbn().getKey()};
10825         mService.getBinderService().cancelNotificationsFromListener(null, keys);
10826         waitForIdle();
10827 
10828         // Notif not active anymore
10829         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10830         assertEquals(0, notifs.length);
10831         assertEquals(0, mService.getNotificationRecordCount());
10832         // Cancel event is logged
10833         assertEquals(1, mNotificationRecordLogger.numCalls());
10834         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
10835             .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
10836     }
10837 
10838     @Test
testCancelNotificationsFromListener_suppressesBubble()10839     public void testCancelNotificationsFromListener_suppressesBubble() throws Exception {
10840         // Add bubble notif
10841         setUpPrefsForBubbles(mPkg, mUid,
10842             true /* global */,
10843             BUBBLE_PREFERENCE_ALL /* app */,
10844             true /* channel */);
10845         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
10846 
10847         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
10848             nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
10849         waitForIdle();
10850 
10851         // Cancel via listener
10852         String[] keys = {nr.getSbn().getKey()};
10853         mService.getBinderService().cancelNotificationsFromListener(null, keys);
10854         waitForIdle();
10855 
10856         // Bubble notif active and suppressed
10857         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10858         assertEquals(1, notifs.length);
10859         assertEquals(1, mService.getNotificationRecordCount());
10860         assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed());
10861     }
10862 
10863     @Test
testCancelAllNotificationsFromStatusBar_ignoresBubble()10864     public void testCancelAllNotificationsFromStatusBar_ignoresBubble() throws Exception {
10865         // GIVEN a notification bubble
10866         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
10867         nr.getSbn().getNotification().flags |= FLAG_BUBBLE;
10868         mService.addNotification(nr);
10869 
10870         // WHEN the status bar clears all notifications
10871         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
10872                 nr.getSbn().getUserId());
10873         waitForIdle();
10874 
10875         // THEN the bubble notification does not get removed
10876         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
10877         assertEquals(1, notifs.length);
10878         assertEquals(1, mService.getNotificationRecordCount());
10879     }
10880 
10881 
10882     @Test
testGetAllowedAssistantAdjustments()10883     public void testGetAllowedAssistantAdjustments() throws Exception {
10884         List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null);
10885         assertNotNull(adjustments);
10886     }
10887 
10888     @Test
testAdjustRestrictedKey()10889     public void testAdjustRestrictedKey() throws Exception {
10890         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
10891         mService.addNotification(r);
10892         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
10893 
10894         when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true);
10895         when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false);
10896 
10897         Bundle signals = new Bundle();
10898         signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
10899         signals.putInt(KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
10900         signals.putInt(KEY_TYPE, TYPE_PROMOTION);
10901         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
10902                "", r.getUser().getIdentifier());
10903 
10904         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
10905         r.applyAdjustments();
10906 
10907         assertEquals(IMPORTANCE_LOW, r.getAssistantImportance());
10908         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
10909     }
10910 
10911     @Test
testAutomaticZenRuleValidation_policyFilterAgreement()10912     public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception {
10913         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10914                 .thenReturn(true);
10915         mService.setZenHelper(mock(ZenModeHelper.class));
10916         ComponentName owner = new ComponentName(mContext, this.getClass());
10917         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10918         boolean isEnabled = true;
10919         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10920                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
10921 
10922         try {
10923             mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
10924             fail("Zen policy only applies to priority only mode");
10925         } catch (IllegalArgumentException e) {
10926             // yay
10927         }
10928 
10929         rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10930                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10931         mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
10932 
10933         rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10934                 null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
10935         mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false);
10936     }
10937 
10938     @Test
testAddAutomaticZenRule_systemCallTakesPackageFromOwner()10939     public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
10940         mService.isSystemUid = true;
10941         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
10942         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10943                 .thenReturn(true);
10944         mService.setZenHelper(mockZenModeHelper);
10945         ComponentName owner = new ComponentName("android", "ProviderName");
10946         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10947         boolean isEnabled = true;
10948         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10949                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10950         mBinderService.addAutomaticZenRule(rule, "com.android.settings", false);
10951 
10952         // verify that zen mode helper gets passed in a package name of "android"
10953         verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule),
10954                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt());
10955     }
10956 
10957     @Test
testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner()10958     public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception {
10959         // The multi-user case: where the calling uid doesn't match the system uid, but the calling
10960         // *appid* is the system.
10961         mService.isSystemUid = false;
10962         mService.isSystemAppId = true;
10963         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
10964         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10965                 .thenReturn(true);
10966         mService.setZenHelper(mockZenModeHelper);
10967         ComponentName owner = new ComponentName("android", "ProviderName");
10968         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10969         boolean isEnabled = true;
10970         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10971                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10972         mBinderService.addAutomaticZenRule(rule, "com.android.settings", false);
10973 
10974         // verify that zen mode helper gets passed in a package name of "android"
10975         verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule),
10976                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt());
10977     }
10978 
10979     @Test
testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg()10980     public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
10981         mService.isSystemUid = false;
10982         mService.isSystemAppId = false;
10983         ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
10984         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
10985                 .thenReturn(true);
10986         mService.setZenHelper(mockZenModeHelper);
10987         ComponentName owner = new ComponentName("android", "ProviderName");
10988         ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
10989         boolean isEnabled = true;
10990         AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
10991                 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
10992         mBinderService.addAutomaticZenRule(rule, "another.package", false);
10993 
10994         // verify that zen mode helper gets passed in the package name from the arg, not the owner
10995         verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("another.package"), eq(rule),
10996                 eq(ZenModeConfig.ORIGIN_APP), anyString(),
10997                 anyInt());  // doesn't count as a system/systemui call
10998     }
10999 
11000     @Test
testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners()11001     public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception {
11002         ZenModeHelper zenModeHelper = setUpMockZenTest();
11003         mService.setCallerIsNormalPackage();
11004 
11005         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
11006                 .setType(AutomaticZenRule.TYPE_MANAGED)
11007                 .setOwner(new ComponentName(mPkg, "cls"))
11008                 .build();
11009         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
11010 
11011         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
11012 
11013         verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(),
11014                 anyInt());
11015     }
11016 
11017     @Test
testAddAutomaticZenRule_typeManagedCanBeUsedBySystem()11018     public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception {
11019         addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED);
11020     }
11021 
11022     @Test
testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps()11023     public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception {
11024         addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
11025                 AutomaticZenRule.TYPE_MANAGED);
11026     }
11027 
11028     @Test
testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing()11029     public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception {
11030         ZenModeHelper zenModeHelper = setUpMockZenTest();
11031         mService.setCallerIsNormalPackage();
11032         reset(mPackageManagerInternal);
11033         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
11034         when(mResources
11035                 .getString(com.android.internal.R.string.config_systemWellbeing))
11036                 .thenReturn(mPkg);
11037         when(mContext.getResources()).thenReturn(mResources);
11038 
11039         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
11040                 .setType(AutomaticZenRule.TYPE_BEDTIME)
11041                 .setOwner(new ComponentName(mPkg, "cls"))
11042                 .build();
11043 
11044         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
11045 
11046         verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(),
11047                 anyInt());
11048     }
11049 
11050     @Test
testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem()11051     public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception {
11052         reset(mPackageManagerInternal);
11053         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
11054         addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME);
11055     }
11056 
11057     @Test
testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps()11058     public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception {
11059         reset(mPackageManagerInternal);
11060         when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
11061         addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
11062                 AutomaticZenRule.TYPE_BEDTIME);
11063     }
11064 
addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( @utomaticZenRule.Type int ruleType)11065     private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(
11066             @AutomaticZenRule.Type int ruleType) throws Exception {
11067         ZenModeHelper zenModeHelper = setUpMockZenTest();
11068         mService.isSystemUid = true;
11069 
11070         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
11071                 .setType(ruleType)
11072                 .setOwner(new ComponentName(mPkg, "cls"))
11073                 .build();
11074         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
11075 
11076         mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false);
11077 
11078         verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(),
11079                 anyInt());
11080     }
11081 
addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( @utomaticZenRule.Type int ruleType)11082     private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
11083             @AutomaticZenRule.Type int ruleType) {
11084         mService.setCallerIsNormalPackage();
11085         mService.setZenHelper(mock(ZenModeHelper.class));
11086         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
11087                 .thenReturn(true);
11088 
11089         AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
11090                 .setType(ruleType)
11091                 .setOwner(new ComponentName(mPkg, "cls"))
11092                 .build();
11093         when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false);
11094 
11095         assertThrows(IllegalArgumentException.class,
11096                 () -> mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false));
11097     }
11098 
11099     @Test
addAutomaticZenRule_fromUser_mappedToOriginUser()11100     public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception {
11101         ZenModeHelper zenModeHelper = setUpMockZenTest();
11102         mService.isSystemUid = true;
11103 
11104         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true);
11105 
11106         verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE),
11107                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt());
11108     }
11109 
11110     @Test
addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem()11111     public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception {
11112         ZenModeHelper zenModeHelper = setUpMockZenTest();
11113         mService.isSystemUid = true;
11114 
11115         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false);
11116 
11117         verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE),
11118                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt());
11119     }
11120 
11121     @Test
addAutomaticZenRule_fromApp_mappedToOriginApp()11122     public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception {
11123         ZenModeHelper zenModeHelper = setUpMockZenTest();
11124         mService.setCallerIsNormalPackage();
11125 
11126         mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false);
11127 
11128         verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE),
11129                 eq(ZenModeConfig.ORIGIN_APP), anyString(), anyInt());
11130     }
11131 
11132     @Test
addAutomaticZenRule_fromAppFromUser_blocked()11133     public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception {
11134         setUpMockZenTest();
11135         mService.setCallerIsNormalPackage();
11136 
11137         assertThrows(SecurityException.class, () ->
11138                 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true));
11139     }
11140 
11141     @Test
updateAutomaticZenRule_fromUserFromSystem_allowed()11142     public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
11143         ZenModeHelper zenModeHelper = setUpMockZenTest();
11144         mService.isSystemUid = true;
11145 
11146         mBinderService.updateAutomaticZenRule("id", SOME_ZEN_RULE, /* fromUser= */ true);
11147 
11148         verify(zenModeHelper).updateAutomaticZenRule(any(), eq("id"), eq(SOME_ZEN_RULE),
11149                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt());
11150     }
11151 
11152     @Test
updateAutomaticZenRule_fromUserFromApp_blocked()11153     public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
11154         setUpMockZenTest();
11155         mService.setCallerIsNormalPackage();
11156 
11157         assertThrows(SecurityException.class, () ->
11158                 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true));
11159     }
11160 
11161     @Test
removeAutomaticZenRule_fromUserFromSystem_allowed()11162     public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
11163         ZenModeHelper zenModeHelper = setUpMockZenTest();
11164         mService.isSystemUid = true;
11165 
11166         mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true);
11167 
11168         verify(zenModeHelper).removeAutomaticZenRule(any(), eq("id"),
11169                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt());
11170     }
11171 
11172     @Test
removeAutomaticZenRule_fromUserFromApp_blocked()11173     public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
11174         setUpMockZenTest();
11175         mService.setCallerIsNormalPackage();
11176 
11177         assertThrows(SecurityException.class, () ->
11178                 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true));
11179     }
11180 
11181     @Test
setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()11182     public void setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()
11183             throws Exception {
11184         ZenModeHelper zenModeHelper = setUpMockZenTest();
11185         mService.setCallerIsNormalPackage();
11186 
11187         Condition withSourceUser = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11188                 SOURCE_USER_ACTION);
11189         mBinderService.setAutomaticZenRuleState("id", withSourceUser);
11190 
11191         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceUser),
11192                 eq(ZenModeConfig.ORIGIN_USER_IN_APP), anyInt());
11193     }
11194 
11195     @Test
setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()11196     public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()
11197             throws Exception {
11198         ZenModeHelper zenModeHelper = setUpMockZenTest();
11199         mService.setCallerIsNormalPackage();
11200 
11201         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11202                 SOURCE_CONTEXT);
11203         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
11204 
11205         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext),
11206                 eq(ZenModeConfig.ORIGIN_APP), anyInt());
11207     }
11208 
11209     @Test
setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()11210     public void setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()
11211             throws Exception {
11212         ZenModeHelper zenModeHelper = setUpMockZenTest();
11213         mService.isSystemUid = true;
11214 
11215         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11216                 SOURCE_USER_ACTION);
11217         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
11218 
11219         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext),
11220                 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyInt());
11221     }
11222     @Test
setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()11223     public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()
11224             throws Exception {
11225         ZenModeHelper zenModeHelper = setUpMockZenTest();
11226         mService.isSystemUid = true;
11227 
11228         Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE,
11229                 SOURCE_CONTEXT);
11230         mBinderService.setAutomaticZenRuleState("id", withSourceContext);
11231 
11232         verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext),
11233                 eq(ZenModeConfig.ORIGIN_SYSTEM), anyInt());
11234     }
11235 
11236 
11237     @Test
11238     @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER)
getAutomaticZenRules_fromSystem_readsWithCurrentUser()11239     public void getAutomaticZenRules_fromSystem_readsWithCurrentUser() throws Exception {
11240         ZenModeHelper zenModeHelper = setUpMockZenTest();
11241         mService.isSystemUid = true;
11242 
11243         // Representative used to verify getCallingZenUser().
11244         mBinderService.getAutomaticZenRules();
11245 
11246         verify(zenModeHelper).getAutomaticZenRules(eq(UserHandle.CURRENT), anyInt());
11247     }
11248 
11249     @Test
11250     @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER)
getAutomaticZenRules_fromNormalPackage_readsWithBinderUser()11251     public void getAutomaticZenRules_fromNormalPackage_readsWithBinderUser() throws Exception {
11252         ZenModeHelper zenModeHelper = setUpMockZenTest();
11253         mService.setCallerIsNormalPackage();
11254 
11255         // Representative used to verify getCallingZenUser().
11256         mBinderService.getAutomaticZenRules();
11257 
11258         verify(zenModeHelper).getAutomaticZenRules(eq(Binder.getCallingUserHandle()), anyInt());
11259     }
11260 
11261     /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */
setUpMockZenTest()11262     private ZenModeHelper setUpMockZenTest() {
11263         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
11264         mService.setZenHelper(zenModeHelper);
11265         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
11266                 .thenReturn(true);
11267         return zenModeHelper;
11268     }
11269 
11270     @Test
11271     @DisableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS)
onZenModeChanged_sendsBroadcasts_oldBehavior()11272     public void onZenModeChanged_sendsBroadcasts_oldBehavior() throws Exception {
11273         when(mAmi.getCurrentUserId()).thenReturn(100);
11274         when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
11275         when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
11276             @Override
11277             public List<String> answer(InvocationOnMock invocation) {
11278                 int userId = invocation.getArgument(0);
11279                 switch (userId) {
11280                     case 100:
11281                         return Lists.newArrayList("a", "b", "c");
11282                     case 101:
11283                         return Lists.newArrayList();
11284                     case 102:
11285                         return Lists.newArrayList("b");
11286                     default:
11287                         throw new IllegalArgumentException(
11288                                 "Why would you ask for packages of userId " + userId + "?");
11289                 }
11290             }
11291         });
11292 
11293         mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
11294                 "testing!", false);
11295         waitForIdle();
11296 
11297         InOrder inOrder = inOrder(mContext);
11298         // Verify broadcasts for registered receivers
11299         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
11300                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
11301                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null));
11302         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
11303                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
11304                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null));
11305         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
11306                 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
11307                         Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null));
11308 
11309         // Verify broadcast for packages that manage DND.
11310         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11311                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags(
11312                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
11313         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11314                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
11315                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
11316         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11317                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags(
11318                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
11319         inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
11320                 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
11321                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102)));
11322     }
11323 
11324     @Test
11325     @EnableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS)
onZenModeChanged_sendsBroadcasts()11326     public void onZenModeChanged_sendsBroadcasts() throws Exception {
11327         when(mAmi.getCurrentUserId()).thenReturn(100);
11328         when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
11329         when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
11330             @Override
11331             public List<String> answer(InvocationOnMock invocation) {
11332                 int userId = invocation.getArgument(0);
11333                 switch (userId) {
11334                     case 100:
11335                         return Lists.newArrayList("a", "b", "c");
11336                     case 101:
11337                         return Lists.newArrayList();
11338                     case 102:
11339                         return Lists.newArrayList("b");
11340                     default:
11341                         throw new IllegalArgumentException(
11342                                 "Why would you ask for packages of userId " + userId + "?");
11343                 }
11344             }
11345         });
11346         Context context100 = mock(Context.class);
11347         doReturn(context100).when(mContext).createContextAsUser(eq(UserHandle.of(100)), anyInt());
11348         Context context101 = mock(Context.class);
11349         doReturn(context101).when(mContext).createContextAsUser(eq(UserHandle.of(101)), anyInt());
11350         Context context102 = mock(Context.class);
11351         doReturn(context102).when(mContext).createContextAsUser(eq(UserHandle.of(102)), anyInt());
11352 
11353         mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
11354                 "testing!", false);
11355         waitForIdle();
11356 
11357         // Verify broadcasts per user: registered receivers first, then DND packages.
11358         InOrder inOrder = inOrder(context100, context101, context102);
11359 
11360         inOrder.verify(context100).sendBroadcastMultiplePermissions(
11361                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11362                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
11363                 eq(new String[0]), eq(new String[0]), eq(new String[] {"a", "b", "c"}));
11364         inOrder.verify(context100).sendBroadcast(
11365                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11366                         .setPackage("a")
11367                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
11368         inOrder.verify(context100).sendBroadcast(
11369                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11370                         .setPackage("b")
11371                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
11372         inOrder.verify(context100).sendBroadcast(
11373                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11374                         .setPackage("c")
11375                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
11376 
11377         inOrder.verify(context101).sendBroadcastMultiplePermissions(
11378                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11379                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
11380                 eq(new String[0]), eq(new String[0]), eq(new String[] {}));
11381 
11382         inOrder.verify(context102).sendBroadcastMultiplePermissions(
11383                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11384                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
11385                 eq(new String[0]), eq(new String[0]), eq(new String[] {"b"}));
11386         inOrder.verify(context102).sendBroadcast(
11387                 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
11388                         .setPackage("b")
11389                         .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
11390     }
11391 
11392     @Test
onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner()11393     public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception {
11394         mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged(
11395                 mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED));
11396 
11397         Intent expected = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED)
11398                 .setPackage("rule.owner.pkg")
11399                 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, "rule_id")
11400                 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, AUTOMATIC_RULE_STATUS_ACTIVATED)
11401                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
11402 
11403         verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId)));
11404     }
11405 
isIntentWithAction(String wantedAction)11406     private static Intent isIntentWithAction(String wantedAction) {
11407         return argThat(
11408                 intent -> intent != null && wantedAction.equals(intent.getAction())
11409         );
11410     }
11411 
eqIntent(Intent wanted)11412     private static Intent eqIntent(Intent wanted) {
11413         return argThat(
11414                 new ArgumentMatcher<Intent>() {
11415                     @Override
11416                     public boolean matches(Intent argument) {
11417                         return wanted.filterEquals(argument)
11418                                 && wanted.getFlags() == argument.getFlags()
11419                                 && equalBundles(wanted.getExtras(), argument.getExtras());
11420                     }
11421 
11422                     @Override
11423                     public String toString() {
11424                         return wanted.toString();
11425                     }
11426 
11427                     private boolean equalBundles(Bundle one, Bundle two) {
11428                         if (one == null && two == null) {
11429                             return true;
11430                         }
11431                         if ((one == null) != (two == null)) {
11432                             return false;
11433                         }
11434                         if (one.size() != two.size()) {
11435                             return false;
11436                         }
11437 
11438                         HashSet<String> setOne = new HashSet<>(one.keySet());
11439                         setOne.addAll(two.keySet());
11440 
11441                         for (String key : setOne) {
11442                             if (!one.containsKey(key) || !two.containsKey(key)) {
11443                                 return false;
11444                             }
11445 
11446                             Object valueOne = one.get(key);
11447                             Object valueTwo = two.get(key);
11448                             if (valueOne instanceof Bundle
11449                                     && valueTwo instanceof Bundle
11450                                     && !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) {
11451                                 return false;
11452                             } else if (valueOne == null) {
11453                                 if (valueTwo != null) {
11454                                     return false;
11455                                 }
11456                             } else if (!valueOne.equals(valueTwo)) {
11457                                 return false;
11458                             }
11459                         }
11460                         return true;
11461                     }
11462                 });
11463     }
11464 
11465     @Test
11466     public void testAreNotificationsEnabledForPackage() throws Exception {
11467         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
11468                 mUid);
11469 
11470         verify(mPermissionHelper).hasPermission(mUid);
11471     }
11472 
11473     @Test
11474     public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
11475         try {
11476             mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
11477                     mUid + UserHandle.PER_USER_RANGE);
11478             fail("Cannot call cross user without permission");
11479         } catch (SecurityException e) {
11480             // pass
11481         }
11482         verify(mPermissionHelper, never()).hasPermission(anyInt());
11483 
11484         // cross user, with permission, no problem
11485         enableInteractAcrossUsers();
11486         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
11487                 mUid + UserHandle.PER_USER_RANGE);
11488 
11489         verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
11490     }
11491 
11492     @Test
11493     public void testAreNotificationsEnabledForPackage_viaInternalService() {
11494         mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
11495         verify(mPermissionHelper).hasPermission(mUid);
11496     }
11497 
11498     @Test
11499     public void testGetPackageImportance() throws Exception {
11500         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
11501         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
11502                 .isEqualTo(IMPORTANCE_DEFAULT);
11503 
11504         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
11505         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
11506                 .isEqualTo(IMPORTANCE_NONE);
11507     }
11508 
11509     @Test
11510     public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
11511         try {
11512             mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
11513                     mUid + UserHandle.PER_USER_RANGE);
11514             fail("Cannot call cross user without permission");
11515         } catch (SecurityException e) {
11516             // pass
11517         }
11518 
11519         // cross user, with permission, no problem
11520         enableInteractAcrossUsers();
11521         mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
11522                 mUid + UserHandle.PER_USER_RANGE);
11523     }
11524 
11525     private void enableInteractAcrossUsers() {
11526         TestablePermissions perms = mContext.getTestablePermissions();
11527         perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
11528     }
11529 
11530     @Test
11531     public void testNotificationBubbleChanged_false() throws Exception {
11532         setUpPrefsForBubbles(mPkg, mUid,
11533                 true /* global */,
11534                 BUBBLE_PREFERENCE_ALL /* app */,
11535                 true /* channel */);
11536 
11537         // Notif with bubble metadata
11538         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11539                 "testNotificationBubbleChanged_false");
11540 
11541         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11542                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11543         waitForIdle();
11544 
11545         // Reset as this is called when the notif is first sent
11546         reset(mListeners);
11547 
11548         // First we were a bubble
11549         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11550         assertEquals(1, notifsBefore.length);
11551         assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0);
11552 
11553         // Notify we're not a bubble
11554         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
11555         waitForIdle();
11556 
11557         // Make sure we are not a bubble
11558         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11559         assertEquals(1, notifsAfter.length);
11560         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
11561     }
11562 
11563     @Test
11564     public void testNotificationBubbleChanged_true() throws Exception {
11565         setUpPrefsForBubbles(mPkg, mUid,
11566                 true /* global */,
11567                 BUBBLE_PREFERENCE_ALL /* app */,
11568                 true /* channel */);
11569 
11570         // Notif that is not a bubble
11571         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
11572                 1, null, false);
11573         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11574                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11575         waitForIdle();
11576 
11577         // Would be a normal notification because wouldn't have met requirements to bubble
11578         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11579         assertEquals(1, notifsBefore.length);
11580         assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
11581 
11582         // Update the notification to be message style / meet bubble requirements
11583         NotificationRecord nr2 = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11584                 nr.getSbn().getTag());
11585         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr2.getSbn().getTag(),
11586                 nr2.getSbn().getId(), nr2.getSbn().getNotification(), nr2.getSbn().getUserId());
11587         waitForIdle();
11588 
11589         // Reset as this is called when the notif is first sent
11590         reset(mListeners);
11591 
11592         // Notify we are now a bubble
11593         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
11594         waitForIdle();
11595 
11596         // Make sure we are a bubble
11597         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11598         assertEquals(1, notifsAfter.length);
11599         assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
11600     }
11601 
11602     @Test
11603     public void testNotificationBubbleChanged_true_notAllowed() throws Exception {
11604         setUpPrefsForBubbles(mPkg, mUid,
11605                 true /* global */,
11606                 BUBBLE_PREFERENCE_ALL /* app */,
11607                 true /* channel */);
11608 
11609         // Notif that is not a bubble
11610         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
11611         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11612                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11613         waitForIdle();
11614 
11615         // Reset as this is called when the notif is first sent
11616         reset(mListeners);
11617 
11618         // Would be a normal notification because wouldn't have met requirements to bubble
11619         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11620         assertEquals(1, notifsBefore.length);
11621         assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
11622 
11623         // Notify we are now a bubble
11624         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
11625         waitForIdle();
11626 
11627         // We still wouldn't be a bubble because the notification didn't meet requirements
11628         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11629         assertEquals(1, notifsAfter.length);
11630         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
11631     }
11632 
11633     @Test
11634     public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception {
11635         setUpPrefsForBubbles(mPkg, mUid,
11636                 true /* global */,
11637                 BUBBLE_PREFERENCE_ALL /* app */,
11638                 true /* channel */);
11639 
11640         // Notif with bubble metadata
11641         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11642                 "testNotificationBubbleIsFlagRemoved_resetOnUpdate");
11643 
11644         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11645                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11646         waitForIdle();
11647         // Flag shouldn't be modified
11648         NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11649         assertFalse(recordToCheck.isFlagBubbleRemoved());
11650 
11651         // Notify we're not a bubble
11652         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
11653         waitForIdle();
11654         // Flag should be modified
11655         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11656         assertTrue(recordToCheck.isFlagBubbleRemoved());
11657 
11658 
11659         // Update the notif
11660         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11661                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11662         waitForIdle();
11663         // And the flag is reset
11664         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11665         assertFalse(recordToCheck.isFlagBubbleRemoved());
11666     }
11667 
11668     @Test
11669     public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception {
11670         setUpPrefsForBubbles(mPkg, mUid,
11671                 true /* global */,
11672                 BUBBLE_PREFERENCE_ALL /* app */,
11673                 true /* channel */);
11674 
11675         // Notif with bubble metadata
11676         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11677                 "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue");
11678 
11679         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11680                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11681         waitForIdle();
11682         // Flag shouldn't be modified
11683         NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11684         assertFalse(recordToCheck.isFlagBubbleRemoved());
11685 
11686         // Notify we're not a bubble
11687         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
11688         waitForIdle();
11689         // Flag should be modified
11690         recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
11691         assertTrue(recordToCheck.isFlagBubbleRemoved());
11692 
11693         // Notify we are a bubble
11694         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
11695         waitForIdle();
11696         // And the flag is reset
11697         assertFalse(recordToCheck.isFlagBubbleRemoved());
11698     }
11699 
11700     @Test
11701     public void testOnBubbleMetadataFlagChanged() throws Exception {
11702         setUpPrefsForBubbles(mPkg, mUid,
11703                 true /* global */,
11704                 BUBBLE_PREFERENCE_ALL /* app */,
11705                 true /* channel */);
11706 
11707         // Post a bubble notification
11708         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
11709         // Set this so that the bubble can be suppressed
11710         nr.getNotification().getBubbleMetadata().setFlags(
11711                 Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE);
11712         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11713                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11714         waitForIdle();
11715 
11716         // Check the flags
11717         Notification n =  mBinderService.getActiveNotifications(mPkg)[0].getNotification();
11718         assertFalse(n.getBubbleMetadata().isNotificationSuppressed());
11719         assertFalse(n.getBubbleMetadata().getAutoExpandBubble());
11720         assertFalse(n.getBubbleMetadata().isBubbleSuppressed());
11721         assertTrue(n.getBubbleMetadata().isBubbleSuppressable());
11722 
11723         // Reset as this is called when the notif is first sent
11724         reset(mListeners);
11725 
11726         // Test: change the flags
11727         int flags = Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE;
11728         flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
11729         flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
11730         flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
11731         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), flags);
11732         waitForIdle();
11733 
11734         // Check
11735         n =  mBinderService.getActiveNotifications(mPkg)[0].getNotification();
11736         assertEquals(flags, n.getBubbleMetadata().getFlags());
11737 
11738         // Reset to check again
11739         reset(mListeners);
11740 
11741         // Test: clear flags
11742         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 0);
11743         waitForIdle();
11744 
11745         // Check
11746         n = mBinderService.getActiveNotifications(mPkg)[0].getNotification();
11747         assertEquals(0, n.getBubbleMetadata().getFlags());
11748     }
11749 
11750     @Test
11751     public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped()
11752             throws RemoteException {
11753 
11754         setUpPrefsForBubbles(mPkg, mUid,
11755                 true /* global */,
11756                 BUBBLE_PREFERENCE_ALL /* app */,
11757                 true /* channel */);
11758 
11759         // Post a bubble notification
11760         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
11761         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11762                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11763         waitForIdle();
11764 
11765         // Test: suppress notification via bubble metadata update
11766         mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(),
11767                 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
11768         waitForIdle();
11769 
11770         // Check audio is stopped
11771         verify(mAttentionHelper).clearEffectsLocked(nr.getKey());
11772     }
11773 
11774     @Test
11775     public void testGrantInlineReplyUriPermission_recordExists() throws Exception {
11776         int userId = UserManager.isHeadlessSystemUserMode()
11777                 ? UserHandle.getUserId(UID_HEADLESS)
11778                 : USER_SYSTEM;
11779 
11780         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
11781         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
11782                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11783         waitForIdle();
11784 
11785         // A notification exists for the given record
11786         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11787         assertEquals(1, notifsBefore.length);
11788 
11789         reset(mPackageManager);
11790 
11791         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11792 
11793         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11794                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11795                 nr.getSbn().getUid());
11796 
11797         // Grant permission called for the UID of SystemUI under the target user ID
11798         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11799                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
11800                 anyInt(), eq(nr.getSbn().getUserId()));
11801     }
11802 
11803     @Test
11804     public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception {
11805         int userId = UserManager.isHeadlessSystemUserMode()
11806                 ? UserHandle.getUserId(UID_HEADLESS)
11807                 : USER_SYSTEM;
11808 
11809         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
11810         waitForIdle();
11811 
11812         // No notifications exist for the given record
11813         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11814         assertEquals(0, notifsBefore.length);
11815 
11816         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11817 
11818         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11819                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11820                 nr.getSbn().getUid());
11821 
11822         // Grant permission still called if no NotificationRecord exists for the given key
11823         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11824                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
11825                 anyInt(), eq(nr.getSbn().getUserId()));
11826     }
11827 
11828     @Test
11829     public void testGrantInlineReplyUriPermission_userAll() throws Exception {
11830         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
11831         NotificationRecord nr =
11832                 generateNotificationRecord(mTestNotificationChannel, UserHandle.USER_ALL);
11833         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
11834                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11835         waitForIdle();
11836 
11837         // A notification exists for the given record
11838         StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg);
11839         assertEquals(1, notifsBefore.length);
11840 
11841         reset(mPackageManager);
11842 
11843         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11844 
11845         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11846                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11847                 nr.getSbn().getUid());
11848 
11849         // Target user for the grant is USER_ALL instead of USER_SYSTEM
11850         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11851                 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(),
11852                 anyInt(), UserManager.isHeadlessSystemUserMode()
11853                         ? eq(UserHandle.getUserId(UID_HEADLESS))
11854                         : eq(USER_SYSTEM));
11855     }
11856 
11857     @Test
11858     public void testGrantInlineReplyUriPermission_acrossUsers() throws Exception {
11859         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
11860         int otherUserId = 11;
11861         NotificationRecord nr =
11862                 generateNotificationRecord(mTestNotificationChannel, otherUserId);
11863         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
11864                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11865         waitForIdle();
11866 
11867         // A notification exists for the given record
11868         List<StatusBarNotification> notifsBefore =
11869                 mBinderService.getAppActiveNotifications(mPkg, nr.getSbn().getUserId()).getList();
11870         assertEquals(1, notifsBefore.size());
11871 
11872         reset(mPackageManager);
11873 
11874         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11875 
11876         int uid = 0; // sysui on primary user
11877         int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user
11878         String sysuiPackage = "sysui";
11879         final String[] sysuiPackages = new String[] { sysuiPackage };
11880         when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages);
11881 
11882         // Make sure to mock call for USER_SYSTEM and not USER_ALL, since it's been replaced by the
11883         // time this is called
11884         when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId))
11885                 .thenReturn(otherUserUid);
11886 
11887         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11888                 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), uid);
11889 
11890         // Target user for the grant is USER_ALL instead of USER_SYSTEM
11891         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
11892                 eq(otherUserUid), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), anyInt(),
11893                 eq(otherUserId));
11894     }
11895 
11896     @Test
11897     public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception {
11898         int userId = UserManager.isHeadlessSystemUserMode()
11899                 ? UserHandle.getUserId(UID_HEADLESS)
11900                 : USER_SYSTEM;
11901 
11902         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId);
11903         reset(mPackageManager);
11904 
11905         Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11906         Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2);
11907 
11908         // create an inline record with two uris in it
11909         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11910                 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11911                 nr.getSbn().getUid());
11912         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11913                 nr.getKey(), uri2, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11914                 nr.getSbn().getUid());
11915 
11916         InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
11917         assertNotNull(record); // record exists
11918         assertEquals(record.getUris().size(), 2); // record has two uris in it
11919 
11920         mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(),
11921                 nr.getSbn().getUid());
11922 
11923         // permissionOwner destroyed
11924         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
11925                 eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId()));
11926     }
11927 
11928 
11929     @Test
11930     public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception {
11931         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0);
11932         reset(mPackageManager);
11933 
11934         mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(),
11935                 nr.getSbn().getUid());
11936 
11937         // no permissionOwner destroyed
11938         verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner(
11939                 any(), eq(null), eq(~0), eq(nr.getUserId()));
11940     }
11941 
11942     @Test
11943     public void testClearInlineReplyUriPermission_userAll() throws Exception {
11944         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
11945                 UserHandle.USER_ALL);
11946         reset(mPackageManager);
11947 
11948         Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
11949 
11950         // create an inline record a uri in it
11951         mService.mNotificationDelegate.grantInlineReplyUriPermission(
11952                 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(),
11953                 nr.getSbn().getUid());
11954 
11955         InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
11956         assertNotNull(record); // record exists
11957 
11958         mService.mNotificationDelegate.clearInlineReplyUriPermissions(
11959                 nr.getKey(), nr.getSbn().getUid());
11960 
11961         // permissionOwner destroyed for USER_SYSTEM, not USER_ALL
11962         verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
11963                 eq(record.getPermissionOwner()), eq(null), eq(~0),
11964                 UserManager.isHeadlessSystemUserMode()
11965                         ? eq(UserHandle.getUserId(UID_HEADLESS))
11966                         : eq(USER_SYSTEM));
11967     }
11968 
11969     @Test
11970     public void testNotificationBubbles_disabled_lowRamDevice() throws Exception {
11971         setUpPrefsForBubbles(mPkg, mUid,
11972                 true /* global */,
11973                 BUBBLE_PREFERENCE_ALL /* app */,
11974                 true /* channel */);
11975 
11976         // And we are low ram
11977         when(mActivityManager.isLowRamDevice()).thenReturn(true);
11978 
11979         // Notification that would typically bubble
11980         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
11981                 "testNotificationBubbles_disabled_lowRamDevice");
11982         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
11983                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
11984         waitForIdle();
11985 
11986         // But we wouldn't be a bubble because the device is low ram & all bubbles are disabled.
11987         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
11988         assertEquals(1, notifsAfter.length);
11989         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
11990     }
11991 
11992     @Test
11993     @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
11994     public void testRemoveLargeRemoteViews() throws Exception {
11995         // Cast to long to mock RemoteViews.estimateMemoryUsage which returns long.
11996         long removeSize = mContext.getResources().getInteger(
11997                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
11998 
11999         RemoteViews rv = mock(RemoteViews.class);
12000         when(rv.estimateMemoryUsage()).thenReturn(removeSize);
12001         when(rv.clone()).thenReturn(rv);
12002         RemoteViews rv1 = mock(RemoteViews.class);
12003         when(rv1.estimateMemoryUsage()).thenReturn(removeSize);
12004         when(rv1.clone()).thenReturn(rv1);
12005         RemoteViews rv2 = mock(RemoteViews.class);
12006         when(rv2.estimateMemoryUsage()).thenReturn(removeSize);
12007         when(rv2.clone()).thenReturn(rv2);
12008         RemoteViews rv3 = mock(RemoteViews.class);
12009         when(rv3.estimateMemoryUsage()).thenReturn(removeSize);
12010         when(rv3.clone()).thenReturn(rv3);
12011         RemoteViews rv4 = mock(RemoteViews.class);
12012         when(rv4.estimateMemoryUsage()).thenReturn(removeSize);
12013         when(rv4.clone()).thenReturn(rv4);
12014         // note: different!
12015         RemoteViews rv5 = mock(RemoteViews.class);
12016         when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1);
12017         when(rv5.clone()).thenReturn(rv5);
12018 
12019         Notification np = new Notification.Builder(mContext, "test")
12020                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12021                 .setContentText("test")
12022                 .setCustomContentView(rv)
12023                 .setCustomBigContentView(rv1)
12024                 .setCustomHeadsUpContentView(rv2)
12025                 .build();
12026         Notification n = new Notification.Builder(mContext, "test")
12027                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12028                 .setContentText("test")
12029                 .setCustomContentView(rv3)
12030                 .setCustomBigContentView(rv4)
12031                 .setCustomHeadsUpContentView(rv5)
12032                 .setPublicVersion(np)
12033                 .build();
12034 
12035         assertNotNull(np.contentView);
12036         assertNotNull(np.bigContentView);
12037         assertNotNull(np.headsUpContentView);
12038 
12039         assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
12040         assertNotNull(n.publicVersion.contentView);
12041         assertNotNull(n.publicVersion.bigContentView);
12042         assertNotNull(n.publicVersion.headsUpContentView);
12043 
12044         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
12045 
12046         assertNull(n.contentView);
12047         assertNull(n.bigContentView);
12048         assertNotNull(n.headsUpContentView);
12049         assertNull(n.publicVersion.contentView);
12050         assertNull(n.publicVersion.bigContentView);
12051         assertNull(n.publicVersion.headsUpContentView);
12052 
12053         verify(mUsageStats, times(5)).registerImageRemoved(mPkg);
12054     }
12055 
12056     @Test
12057     @EnableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
12058     public void testRemoveRemoteViews() throws Exception {
12059         Notification np = new Notification.Builder(mContext, "test")
12060                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12061                 .setContentText("test")
12062                 .setCustomContentView(mock(RemoteViews.class))
12063                 .setCustomBigContentView(mock(RemoteViews.class))
12064                 .setCustomHeadsUpContentView(mock(RemoteViews.class))
12065                 .build();
12066         Notification n = new Notification.Builder(mContext, "test")
12067                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12068                 .setContentText("test")
12069                 .setCustomContentView(mock(RemoteViews.class))
12070                 .setCustomBigContentView(mock(RemoteViews.class))
12071                 .setCustomHeadsUpContentView(mock(RemoteViews.class))
12072                 .setPublicVersion(np)
12073                 .build();
12074 
12075         assertNotNull(n.contentView);
12076         assertNotNull(n.bigContentView);
12077         assertNotNull(n.headsUpContentView);
12078 
12079         assertTrue(np.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
12080         assertNotNull(np.contentView);
12081         assertNotNull(np.bigContentView);
12082         assertNotNull(np.headsUpContentView);
12083 
12084         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
12085 
12086         assertNull(n.contentView);
12087         assertNull(n.bigContentView);
12088         assertNull(n.headsUpContentView);
12089         assertNull(n.publicVersion.contentView);
12090         assertNull(n.publicVersion.bigContentView);
12091         assertNull(n.publicVersion.headsUpContentView);
12092 
12093         verify(mUsageStats, times(1)).registerImageRemoved(mPkg);
12094     }
12095 
12096     @Test
12097     public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground()
12098             throws Exception {
12099         setUpPrefsForBubbles(mPkg, mUid,
12100                 true /* global */,
12101                 BUBBLE_PREFERENCE_ALL /* app */,
12102                 true /* channel */);
12103 
12104         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12105                 "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground");
12106         // Modify metadata flags
12107         nr.getSbn().getNotification().getBubbleMetadata().setFlags(
12108                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
12109                         | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
12110 
12111         // Ensure we're not foreground
12112         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
12113                 IMPORTANCE_VISIBLE);
12114 
12115         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12116                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12117         waitForIdle();
12118 
12119         // yes allowed, yes messaging, yes bubble
12120         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12121         assertTrue(notif.isBubbleNotification());
12122 
12123         // The flag should have failed since we're not foreground
12124         assertFalse(notif.getBubbleMetadata().getAutoExpandBubble());
12125     }
12126 
12127     @Test
12128     public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground()
12129             throws RemoteException {
12130         setUpPrefsForBubbles(mPkg, mUid,
12131                 true /* global */,
12132                 BUBBLE_PREFERENCE_ALL /* app */,
12133                 true /* channel */);
12134 
12135         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12136                 "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground");
12137         // Modify metadata flags
12138         nr.getSbn().getNotification().getBubbleMetadata().setFlags(
12139                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
12140                         | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
12141 
12142         // Ensure we are in the foreground
12143         when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn(
12144                 IMPORTANCE_FOREGROUND);
12145 
12146         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12147                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12148         waitForIdle();
12149 
12150         // yes allowed, yes messaging, yes bubble
12151         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12152         assertTrue(notif.isBubbleNotification());
12153 
12154         // Our flags should have passed since we are foreground
12155         assertTrue(notif.getBubbleMetadata().getAutoExpandBubble());
12156         assertTrue(notif.getBubbleMetadata().isNotificationSuppressed());
12157     }
12158 
12159     @Test
12160     public void testNotificationBubbles_flagRemoved_whenShortcutRemoved()
12161             throws RemoteException {
12162         setUpPrefsForBubbles(mPkg, mUid,
12163                 true /* global */,
12164                 BUBBLE_PREFERENCE_ALL /* app */,
12165                 true /* channel */);
12166 
12167         ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
12168                 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
12169 
12170         // Messaging notification with shortcut info
12171         Notification.BubbleMetadata metadata =
12172                 new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build();
12173         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12174                 null /* groupKey */, false /* isSummary */, true);
12175         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12176         nb.setBubbleMetadata(metadata);
12177         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12178                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12179         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12180 
12181         // Test: Send the bubble notification
12182         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12183                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12184         waitForIdle();
12185 
12186         // Verify:
12187 
12188         // Make sure we register the callback for shortcut changes
12189         verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
12190                 shortcutChangeCallback.capture());
12191 
12192         // yes allowed, yes messaging w/shortcut, yes bubble
12193         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12194         assertTrue(notif.isBubbleNotification());
12195 
12196         // Make sure the shortcut is cached.
12197         verify(mShortcutServiceInternal).cacheShortcuts(
12198                 anyInt(), any(), eq(mPkg), eq(singletonList(VALID_CONVO_SHORTCUT_ID)),
12199                 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
12200 
12201         // Test: Remove the shortcut
12202         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12203         ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>();
12204         removedShortcuts.add(createMockConvoShortcut());
12205         shortcutChangeCallback.getValue().onShortcutsRemoved(mPkg, removedShortcuts,
12206                 UserHandle.getUserHandleForUid(mUid));
12207         waitForIdle();
12208 
12209         // Verify:
12210 
12211         // Make sure callback is unregistered
12212         verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
12213                 shortcutChangeCallback.getValue());
12214 
12215         // We're no longer a bubble
12216         NotificationRecord notif2 = mService.getNotificationRecord(
12217                 nr.getSbn().getKey());
12218         assertNull(notif2.getShortcutInfo());
12219         assertFalse(notif2.getNotification().isBubbleNotification());
12220     }
12221 
12222     @Test
12223     public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved()
12224             throws RemoteException {
12225         final String shortcutId = "someshortcutId";
12226         setUpPrefsForBubbles(mPkg, mUid,
12227                 true /* global */,
12228                 BUBBLE_PREFERENCE_ALL /* app */,
12229                 true /* channel */);
12230 
12231         ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
12232                 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
12233 
12234         // Messaging notification with shortcut info
12235         Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
12236                 shortcutId).build();
12237         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12238                 null /* groupKey */, false /* isSummary */, true);
12239         nb.setShortcutId(shortcutId);
12240         nb.setBubbleMetadata(metadata);
12241         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12242                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12243         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12244 
12245         // Pretend the shortcut exists
12246         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
12247         ShortcutInfo info = mock(ShortcutInfo.class);
12248         when(info.getPackage()).thenReturn(mPkg);
12249         when(info.getId()).thenReturn(shortcutId);
12250         when(info.getUserId()).thenReturn(USER_SYSTEM);
12251         when(info.isLongLived()).thenReturn(true);
12252         when(info.isEnabled()).thenReturn(true);
12253         shortcutInfos.add(info);
12254         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
12255         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
12256                 anyString(), anyInt(), any())).thenReturn(true);
12257 
12258         // Test: Send the bubble notification
12259         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12260                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12261         waitForIdle();
12262 
12263         // Verify:
12264 
12265         // Make sure we register the callback for shortcut changes
12266         verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
12267                 shortcutChangeCallback.capture());
12268 
12269         // yes allowed, yes messaging w/shortcut, yes bubble
12270         Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
12271         assertTrue(notif.isBubbleNotification());
12272 
12273         // Make sure the shortcut is cached.
12274         verify(mShortcutServiceInternal).cacheShortcuts(
12275                 anyInt(), any(), eq(mPkg), eq(singletonList(shortcutId)),
12276                 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
12277 
12278         // Test: Remove the notification
12279         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12280                 nr.getSbn().getId(), nr.getSbn().getUserId());
12281         waitForIdle();
12282 
12283         // Verify:
12284 
12285         // Make sure callback is unregistered
12286         verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
12287                 shortcutChangeCallback.getValue());
12288     }
12289 
12290     @Test
12291     public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed()
12292             throws Exception {
12293         setUpPrefsForBubbles(mPkg, mUid,
12294                 true /* global */,
12295                 BUBBLE_PREFERENCE_ALL /* app */,
12296                 true /* channel */);
12297 
12298         NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
12299                 true /* summaryAutoCancel */);
12300 
12301         // Dismiss summary
12302         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
12303                 true);
12304         mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg,
12305                 nrSummary.getUserId(), nrSummary.getKey(),
12306                 NotificationStats.DISMISSAL_SHADE,
12307                 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv);
12308         waitForIdle();
12309 
12310         // The bubble should still exist
12311         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12312         assertEquals(1, notifsAfter.length);
12313     }
12314 
12315     @Test
12316     public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked()
12317             throws Exception {
12318         setUpPrefsForBubbles(mPkg, mUid,
12319                 true /* global */,
12320                 BUBBLE_PREFERENCE_ALL /* app */,
12321                 true /* channel */);
12322 
12323         NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
12324                 true /* summaryAutoCancel */);
12325 
12326         // Click summary
12327         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
12328                 true);
12329         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
12330                 nrSummary.getKey(), nv);
12331         waitForIdle();
12332 
12333         // The bubble should still exist
12334         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12335         assertEquals(1, notifsAfter.length);
12336 
12337         // Check we got the click log and associated dismissal logs
12338         assertEquals(6, mNotificationRecordLogger.numCalls());
12339         // Skip the notification-creation logs
12340         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
12341                 mNotificationRecordLogger.event(3));
12342         assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK,
12343                 mNotificationRecordLogger.event(4));
12344         assertEquals(NotificationRecordLogger.NotificationCancelledEvent
12345                         .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED,
12346                 mNotificationRecordLogger.event(5));
12347     }
12348 
12349     @Test
12350     public void testNotificationBubbles_bubbleStays_whenClicked()
12351             throws Exception {
12352         setUpPrefsForBubbles(mPkg, mUid,
12353                 true /* global */,
12354                 BUBBLE_PREFERENCE_ALL /* app */,
12355                 true /* channel */);
12356 
12357         // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble
12358         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
12359         nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL;
12360         mService.addNotification(nr);
12361 
12362         // WHEN we click the notification
12363         final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true);
12364         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
12365                 nr.getKey(), nv);
12366         waitForIdle();
12367 
12368         // THEN the bubble should still exist
12369         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12370         assertEquals(1, notifsAfter.length);
12371 
12372         // Check we got the click log
12373         assertEquals(1, mNotificationRecordLogger.numCalls());
12374         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
12375                 mNotificationRecordLogger.event(0));
12376     }
12377 
12378     /**
12379      * When something is bubble'd and the bubble is dismissed, but the notification is still
12380      * visible, clicking on the notification shouldn't auto-cancel it because clicking on
12381      * it will produce a bubble.
12382      */
12383     @Test
12384     public void testNotificationBubbles_bubbleStays_whenClicked_afterBubbleDismissed()
12385             throws Exception {
12386         setUpPrefsForBubbles(mPkg, mUid,
12387                 true /* global */,
12388                 BUBBLE_PREFERENCE_ALL /* app */,
12389                 true /* channel */);
12390 
12391         // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble
12392         final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
12393         nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL;
12394         nr.setAllowBubble(true);
12395         mService.addNotification(nr);
12396 
12397         // And the bubble is dismissed
12398         mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(),
12399                 false /* isBubble */, 0 /* bubbleFlags */);
12400         waitForIdle();
12401         assertTrue(nr.isFlagBubbleRemoved());
12402 
12403         // WHEN we click the notification
12404         final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true);
12405         mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
12406                 nr.getKey(), nv);
12407         waitForIdle();
12408 
12409         // THEN the bubble should still exist
12410         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg);
12411         assertEquals(1, notifsAfter.length);
12412 
12413         // Check we got the click log
12414         assertEquals(1, mNotificationRecordLogger.numCalls());
12415         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
12416                 mNotificationRecordLogger.event(0));
12417     }
12418 
12419     @Test
12420     public void testLoadDefaultApprovedServices_emptyResources() {
12421         TestableResources tr = mContext.getOrCreateTestableResources();
12422         tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, "");
12423         tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "");
12424         tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, "");
12425 
12426         mService.loadDefaultApprovedServices(USER_SYSTEM);
12427 
12428         verify(mListeners, never()).addDefaultComponentOrPackage(anyString());
12429         verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString());
12430         verify(mAssistants, never()).addDefaultComponentOrPackage(anyString());
12431     }
12432 
12433     @Test
12434     public void testLoadDefaultApprovedServices_dnd() {
12435         TestableResources tr = mContext.getOrCreateTestableResources();
12436         tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test");
12437         when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
12438                 .thenReturn(new ArraySet<>());
12439 
12440         mService.loadDefaultApprovedServices(USER_SYSTEM);
12441 
12442         verify(mConditionProviders, times(1)).loadDefaultsFromConfig();
12443     }
12444 
12445     // TODO: add tests for the rest of the non-empty cases
12446 
12447     @Test
12448     public void testOnUnlockUser() {
12449         UserInfo ui = new UserInfo();
12450         ui.id = 10;
12451         mService.onUserUnlocked(new TargetUser(ui));
12452         waitForIdle();
12453 
12454         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
12455     }
12456 
12457     @Test
12458     public void testOnStopUser() {
12459         UserInfo ui = new UserInfo();
12460         ui.id = 10;
12461         mService.onUserStopping(new TargetUser(ui));
12462         waitForIdle();
12463 
12464         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
12465     }
12466 
12467     @Test
12468     public void testHandleOnPackageChanged() {
12469         String[] pkgs = new String[] {mPkg, PKG_N_MR1};
12470         int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1};
12471 
12472         mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids);
12473 
12474         verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString());
12475 
12476         mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids);
12477 
12478         verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]);
12479         verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]);
12480     }
12481 
12482     @Test
12483     public void testHandleOnPackageRemoved_ClearsHistory() throws Exception {
12484         // Enables Notification History setting
12485         setUpPrefsForHistory(mUserId, true /* =enabled */);
12486 
12487         // Posts a notification to the mTestNotificationChannel.
12488         final NotificationRecord notif = generateNotificationRecord(
12489                 mTestNotificationChannel, 1, null, false);
12490         mService.addNotification(notif);
12491         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(
12492                 notif.getSbn().getPackageName());
12493         assertEquals(1, notifs.length);
12494 
12495         // Cancels all notifications.
12496         mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0,
12497                 notif.getUserId(), REASON_CANCEL);
12498         waitForIdle();
12499         notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
12500         assertEquals(0, notifs.length);
12501 
12502         // Checks that notification history's recently canceled archive contains the notification.
12503         notifs = mBinderService.getHistoricalNotificationsWithAttribution(mPkg,
12504                         mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
12505         waitForIdle();
12506         assertEquals(1, notifs.length);
12507 
12508         // Remove sthe package that contained the channel
12509         simulatePackageRemovedBroadcast(mPkg, mUid);
12510         waitForIdle();
12511 
12512         // Checks that notification history no longer contains the notification.
12513         notifs = mBinderService.getHistoricalNotificationsWithAttribution(
12514                 mPkg, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
12515         waitForIdle();
12516         assertEquals(0, notifs.length);
12517     }
12518 
12519     @Test
12520     public void testNotificationHistory_addNoisyNotification() throws Exception {
12521         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
12522                 null /* tvExtender */);
12523         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12524                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12525         waitForIdle();
12526 
12527         verify(mHistoryManager, times(1)).addNotification(any());
12528     }
12529 
12530     @Test
12531     public void createConversationNotificationChannel() throws Exception {
12532         int userId = UserManager.isHeadlessSystemUserMode()
12533                 ? UserHandle.getUserId(UID_HEADLESS)
12534                 : USER_SYSTEM;
12535 
12536         NotificationChannel original = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
12537         original.setAllowBubbles(!original.canBubble());
12538         original.setShowBadge(!original.canShowBadge());
12539 
12540         Parcel parcel = Parcel.obtain();
12541         original.writeToParcel(parcel, 0);
12542         parcel.setDataPosition(0);
12543         NotificationChannel orig = NotificationChannel.CREATOR.createFromParcel(parcel);
12544         assertEquals(original, orig);
12545         assertFalse(TextUtils.isEmpty(orig.getName()));
12546 
12547         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(Arrays.asList(
12548                 orig)));
12549 
12550         mBinderService.createConversationNotificationChannelForPackage(
12551                 mPkg, mUid, orig, "friend");
12552 
12553         NotificationChannel friendChannel = mBinderService.getConversationNotificationChannel(
12554                 mPkg, userId, mPkg, original.getId(), false, "friend");
12555 
12556         assertEquals(original.getName(), friendChannel.getName());
12557         assertEquals(original.getId(), friendChannel.getParentChannelId());
12558         assertEquals("friend", friendChannel.getConversationId());
12559         assertEquals(null, original.getConversationId());
12560         assertEquals(original.canShowBadge(), friendChannel.canShowBadge());
12561         assertFalse(friendChannel.canBubble()); // can't be modified by app
12562         assertFalse(original.getId().equals(friendChannel.getId()));
12563         assertNotNull(friendChannel.getId());
12564     }
12565 
12566     @Test
12567     public void testCorrectCategory_systemOn_appCannotTurnOff() {
12568         int requested = 0;
12569         int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12570 
12571         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12572                 system);
12573 
12574         assertEquals(PRIORITY_CATEGORY_CONVERSATIONS, actual);
12575     }
12576 
12577     @Test
12578     public void testCorrectCategory_systemOff_appTurnOff_noChanges() {
12579         int requested = PRIORITY_CATEGORY_CALLS;
12580         int system = PRIORITY_CATEGORY_CALLS;
12581 
12582         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12583                 system);
12584 
12585         assertEquals(PRIORITY_CATEGORY_CALLS, actual);
12586     }
12587 
12588     @Test
12589     public void testCorrectCategory_systemOn_appTurnOn_noChanges() {
12590         int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12591         int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12592 
12593         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12594                 system);
12595 
12596         assertEquals(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS, actual);
12597     }
12598 
12599     @Test
12600     public void testCorrectCategory_systemOff_appCannotTurnOn() {
12601         int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS;
12602         int system = PRIORITY_CATEGORY_CALLS;
12603 
12604         int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS,
12605                 system);
12606 
12607         assertEquals(PRIORITY_CATEGORY_CALLS, actual);
12608     }
12609 
12610     @Test
12611     public void testRestoreConversationChannel_deleted() throws Exception {
12612         // Create parent channel
12613         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12614         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12615                 IMPORTANCE_DEFAULT);
12616         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12617                 NotificationChannel.CREATOR);
12618         assertEquals(originalChannel, parentChannel);
12619         mBinderService.createNotificationChannels(mPkg,
12620                 new ParceledListSlice(Arrays.asList(parentChannel)));
12621 
12622         //Create deleted conversation channel
12623         mBinderService.createConversationNotificationChannelForPackage(
12624                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
12625         final NotificationChannel conversationChannel =
12626                 mBinderService.getConversationNotificationChannel(
12627                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
12628         conversationChannel.setDeleted(true);
12629 
12630         //Create notification record
12631         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12632                 null /* groupKey */, false /* isSummary */, true);
12633         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12634         nb.setChannelId(originalChannel.getId());
12635         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12636                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12637         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12638         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12639 
12640         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12641                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12642         waitForIdle();
12643 
12644         // Verify that the channel was changed to the conversation channel and restored
12645         assertThat(mService.getNotificationRecord(nr.getKey()).isConversation()).isTrue();
12646         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
12647                 conversationChannel);
12648         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().isDeleted()).isFalse();
12649         assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().getDeletedTimeMs())
12650                 .isEqualTo(-1);
12651     }
12652 
12653     @Test
12654     public void testDoNotRestoreParentChannel_deleted() throws Exception {
12655         // Create parent channel and set as deleted
12656         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12657         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12658                 IMPORTANCE_DEFAULT);
12659         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12660                 NotificationChannel.CREATOR);
12661         assertEquals(originalChannel, parentChannel);
12662         mBinderService.createNotificationChannels(mPkg,
12663                 new ParceledListSlice(Arrays.asList(parentChannel)));
12664         parentChannel.setDeleted(true);
12665 
12666         //Create notification record
12667         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12668                 null /* groupKey */, false /* isSummary */, true);
12669         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12670         nb.setChannelId(originalChannel.getId());
12671         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12672                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12673         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12674         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12675 
12676         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
12677 
12678         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12679                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12680         waitForIdle();
12681 
12682         // Verify that the channel was not restored and the notification was not posted
12683         assertThat(mService.mChannelToastsSent).contains(mUid);
12684         assertThat(mService.getNotificationRecord(nr.getKey())).isNull();
12685         assertThat(parentChannel.isDeleted()).isTrue();
12686     }
12687 
12688     @Test
12689     public void testEnqueueToConversationChannel_notDeleted_doesNotRestore() throws Exception {
12690         TestableNotificationManagerService service = spy(mService);
12691         PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper);
12692         service.setPreferencesHelper(preferencesHelper);
12693         // Create parent channel
12694         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12695         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12696                 IMPORTANCE_DEFAULT);
12697         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12698                 NotificationChannel.CREATOR);
12699         assertEquals(originalChannel, parentChannel);
12700         mBinderService.createNotificationChannels(mPkg,
12701                 new ParceledListSlice(Arrays.asList(parentChannel)));
12702 
12703         //Create conversation channel
12704         mBinderService.createConversationNotificationChannelForPackage(
12705                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
12706         final NotificationChannel conversationChannel =
12707                 mBinderService.getConversationNotificationChannel(
12708                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
12709 
12710         //Create notification record
12711         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12712                 null /* groupKey */, false /* isSummary */, true);
12713         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
12714         nb.setChannelId(originalChannel.getId());
12715         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12716                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12717         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12718         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12719 
12720         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12721                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12722         waitForIdle();
12723 
12724         // Verify that the channel was changed to the conversation channel and not restored
12725         assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isTrue();
12726         assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
12727                 conversationChannel);
12728         verify(service, never()).handleSavePolicyFile();
12729         verify(preferencesHelper, never()).createNotificationChannel(anyString(),
12730                 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean());
12731     }
12732 
12733     @Test
12734     public void testEnqueueToParentChannel_notDeleted_doesNotRestore() throws Exception {
12735         TestableNotificationManagerService service = spy(mService);
12736         PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper);
12737         service.setPreferencesHelper(preferencesHelper);
12738         // Create parent channel
12739         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
12740         final NotificationChannel originalChannel = new NotificationChannel("id", "name",
12741                 IMPORTANCE_DEFAULT);
12742         NotificationChannel parentChannel = parcelAndUnparcel(originalChannel,
12743                 NotificationChannel.CREATOR);
12744         assertEquals(originalChannel, parentChannel);
12745         mBinderService.createNotificationChannels(mPkg,
12746                 new ParceledListSlice(Arrays.asList(parentChannel)));
12747 
12748         //Create deleted conversation channel
12749         mBinderService.createConversationNotificationChannelForPackage(
12750                 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID);
12751         final NotificationChannel conversationChannel =
12752                 mBinderService.getConversationNotificationChannel(
12753                         mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID);
12754 
12755         //Create notification record without a shortcutId
12756         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12757                 null /* groupKey */, false /* isSummary */, true);
12758         nb.setShortcutId(null);
12759         nb.setChannelId(originalChannel.getId());
12760         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12761                 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
12762         NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel);
12763         assertThat(nr.getChannel()).isEqualTo(originalChannel);
12764 
12765         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12766                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12767         waitForIdle();
12768 
12769         // Verify that the channel is the parent channel and no channel was restored
12770         //assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isFalse();
12771         assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo(
12772                 parentChannel);
12773         verify(service, never()).handleSavePolicyFile();
12774         verify(preferencesHelper, never()).createNotificationChannel(anyString(),
12775                 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean());
12776     }
12777 
12778     @Test
12779     public void testGetConversationsForPackage_hasShortcut() throws Exception {
12780         mService.setPreferencesHelper(mPreferencesHelper);
12781         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
12782         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
12783         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
12784         channel1.setConversationId("parent1", "convo 1");
12785         convo1.setNotificationChannel(channel1);
12786         convos.add(convo1);
12787 
12788         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
12789         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
12790         channel2.setConversationId("parent1", "convo 2");
12791         convo2.setNotificationChannel(channel2);
12792         convos.add(convo2);
12793         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
12794 
12795         ShortcutInfo si = mock(ShortcutInfo.class);
12796         when(si.getPackage()).thenReturn(PKG_P);
12797         when(si.getId()).thenReturn("convo");
12798         when(si.getUserId()).thenReturn(USER_SYSTEM);
12799         when(si.getLabel()).thenReturn("Hello");
12800         when(si.isLongLived()).thenReturn(true);
12801         when(si.isEnabled()).thenReturn(true);
12802         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
12803         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
12804                 anyString(), anyInt(), any())).thenReturn(true);
12805 
12806         List<ConversationChannelWrapper> conversations =
12807                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12808         assertEquals(si, conversations.get(0).getShortcutInfo());
12809         assertEquals(si, conversations.get(1).getShortcutInfo());
12810 
12811         // Returns null shortcuts when locked.
12812         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(false);
12813         conversations =
12814                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12815         assertThat(conversations.get(0).getShortcutInfo()).isNull();
12816         assertThat(conversations.get(1).getShortcutInfo()).isNull();
12817     }
12818 
12819     @Test
12820     public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception {
12821         mService.setPreferencesHelper(mPreferencesHelper);
12822         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
12823         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
12824         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
12825         channel1.setConversationId("parent1", "convo 1");
12826         convo1.setNotificationChannel(channel1);
12827         convos.add(convo1);
12828 
12829         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
12830         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
12831         channel2.setConversationId("parent1", "convo 2");
12832         convo2.setNotificationChannel(channel2);
12833         convos.add(convo2);
12834         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
12835 
12836         ShortcutInfo si = mock(ShortcutInfo.class);
12837         when(si.getPackage()).thenReturn(PKG_P);
12838         when(si.getId()).thenReturn("convo");
12839         when(si.getUserId()).thenReturn(USER_SYSTEM);
12840         when(si.getLabel()).thenReturn("Hello");
12841         when(si.isLongLived()).thenReturn(false);
12842         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
12843 
12844         List<ConversationChannelWrapper> conversations =
12845                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12846         assertNull(conversations.get(0).getShortcutInfo());
12847         assertNull(conversations.get(1).getShortcutInfo());
12848     }
12849 
12850     @Test
12851     public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception {
12852         mService.setPreferencesHelper(mPreferencesHelper);
12853         ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
12854         ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
12855         NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
12856         channel1.setConversationId("parent1", "convo 1");
12857         convo1.setNotificationChannel(channel1);
12858         convos.add(convo1);
12859 
12860         ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
12861         NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
12862         channel2.setConversationId("parent1", "convo 2");
12863         convo2.setNotificationChannel(channel2);
12864         convos.add(convo2);
12865         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
12866         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12867 
12868         List<ConversationChannelWrapper> conversations =
12869                 mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
12870         assertNull(conversations.get(0).getShortcutInfo());
12871         assertNull(conversations.get(1).getShortcutInfo());
12872     }
12873 
12874     @Test
12875     public void testShortcutHelperNull_doesntCrashEnqueue() throws RemoteException {
12876         mService.setShortcutHelper(null);
12877         NotificationRecord nr =
12878                 generateMessageBubbleNotifRecord(mTestNotificationChannel,
12879                         "testShortcutHelperNull_doesntCrashEnqueue");
12880         try {
12881             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12882                     nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12883             waitForIdle();
12884         } catch (Exception e) {
12885             fail(e.getMessage());
12886         }
12887     }
12888 
12889     @Test
12890     public void testRecordMessages_invalidMsg() throws RemoteException {
12891         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12892                 null /* groupKey */, false /* isSummary */, true);
12893         nb.setShortcutId(null);
12894         StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
12895                 "testRecordMessages_invalidMsg", mUid, 0, nb.build(),
12896                 UserHandle.getUserHandleForUid(mUid), null, 0);
12897         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12898 
12899         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12900         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
12901                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12902         waitForIdle();
12903 
12904         assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
12905     }
12906 
12907     @Test
12908     public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException {
12909         Notification.Builder nb = new Notification.Builder(mContext,
12910                 mTestNotificationChannel.getId())
12911                 .setContentTitle("foo")
12912                 .setShortcutId(null)
12913                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
12914                 .setCategory(Notification.CATEGORY_MESSAGE);
12915         StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1,
12916                 "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(),
12917                 UserHandle.getUserHandleForUid(mUid), null, 0);
12918         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12919 
12920         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
12921         mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(),
12922                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12923         waitForIdle();
12924 
12925         // PKG_O is allowed to be in conversation space b/c of override in
12926         // TestableNotificationManagerService
12927         assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid));
12928     }
12929 
12930     @Test
12931     public void testRecordMessages_validMsg() throws RemoteException {
12932         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12933                 null /* groupKey */, false /* isSummary */, true);
12934         nb.setShortcutId(null);
12935         StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
12936                 "testRecordMessages_validMsg", mUid, 0, nb.build(),
12937                 UserHandle.getUserHandleForUid(mUid), null, 0);
12938         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12939 
12940         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
12941                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12942         waitForIdle();
12943 
12944         assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
12945 
12946         nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12947                 "testRecordMessages_validMsg");
12948 
12949         mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
12950                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12951         waitForIdle();
12952 
12953         assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid));
12954     }
12955 
12956     @Test
12957     public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException {
12958         NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
12959                 "testRecordMessages_invalidMsg_afterValidMsg_1");
12960         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12961                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12962         waitForIdle();
12963         assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation());
12964 
12965         mBinderService.cancelAllNotifications(mPkg, mUid);
12966         waitForIdle();
12967 
12968         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
12969                 null /* groupKey */, false /* isSummary */, true);
12970         nb.setShortcutId(null);
12971         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1,
12972                 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
12973                 UserHandle.getUserHandleForUid(mUid), null, 0);
12974          nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
12975 
12976         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
12977                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
12978         waitForIdle();
12979 
12980         assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation());
12981     }
12982 
12983     @Test
12984     public void testCanPostFgsWhenOverLimit() throws RemoteException {
12985         when(mAmi.applyForegroundServiceNotification(
12986                 any(), anyString(), anyInt(), anyString(), anyInt()))
12987                 .thenReturn(SHOW_IMMEDIATELY);
12988         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
12989             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
12990                     i, null, false).getSbn();
12991             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12992                     "testCanPostFgsWhenOverLimit",
12993                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
12994         }
12995 
12996         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
12997         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
12998         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
12999                 "testCanPostFgsWhenOverLimit - fgs over limit!",
13000                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13001 
13002         waitForIdle();
13003 
13004         StatusBarNotification[] notifs =
13005                 mBinderService.getActiveNotifications(sbn.getPackageName());
13006         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
13007         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
13008                 mService.getNotificationRecordCount());
13009     }
13010 
13011     @Test
13012     public void testCannotPostNonFgsWhenOverLimit() throws RemoteException {
13013         when(mAmi.applyForegroundServiceNotification(
13014                 any(), anyString(), anyInt(), anyString(), anyInt()))
13015                 .thenReturn(SHOW_IMMEDIATELY);
13016         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
13017             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
13018                     i, null, false).getSbn();
13019             mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13020                     "testCanPostFgsWhenOverLimit",
13021                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
13022             waitForIdle();
13023         }
13024 
13025         final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
13026                 100, null, false).getSbn();
13027         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
13028         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13029                 "testCanPostFgsWhenOverLimit - fgs over limit!",
13030                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
13031 
13032         final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
13033                 101, null, false).getSbn();
13034         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13035                 "testCanPostFgsWhenOverLimit - non fgs over limit!",
13036                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
13037 
13038 
13039         when(mAmi.applyForegroundServiceNotification(
13040                 any(), anyString(), anyInt(), anyString(), anyInt()))
13041                 .thenReturn(NOT_FOREGROUND_SERVICE);
13042         final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
13043                 101, null, false).getSbn();
13044         sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
13045         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
13046                 "testCanPostFgsWhenOverLimit - fake fgs over limit!",
13047                 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
13048 
13049         waitForIdle();
13050 
13051         StatusBarNotification[] notifs =
13052                 mBinderService.getActiveNotifications(sbn.getPackageName());
13053         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
13054         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
13055                 mService.getNotificationRecordCount());
13056     }
13057 
13058     @Test
13059     public void testIsVisibleToListener_notEnabled() {
13060         StatusBarNotification sbn = mock(StatusBarNotification.class);
13061         when(sbn.getUserId()).thenReturn(10);
13062         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13063         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
13064         info.userid = 10;
13065         when(info.isSameUser(anyInt())).thenReturn(true);
13066         when(assistant.isSameUser(anyInt())).thenReturn(true);
13067         when(info.enabledAndUserMatches(info.userid)).thenReturn(false);
13068         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13069 
13070         assertFalse(mService.isVisibleToListener(sbn, 0, info));
13071     }
13072 
13073     @Test
13074     public void testIsVisibleToListener_noAssistant() {
13075         StatusBarNotification sbn = mock(StatusBarNotification.class);
13076         when(sbn.getUserId()).thenReturn(10);
13077         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13078         info.userid = 10;
13079         when(info.isSameUser(anyInt())).thenReturn(true);
13080         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13081         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null);
13082 
13083         assertTrue(mService.isVisibleToListener(sbn, 0, info));
13084     }
13085 
13086     @Test
13087     public void testIsVisibleToListener_assistant_differentUser() {
13088         StatusBarNotification sbn = mock(StatusBarNotification.class);
13089         when(sbn.getUserId()).thenReturn(10);
13090         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13091         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
13092         info.userid = 0;
13093         when(info.isSameUser(anyInt())).thenReturn(true);
13094         when(assistant.isSameUser(anyInt())).thenReturn(true);
13095         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13096         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13097 
13098         assertFalse(mService.isVisibleToListener(sbn, 0, info));
13099     }
13100 
13101     @Test
13102     public void testIsVisibleToListener_assistant_sameUser() {
13103         StatusBarNotification sbn = mock(StatusBarNotification.class);
13104         when(sbn.getUserId()).thenReturn(10);
13105         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13106         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
13107         info.userid = 10;
13108         when(info.isSameUser(anyInt())).thenReturn(true);
13109         when(assistant.isSameUser(anyInt())).thenReturn(true);
13110         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13111         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13112 
13113         assertTrue(mService.isVisibleToListener(sbn, 0, info));
13114     }
13115 
13116     @Test
13117     public void testIsVisibleToListener_mismatchedType() {
13118         when(mNlf.isTypeAllowed(anyInt())).thenReturn(false);
13119 
13120         StatusBarNotification sbn = mock(StatusBarNotification.class);
13121         when(sbn.getUserId()).thenReturn(10);
13122         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13123         ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
13124         info.userid = 10;
13125         when(info.isSameUser(anyInt())).thenReturn(true);
13126         when(assistant.isSameUser(anyInt())).thenReturn(true);
13127         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13128         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13129 
13130         assertFalse(mService.isVisibleToListener(sbn, 0, info));
13131     }
13132 
13133     @Test
13134     public void testIsVisibleToListener_disallowedPackage() {
13135         when(mNlf.isPackageAllowed(any())).thenReturn(false);
13136 
13137         StatusBarNotification sbn = mock(StatusBarNotification.class);
13138         when(sbn.getUserId()).thenReturn(10);
13139         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13140         ManagedServices.ManagedServiceInfo assistant =
13141                 mock(ManagedServices.ManagedServiceInfo.class);
13142         info.userid = 10;
13143         when(info.isSameUser(anyInt())).thenReturn(true);
13144         when(assistant.isSameUser(anyInt())).thenReturn(true);
13145         when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
13146         when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
13147 
13148         assertFalse(mService.isVisibleToListener(sbn, 0, info));
13149     }
13150 
13151     @Test
13152     public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() {
13153         final NotificationRecord parent = spy(generateNotificationRecord(
13154                 mTestNotificationChannel, 1, "group", true));
13155         final NotificationRecord child = spy(generateNotificationRecord(
13156                 mTestNotificationChannel, 2, "group", false));
13157         mService.addNotification(parent);
13158         mService.addNotification(child);
13159 
13160         InOrder inOrder = inOrder(parent, child);
13161 
13162         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
13163                 parent.getUserId());
13164         waitForIdle();
13165         inOrder.verify(parent).recordDismissalSentiment(anyInt());
13166         inOrder.verify(child).recordDismissalSentiment(anyInt());
13167     }
13168 
13169     @Test
13170     public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() {
13171         final NotificationRecord parent = spy(generateNotificationRecord(
13172                 mTestNotificationChannel, 1, "group", true));
13173         final NotificationRecord child = spy(generateNotificationRecord(
13174                 mTestNotificationChannel, 2, "group", false));
13175         mService.addNotification(child);
13176         mService.addNotification(parent);
13177 
13178         InOrder inOrder = inOrder(parent, child);
13179 
13180         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
13181                 parent.getUserId());
13182         waitForIdle();
13183         inOrder.verify(parent).recordDismissalSentiment(anyInt());
13184         inOrder.verify(child).recordDismissalSentiment(anyInt());
13185     }
13186 
13187     @Test
13188     public void testImmutableBubbleIntent() throws Exception {
13189         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13190         NotificationRecord r = generateMessageBubbleNotifRecord(true,
13191                 mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false, false);
13192         try {
13193             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13194                     r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13195 
13196             waitForIdle();
13197             fail("Allowed a bubble with an immutable intent to be posted");
13198         } catch (IllegalArgumentException e) {
13199             // good
13200         }
13201     }
13202 
13203     @Test
13204     public void testMutableBubbleIntent() throws Exception {
13205         NotificationRecord r = generateMessageBubbleNotifRecord(true,
13206                 mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false, true);
13207 
13208         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13209                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13210 
13211         waitForIdle();
13212         StatusBarNotification[] notifs =
13213                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
13214         assertEquals(1, notifs.length);
13215     }
13216 
13217     @Test
13218     public void testImmutableDirectReplyActionIntent() throws Exception {
13219         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13220         NotificationRecord r = generateMessageBubbleNotifRecord(false,
13221                 mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false,
13222                 false);
13223         try {
13224             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13225                     r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13226 
13227             waitForIdle();
13228             fail("Allowed a direct reply with an immutable intent to be posted");
13229         } catch (IllegalArgumentException e) {
13230             // good
13231         }
13232     }
13233 
13234     @Test
13235     public void testMutableDirectReplyActionIntent() throws Exception {
13236         NotificationRecord r = generateMessageBubbleNotifRecord(false,
13237                 mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false,
13238                 true);
13239         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13240                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13241 
13242         waitForIdle();
13243         StatusBarNotification[] notifs =
13244                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
13245         assertEquals(1, notifs.length);
13246     }
13247 
13248     @Test
13249     public void testImmutableDirectReplyContextualActionIntent() throws Exception {
13250         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13251         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13252 
13253         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13254         ArrayList<Notification.Action> extraAction = new ArrayList<>();
13255         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
13256         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
13257         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
13258                 mActivityIntentImmutable).addRemoteInput(remoteInput)
13259                 .build();
13260         extraAction.add(replyAction);
13261         Bundle signals = new Bundle();
13262         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
13263         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
13264                 r.getUser());
13265         r.addAdjustment(adjustment);
13266         r.applyAdjustments();
13267 
13268         try {
13269             mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
13270                     r.getSbn().getTag(), r, false, false);
13271             fail("Allowed a contextual direct reply with an immutable intent to be posted");
13272         } catch (IllegalArgumentException e) {
13273             // good
13274         }
13275     }
13276 
13277     @Test
13278     public void testMutableDirectReplyContextualActionIntent() throws Exception {
13279         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13280         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13281         ArrayList<Notification.Action> extraAction = new ArrayList<>();
13282         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
13283         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
13284         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
13285                 mActivityIntent).addRemoteInput(remoteInput)
13286                 .build();
13287         extraAction.add(replyAction);
13288         Bundle signals = new Bundle();
13289         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
13290         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
13291                 r.getUser());
13292         r.addAdjustment(adjustment);
13293         r.applyAdjustments();
13294 
13295         mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
13296                 r.getSbn().getTag(), r, false, false);
13297     }
13298 
13299     @Test
13300     public void testImmutableActionIntent() throws Exception {
13301         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13302         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13303         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
13304                 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
13305 
13306         waitForIdle();
13307         StatusBarNotification[] notifs =
13308                 mBinderService.getActiveNotifications(r.getSbn().getPackageName());
13309         assertEquals(1, notifs.length);
13310     }
13311 
13312     @Test
13313     public void testImmutableContextualActionIntent() throws Exception {
13314         when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
13315         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13316         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
13317         ArrayList<Notification.Action> extraAction = new ArrayList<>();
13318         extraAction.add(new Notification.Action(0, "hello", mActivityIntentImmutable));
13319         Bundle signals = new Bundle();
13320         signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
13321         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
13322                 r.getUser());
13323         r.addAdjustment(adjustment);
13324         r.applyAdjustments();
13325 
13326         mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
13327                     r.getSbn().getTag(), r, false, false);
13328     }
13329 
13330     @Test
13331     public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception {
13332         int uid = 9000;
13333         int[] userIds = new int[] {mUserId, 1000};
13334         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13335         List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
13336         for (int userId : userIds) {
13337             for (String pkg : disallowedApps) {
13338                 when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++);
13339             }
13340         }
13341 
13342         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
13343                 new NotificationListenerFilter());
13344 
13345         mBinderService.migrateNotificationFilter(null,
13346                 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13347                 disallowedApps);
13348 
13349         ArgumentCaptor<NotificationListenerFilter> captor =
13350                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13351         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13352 
13353         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13354                 captor.getValue().getTypes());
13355         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000)));
13356         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002)));
13357         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003)));
13358 
13359         // hypothetical other user untouched
13360         assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000)));
13361     }
13362 
13363     @Test
13364     public void testMigrateNotificationFilter_invalidPackage() throws Exception {
13365         int[] userIds = new int[] {mUserId, 1000};
13366         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13367         List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
13368         for (int userId : userIds) {
13369             when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow(
13370                     new RemoteException(""));
13371             when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000);
13372             when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001);
13373         }
13374 
13375         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
13376                 new NotificationListenerFilter());
13377 
13378         mBinderService.migrateNotificationFilter(null,
13379                 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13380                 disallowedApps);
13381 
13382         ArgumentCaptor<NotificationListenerFilter> captor =
13383                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13384         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13385 
13386         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
13387                 captor.getValue().getTypes());
13388         // valid values stay
13389         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000)));
13390         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001)));
13391         // don't store invalid values
13392         for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) {
13393             assertNotEquals("apples", vp.getPackageName());
13394         }
13395     }
13396 
13397     @Test
13398     public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception {
13399         int[] userIds = new int[] {mUserId};
13400         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13401         List<String> disallowedApps = ImmutableList.of("apples");
13402         when(mPackageManager.getPackageUid("apples", 0, mUserId))
13403                 .thenReturn(1001);
13404 
13405         when(mListeners.getNotificationListenerFilter(any())).thenReturn(null);
13406 
13407         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
13408                 disallowedApps);
13409 
13410         ArgumentCaptor<NotificationListenerFilter> captor =
13411                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13412         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13413 
13414         assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
13415         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
13416     }
13417 
13418     @Test
13419     public void testMigrateNotificationFilter_existingTypeFilter() throws Exception {
13420         int[] userIds = new int[] {mUserId};
13421         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13422         List<String> disallowedApps = ImmutableList.of("apples");
13423         when(mPackageManager.getPackageUid("apples", 0, mUserId))
13424                 .thenReturn(1001);
13425 
13426         when(mListeners.getNotificationListenerFilter(any())).thenReturn(
13427                 new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>()));
13428 
13429         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
13430                 disallowedApps);
13431 
13432         ArgumentCaptor<NotificationListenerFilter> captor =
13433                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13434         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13435 
13436         // type isn't saved but pkg list is
13437         assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes());
13438         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
13439     }
13440 
13441     @Test
13442     public void testMigrateNotificationFilter_existingPkgFilter() throws Exception {
13443         int[] userIds = new int[] {mUserId};
13444         when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
13445         List<String> disallowedApps = ImmutableList.of("apples");
13446         when(mPackageManager.getPackageUid("apples", 0, mUserId))
13447                 .thenReturn(1001);
13448 
13449         NotificationListenerFilter preexisting = new NotificationListenerFilter();
13450         preexisting.addPackage(new VersionedPackage("test", 1002));
13451         when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting);
13452 
13453         mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
13454                 disallowedApps);
13455 
13456         ArgumentCaptor<NotificationListenerFilter> captor =
13457                 ArgumentCaptor.forClass(NotificationListenerFilter.class);
13458         verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
13459 
13460         // type is saved but pkg list isn't
13461         assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
13462         assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
13463         assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002)));
13464     }
13465 
13466     @Test
13467     public void getPackagesBypassingDnd_blocked()
13468             throws RemoteException, PackageManager.NameNotFoundException {
13469 
13470         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
13471                 NotificationManager.IMPORTANCE_MAX);
13472         NotificationChannel channel2 = new NotificationChannel("id3", "name3",
13473                 NotificationManager.IMPORTANCE_MAX);
13474         NotificationChannel channel3 = new NotificationChannel("id4", "name3",
13475                 NotificationManager.IMPORTANCE_MAX);
13476         channel1.setBypassDnd(true);
13477         channel2.setBypassDnd(true);
13478         channel3.setBypassDnd(false);
13479         // has DND access, so can set bypassDnd attribute
13480         mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
13481                 /*has DND access*/ true, UID_N_MR1, false);
13482         mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true,
13483                 UID_P, false);
13484         mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
13485                 UID_P, false);
13486 
13487         when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P);
13488         when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt()))
13489                 .thenReturn(UID_N_MR1);
13490         when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false);
13491         when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true);
13492 
13493         enableInteractAcrossUsers();
13494         assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList())
13495                 .containsExactly(new ZenBypassingApp(PKG_P, false));
13496     }
13497 
13498     @Test
13499     public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
13500         mService.setPreferencesHelper(mPreferencesHelper);
13501 
13502         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13503 
13504         assertThat(mBinderService.getNotificationChannelsBypassingDnd(mPkg, mUid).getList())
13505                 .isEmpty();
13506         verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid);
13507     }
13508 
13509     @Test
13510     public void testGetPackagesBypassingDnd_empty() throws RemoteException {
13511         mService.setPreferencesHelper(mPreferencesHelper);
13512         List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList();
13513         assertThat(result).isEmpty();
13514     }
13515 
13516     @Test
13517     public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception {
13518         // set the testable NMS to not system uid/appid
13519         mService.isSystemUid = false;
13520         mService.isSystemAppId = false;
13521 
13522         // make sure a caller without listener access or read_contacts permission can't call
13523         // matchesCallFilter.
13524         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
13525         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
13526                 eq("android.permission.READ_CONTACTS"), anyString());
13527 
13528         try {
13529             // shouldn't matter what we're passing in, if we get past this line fail immediately
13530             ((INotificationManager) mService.mService).matchesCallFilter(null);
13531             fail("call to matchesCallFilter with no permissions should fail");
13532         } catch (SecurityException e) {
13533             // pass
13534         }
13535     }
13536 
13537     @Test
13538     public void testMatchesCallFilter_hasSystemPermission() throws Exception {
13539         // set the testable NMS to system uid
13540         mService.isSystemUid = true;
13541 
13542         // make sure caller doesn't have listener access or read_contacts permission
13543         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
13544         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
13545                 eq("android.permission.READ_CONTACTS"), anyString());
13546 
13547         try {
13548             ((INotificationManager) mService.mService).matchesCallFilter(null);
13549             // pass, but check that we actually checked for system permissions
13550             assertTrue(mService.countSystemChecks > 0);
13551         } catch (SecurityException e) {
13552             fail("call to matchesCallFilter with just system permissions should work");
13553         }
13554     }
13555 
13556     @Test
13557     public void testMatchesCallFilter_hasListenerPermission() throws Exception {
13558         mService.isSystemUid = false;
13559         mService.isSystemAppId = false;
13560 
13561         // make sure a caller with only listener access and not read_contacts permission can call
13562         // matchesCallFilter.
13563         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(true);
13564         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
13565                 eq("android.permission.READ_CONTACTS"), anyString());
13566 
13567         try {
13568             ((INotificationManager) mService.mService).matchesCallFilter(null);
13569             // pass, this is not a functionality test
13570         } catch (SecurityException e) {
13571             fail("call to matchesCallFilter with listener permissions should work");
13572         }
13573     }
13574 
13575     @Test
13576     public void testMatchesCallFilter_hasContactsPermission() throws Exception {
13577         mService.isSystemUid = false;
13578         mService.isSystemAppId = false;
13579 
13580         // make sure a caller with only read_contacts permission and not listener access can call
13581         // matchesCallFilter.
13582         when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false);
13583         doNothing().when(mContext).enforceCallingPermission(
13584                 eq("android.permission.READ_CONTACTS"), anyString());
13585 
13586         try {
13587             ((INotificationManager) mService.mService).matchesCallFilter(null);
13588             // pass, this is not a functionality test
13589         } catch (SecurityException e) {
13590             fail("call to matchesCallFilter with listener permissions should work");
13591         }
13592     }
13593 
13594     @Test
13595     public void testMediaNotificationsBypassBlock() throws Exception {
13596         when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
13597                 .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
13598         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13599 
13600         Notification.Builder nb = new Notification.Builder(
13601                 mContext, mTestNotificationChannel.getId())
13602                 .setContentTitle("foo")
13603                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13604                 .addAction(new Notification.Action.Builder(null, "test", null).build());
13605         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13606                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13607         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13608 
13609         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13610 
13611         // normal blocked notifications - blocked
13612         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13613                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13614 
13615         // just using the style - blocked
13616         nb.setStyle(new Notification.MediaStyle());
13617         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13618                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13619         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13620 
13621         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13622                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13623 
13624         // using the style, but incorrect type in session - blocked
13625         nb.setStyle(new Notification.MediaStyle());
13626         Bundle extras = new Bundle();
13627         extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
13628         nb.addExtras(extras);
13629         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13630                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13631         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13632 
13633         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13634                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13635 
13636         // style + media session - bypasses block
13637         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
13638         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13639                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13640         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13641 
13642         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13643                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13644     }
13645 
13646     @Test
13647     public void testMediaNotificationsBypassBlock_atPost() throws Exception {
13648         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
13649         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13650 
13651         Notification.Builder nb = new Notification.Builder(
13652                 mContext, mTestNotificationChannel.getId())
13653                 .setContentTitle("foo")
13654                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13655                 .addAction(new Notification.Action.Builder(null, "test", null).build());
13656         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13657                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13658         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13659 
13660         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
13661 
13662         mService.addEnqueuedNotification(r);
13663         NotificationManagerService.PostNotificationRunnable runnable =
13664                 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
13665                         r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
13666         runnable.run();
13667         waitForIdle();
13668 
13669         verify(mUsageStats).registerBlocked(any());
13670         verify(mUsageStats, never()).registerPostedByApp(any());
13671 
13672         // just using the style - blocked
13673         mService.clearNotifications();
13674         reset(mUsageStats);
13675         nb.setStyle(new Notification.MediaStyle());
13676         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13677                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13678         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13679 
13680         mService.addEnqueuedNotification(r);
13681         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
13682                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
13683         runnable.run();
13684         waitForIdle();
13685 
13686         verify(mUsageStats).registerBlocked(any());
13687         verify(mUsageStats, never()).registerPostedByApp(any());
13688 
13689         // style + media session - bypasses block
13690         mService.clearNotifications();
13691         reset(mUsageStats);
13692         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
13693         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13694                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13695         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13696 
13697         mService.addEnqueuedNotification(r);
13698         runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
13699                 r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
13700         runnable.run();
13701         waitForIdle();
13702 
13703         verify(mUsageStats, never()).registerBlocked(any());
13704         verify(mUsageStats).registerPostedByApp(any());
13705     }
13706 
13707     @Test
13708     public void testCallNotificationsBypassBlock() throws Exception {
13709         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13710 
13711         Notification.Builder nb = new Notification.Builder(
13712                 mContext, mTestNotificationChannel.getId())
13713                 .setContentTitle("foo")
13714                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
13715                 .addAction(new Notification.Action.Builder(null, "test", null).build());
13716         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13717                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13718         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13719 
13720         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13721 
13722         // normal blocked notifications - blocked
13723         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13724                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13725 
13726         // just using the style - blocked
13727         Person person = new Person.Builder()
13728                 .setName("caller")
13729                 .build();
13730         nb.setStyle(Notification.CallStyle.forOngoingCall(
13731                 person, mActivityIntent));
13732         nb.setFullScreenIntent(mActivityIntent, true);
13733         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13734                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13735         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13736 
13737         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13738                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
13739 
13740         // style + managed call - bypasses block
13741         when(mTelecomManager.isInManagedCall()).thenReturn(true);
13742         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13743                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13744 
13745         // style + self managed call - bypasses block
13746         when(mTelecomManager.isInSelfManagedCall(
13747                 r.getSbn().getPackageName(), UserHandle.ALL)).thenReturn(true);
13748         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13749                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
13750 
13751         // set telecom manager to null - blocked
13752         mService.setTelecomManager(null);
13753         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13754                            r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
13755                 .isFalse();
13756 
13757         // set telecom feature to false - blocked
13758         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
13759         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13760                            r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
13761                 .isFalse();
13762 
13763         // telecom manager is not ready - blocked
13764         mService.setTelecomManager(mTelecomManager);
13765         when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
13766         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
13767                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
13768                 .isFalse();
13769     }
13770 
13771     @Test
13772     public void testCallNotificationsBypassBlock_atPost() throws Exception {
13773         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
13774         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
13775 
13776         Notification.Builder nb =
13777                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
13778                         .setContentTitle("foo")
13779                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
13780                         .addAction(new Notification.Action.Builder(null, "test", null).build());
13781         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
13782                 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
13783         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13784 
13785         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
13786 
13787         // normal blocked notifications - blocked
13788         mService.addEnqueuedNotification(r);
13789         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13790                 mPostNotificationTrackerFactory.newTracker(null)).run();
13791         waitForIdle();
13792 
13793         verify(mUsageStats).registerBlocked(any());
13794         verify(mUsageStats, never()).registerPostedByApp(any());
13795 
13796         // just using the style - blocked
13797         mService.clearNotifications();
13798         reset(mUsageStats);
13799         Person person = new Person.Builder().setName("caller").build();
13800         nb.setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent));
13801         nb.setFullScreenIntent(mActivityIntent, true);
13802         sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, nb.build(),
13803                 UserHandle.getUserHandleForUid(mUid), null, 0);
13804         r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
13805 
13806         mService.addEnqueuedNotification(r);
13807         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13808                 mPostNotificationTrackerFactory.newTracker(null)).run();
13809         waitForIdle();
13810 
13811         verify(mUsageStats).registerBlocked(any());
13812         verify(mUsageStats, never()).registerPostedByApp(any());
13813 
13814         // style + managed call - bypasses block
13815         mService.clearNotifications();
13816         reset(mUsageStats);
13817         when(mTelecomManager.isInManagedCall()).thenReturn(true);
13818 
13819         mService.addEnqueuedNotification(r);
13820         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13821                 mPostNotificationTrackerFactory.newTracker(null)).run();
13822         waitForIdle();
13823 
13824         verify(mUsageStats, never()).registerBlocked(any());
13825         verify(mUsageStats).registerPostedByApp(any());
13826 
13827         // style + self managed call - bypasses block
13828         mService.clearNotifications();
13829         reset(mUsageStats);
13830         when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), UserHandle.ALL))
13831                 .thenReturn(true);
13832 
13833         mService.addEnqueuedNotification(r);
13834         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13835                 mPostNotificationTrackerFactory.newTracker(null)).run();
13836         waitForIdle();
13837 
13838         verify(mUsageStats, never()).registerBlocked(any());
13839         verify(mUsageStats).registerPostedByApp(any());
13840 
13841         // set telecom manager to null - notifications should be blocked
13842         // but post notifications runnable should not crash
13843         mService.clearNotifications();
13844         reset(mUsageStats);
13845         mService.setTelecomManager(null);
13846 
13847         mService.addEnqueuedNotification(r);
13848         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13849                 mPostNotificationTrackerFactory.newTracker(null)).run();
13850         waitForIdle();
13851 
13852         verify(mUsageStats).registerBlocked(any());
13853         verify(mUsageStats, never()).registerPostedByApp(any());
13854 
13855         // set FEATURE_TELECOM to false - notifications should be blocked
13856         // but post notifications runnable should not crash
13857         mService.setTelecomManager(mTelecomManager);
13858         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
13859         reset(mUsageStats);
13860         mService.setTelecomManager(null);
13861 
13862         mService.addEnqueuedNotification(r);
13863         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13864                 mPostNotificationTrackerFactory.newTracker(null)).run();
13865         waitForIdle();
13866 
13867         verify(mUsageStats).registerBlocked(any());
13868         verify(mUsageStats, never()).registerPostedByApp(any());
13869 
13870         // telecom is not ready - notifications should be blocked but no crashes
13871         mService.setTelecomManager(mTelecomManager);
13872         when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
13873         reset(mUsageStats);
13874 
13875         mService.addEnqueuedNotification(r);
13876         mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
13877                 mPostNotificationTrackerFactory.newTracker(null)).run();
13878         waitForIdle();
13879 
13880         verify(mUsageStats).registerBlocked(any());
13881         verify(mUsageStats, never()).registerPostedByApp(any());
13882     }
13883 
13884     @Test
13885     public void testGetAllUsersNotificationPermissions() {
13886         // In this case, there are multiple users each with notification permissions (and also,
13887         // for good measure, some without).
13888         // make sure the collection returned contains info for all of them
13889         final List<UserInfo> userInfos = new ArrayList<>();
13890         userInfos.add(new UserInfo(0, "user0", 0));
13891         userInfos.add(new UserInfo(1, "user1", 0));
13892         userInfos.add(new UserInfo(2, "user2", 0));
13893         when(mUm.getUsers()).thenReturn(userInfos);
13894 
13895         // construct the permissions for each of them
13896         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
13897                 permissions1 = new ArrayMap<>();
13898         permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
13899         permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
13900         permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
13901         permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
13902         when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
13903         when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
13904         when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
13905 
13906         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
13907                 mService.getAllUsersNotificationPermissions();
13908         assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
13909         assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
13910         assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
13911         assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
13912         assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
13913         assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
13914         assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
13915         assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
13916     }
13917 
13918     @Test
13919     public void testGetActiveNotification_filtersUsers() throws Exception {
13920         when(mUm.getProfileIds(mUserId, false)).thenReturn(new int[]{mUserId, 10});
13921 
13922         NotificationRecord nr0 =
13923                 generateNotificationRecord(mTestNotificationChannel, mUserId);
13924         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
13925                 nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());
13926 
13927         NotificationRecord nr10 =
13928                 generateNotificationRecord(mTestNotificationChannel, 10);
13929         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag10",
13930                 nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());
13931 
13932         NotificationRecord nr11 =
13933                 generateNotificationRecord(mTestNotificationChannel, 11);
13934         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag11",
13935                 nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
13936         waitForIdle();
13937 
13938         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg);
13939         assertEquals(2, notifs.length);
13940         for (StatusBarNotification sbn : notifs) {
13941             if (sbn.getUserId() == 11) {
13942                 fail("leaked data across users");
13943             }
13944         }
13945     }
13946 
13947     @Test
13948     public void testGetActiveNotificationsFromListener_redactNotification() throws Exception {
13949         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
13950         NotificationRecord r =
13951                 generateNotificationRecord(mTestNotificationChannel, 0, 0);
13952         mService.addNotification(r);
13953         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
13954         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
13955         StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
13956         when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted);
13957         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13958         info.userid = 0;
13959         when(info.isSameUser(anyInt())).thenReturn(true);
13960         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
13961         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
13962         List<StatusBarNotification> notifications = mBinderService
13963                 .getActiveNotificationsFromListener(mock(INotificationListener.class), null, -1)
13964                 .getList();
13965 
13966         boolean foundRedactedSbn = false;
13967         for (StatusBarNotification sbn: notifications) {
13968             String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString();
13969             if (REDACTED_TEXT.equals(text)) {
13970                 foundRedactedSbn = true;
13971                 break;
13972             }
13973         }
13974         assertTrue("expect to find a redacted notification", foundRedactedSbn);
13975     }
13976 
13977     @Test
13978     public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception {
13979         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
13980         NotificationRecord r =
13981                 generateNotificationRecord(mTestNotificationChannel, 0, 0);
13982         when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r));
13983         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
13984         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
13985         StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
13986         when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted);
13987         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
13988         info.userid = 0;
13989         when(info.isSameUser(anyInt())).thenReturn(true);
13990         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
13991         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
13992         List<StatusBarNotification> notifications = mBinderService
13993                 .getSnoozedNotificationsFromListener(mock(INotificationListener.class), -1)
13994                 .getList();
13995 
13996         boolean foundRedactedSbn = false;
13997         for (StatusBarNotification sbn: notifications) {
13998             String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString();
13999             if (REDACTED_TEXT.equals(text)) {
14000                 foundRedactedSbn = true;
14001                 break;
14002             }
14003         }
14004         assertTrue("expect to find a redacted notification", foundRedactedSbn);
14005     }
14006 
14007     @Test
14008     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14009     public void testCancelAutogroupSummary_cancelsAllChildren() throws Exception {
14010         final String originalGroupName = "originalGroup";
14011         final String aggregateGroupName = "Aggregate_Test";
14012         final int summaryId = Integer.MAX_VALUE;
14013         // Add 2 group notifications without a summary
14014         NotificationRecord nr0 =
14015                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
14016         NotificationRecord nr1 =
14017                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
14018         mService.addNotification(nr0);
14019         mService.addNotification(nr1);
14020         mService.mSummaryByGroupKey.remove(nr0.getGroupKey());
14021 
14022         // GroupHelper is a mock, so make the calls it would make
14023         // Add aggregate group summary
14024         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
14025                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
14026                 nr0.getChannel().getId());
14027         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
14028                 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
14029         mService.addNotification(aggregateSummary);
14030         nr0.setOverrideGroupKey(aggregateGroupName);
14031         nr1.setOverrideGroupKey(aggregateGroupName);
14032         final String fullAggregateGroupKey = nr0.getGroupKey();
14033 
14034         // Check that the aggregate group summary was created
14035         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
14036         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
14037                 nr0.getChannel().getId());
14038         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
14039 
14040         // Cancel aggregate group summary
14041         mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(),
14042                 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId());
14043         waitForIdle();
14044 
14045         // Check that child notifications are also removed
14046         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary));
14047         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0));
14048         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1));
14049 
14050         // Make sure the summary was removed and not re-posted
14051         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
14052     }
14053 
14054     @Test
14055     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14056     public void testCancelAutogroupSummary_forceGrouping_cancelsAllChildren() throws Exception {
14057         final String originalGroupName = "originalGroup";
14058         final String aggregateGroupName = "Aggregate_Test";
14059         final int summaryId = Integer.MAX_VALUE;
14060         // Add 2 group notifications without a summary
14061         NotificationRecord nr0 =
14062                 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false);
14063         NotificationRecord nr1 =
14064                 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false);
14065         mService.addNotification(nr0);
14066         mService.addNotification(nr1);
14067         mService.mSummaryByGroupKey.remove(nr0.getGroupKey());
14068 
14069         // GroupHelper is a mock, so make the calls it would make
14070         // Add aggregate group summary
14071         NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS,
14072                 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN,
14073                 nr0.getChannel().getId());
14074         NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(),
14075                 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr);
14076         mService.addNotification(aggregateSummary);
14077         nr0.setOverrideGroupKey(aggregateGroupName);
14078         nr1.setOverrideGroupKey(aggregateGroupName);
14079         final String fullAggregateGroupKey = nr0.getGroupKey();
14080 
14081         // Check that the aggregate group summary was created
14082         assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName);
14083         assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
14084                 nr0.getChannel().getId());
14085         assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue();
14086 
14087         // Cancel aggregate group summary
14088         mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(),
14089                 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId());
14090         waitForIdle();
14091 
14092         // Check that child notifications are also removed
14093         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary), any(),
14094                 eq(false));
14095         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any(), eq(false));
14096         verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any(), eq(false));
14097 
14098         // Make sure the summary was removed and not re-posted
14099         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
14100     }
14101 
14102     @Test
14103     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14104     public void testUngroupingOngoingAutoSummary() throws Exception {
14105         NotificationRecord nr0 =
14106                 generateNotificationRecord(mTestNotificationChannel, 0);
14107         NotificationRecord nr1 =
14108                 generateNotificationRecord(mTestNotificationChannel, 0);
14109         nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT;
14110 
14111         mService.addNotification(nr0);
14112         mService.addNotification(nr1);
14113 
14114         // grouphelper is a mock here, so make the calls it would make
14115 
14116         // add summary
14117         NotificationAttributes attr = new NotificationAttributes(
14118                 GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
14119                 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14120         mService.addNotification(
14121                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14122                     nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14123 
14124         // cancel both children
14125         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
14126                 nr0.getSbn().getId(), nr0.getSbn().getUserId());
14127         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
14128                 nr1.getSbn().getId(), nr1.getSbn().getUserId());
14129         waitForIdle();
14130 
14131         // group helper would send 'remove summary' event
14132         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(),
14133                 AUTOGROUP_KEY);
14134         waitForIdle();
14135 
14136         // make sure the summary was removed and not re-posted
14137         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
14138     }
14139 
14140     @Test
14141     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14142     public void testUngroupingOngoingAutoSummary_forceGrouping() throws Exception {
14143         NotificationRecord nr0 =
14144             generateNotificationRecord(mTestNotificationChannel, 0);
14145         NotificationRecord nr1 =
14146             generateNotificationRecord(mTestNotificationChannel, 0);
14147         nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT;
14148 
14149         mService.addNotification(nr0);
14150         mService.addNotification(nr1);
14151 
14152         // grouphelper is a mock here, so make the calls it would make
14153 
14154         // add summary
14155         NotificationAttributes attr = new NotificationAttributes(
14156             GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
14157             VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14158         mService.addNotification(
14159             mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14160                 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14161 
14162         // cancel both children
14163         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
14164             nr0.getSbn().getId(), nr0.getSbn().getUserId());
14165         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(),
14166             nr1.getSbn().getId(), nr1.getSbn().getUserId());
14167         waitForIdle();
14168 
14169         // group helper would send 'remove summary' event
14170         mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(),
14171             AUTOGROUP_KEY);
14172         waitForIdle();
14173 
14174         // make sure the summary was removed and not re-posted
14175         assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
14176     }
14177 
14178     @Test
14179     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14180     public void testUngroupingAutoSummary_differentUsers() throws Exception {
14181         NotificationRecord nr0 =
14182                 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM);
14183         NotificationRecord nr1 =
14184                 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM);
14185 
14186         // add notifications + summary for USER_SYSTEM
14187         NotificationAttributes attr = new NotificationAttributes(
14188             GroupHelper.BASE_FLAGS, mock(Icon.class), 0,
14189             VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14190         mService.addNotification(nr0);
14191         mService.addNotification(nr1);
14192         mService.addNotification(
14193                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14194                 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14195 
14196         // add notifications + summary for USER_ALL
14197         NotificationRecord nr0_all =
14198                 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL);
14199         NotificationRecord nr1_all =
14200                 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL);
14201 
14202         mService.addNotification(nr0_all);
14203         mService.addNotification(nr1_all);
14204         mService.addNotification(
14205                 mService.createAutoGroupSummary(nr0_all.getUserId(),
14206                 nr0_all.getSbn().getPackageName(),
14207                 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14208 
14209         // cancel both children for USER_ALL
14210         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(),
14211                 nr0_all.getSbn().getId(), UserHandle.USER_ALL);
14212         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(),
14213                 nr1_all.getSbn().getId(), UserHandle.USER_ALL);
14214         waitForIdle();
14215 
14216         // group helper would send 'remove summary' event
14217         mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL,
14218                 nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY);
14219         waitForIdle();
14220 
14221         // make sure the right summary was removed
14222         assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(),
14223                 UserHandle.USER_ALL, 0, null)).isEqualTo(0);
14224 
14225         // the USER_SYSTEM notifications + summary were not removed
14226         assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(),
14227                 USER_SYSTEM, 0, null)).isEqualTo(3);
14228     }
14229 
14230     @Test
14231     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
14232     public void testUngroupingAutoSummary_differentUsers_forceGrouping() throws Exception {
14233         NotificationRecord nr0 =
14234             generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM);
14235         NotificationRecord nr1 =
14236             generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM);
14237 
14238         // add notifications + summary for USER_SYSTEM
14239         NotificationAttributes attr = new NotificationAttributes(
14240             GroupHelper.BASE_FLAGS, mock(Icon.class), 0,
14241             VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID);
14242         mService.addNotification(nr0);
14243         mService.addNotification(nr1);
14244         mService.addNotification(
14245             mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
14246                 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14247 
14248         // add notifications + summary for USER_ALL
14249         NotificationRecord nr0_all =
14250             generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL);
14251         NotificationRecord nr1_all =
14252             generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL);
14253 
14254         mService.addNotification(nr0_all);
14255         mService.addNotification(nr1_all);
14256         mService.addNotification(
14257             mService.createAutoGroupSummary(nr0_all.getUserId(),
14258                 nr0_all.getSbn().getPackageName(),
14259                 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr));
14260 
14261         // cancel both children for USER_ALL
14262         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(),
14263             nr0_all.getSbn().getId(), UserHandle.USER_ALL);
14264         mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(),
14265             nr1_all.getSbn().getId(), UserHandle.USER_ALL);
14266         waitForIdle();
14267 
14268         // group helper would send 'remove summary' event
14269         mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL,
14270             nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY);
14271         waitForIdle();
14272 
14273         // make sure the right summary was removed
14274         assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(),
14275             UserHandle.USER_ALL, 0, null)).isEqualTo(0);
14276 
14277         // the USER_SYSTEM notifications + summary were not removed
14278         assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(),
14279             USER_SYSTEM, 0, null)).isEqualTo(3);
14280     }
14281 
14282     @Test
14283     public void testStrongAuthTracker_isInLockDownMode() {
14284         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
14285                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
14286         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
14287         assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
14288         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId());
14289         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
14290         assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
14291     }
14292 
14293     @Test
14294     public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() {
14295         // post 2 notifications from 2 packages
14296         NotificationRecord pkgA = new NotificationRecord(mContext,
14297                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14298         mService.addNotification(pkgA);
14299         NotificationRecord pkgB = new NotificationRecord(mContext,
14300                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
14301         mService.addNotification(pkgB);
14302 
14303         // when entering the lockdown mode, cancel the 2 notifications.
14304         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
14305                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
14306         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14307         assertTrue(mStrongAuthTracker.isInLockDownMode(0));
14308 
14309         // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
14310         ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
14311         verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
14312         assertEquals(REASON_LOCKDOWN, captor.getValue().intValue());
14313 
14314         // exit lockdown mode.
14315         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
14316         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14317         assertFalse(mStrongAuthTracker.isInLockDownMode(0));
14318 
14319         // the notifyPostedLocked function is called twice.
14320         verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong());
14321     }
14322 
14323     @Test
14324     public void testMakeRankingUpdateLockedInLockDownMode() {
14325         // post 2 notifications from a same package
14326         NotificationRecord pkgA = new NotificationRecord(mContext,
14327                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14328         mService.addNotification(pkgA);
14329         NotificationRecord pkgB = new NotificationRecord(mContext,
14330                 generateSbn("a", 1000, 9, 1), mTestNotificationChannel);
14331         mService.addNotification(pkgB);
14332 
14333         mService.setIsVisibleToListenerReturnValue(true);
14334         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14335         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14336         assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
14337 
14338         // when only user 0 entering the lockdown mode, its notification will be suppressed.
14339         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
14340                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
14341         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14342         assertTrue(mStrongAuthTracker.isInLockDownMode(0));
14343         assertFalse(mStrongAuthTracker.isInLockDownMode(1));
14344 
14345         nru = mService.makeRankingUpdateLocked(info);
14346         assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
14347 
14348         // User 0 exits lockdown mode. Its notification will be resumed.
14349         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
14350         mStrongAuthTracker.onStrongAuthRequiredChanged(0);
14351         assertFalse(mStrongAuthTracker.isInLockDownMode(0));
14352         assertFalse(mStrongAuthTracker.isInLockDownMode(1));
14353 
14354         nru = mService.makeRankingUpdateLocked(info);
14355         assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
14356     }
14357 
14358     @Test
14359     public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() {
14360         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
14361         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
14362         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
14363         NotificationRecord pkgA = new NotificationRecord(mContext,
14364                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14365         addSmartActionsAndReplies(pkgA);
14366         mService.addNotification(pkgA);
14367         NotificationRecord pkgB = new NotificationRecord(mContext,
14368                 generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
14369         addSmartActionsAndReplies(pkgB);
14370         mService.addNotification(pkgB);
14371 
14372         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14373         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
14374         when(info.isSameUser(anyInt())).thenReturn(true);
14375         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14376         NotificationListenerService.Ranking ranking =
14377                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14378         assertEquals(0, ranking.getSmartActions().size());
14379         assertEquals(0, ranking.getSmartReplies().size());
14380         NotificationListenerService.Ranking ranking2 =
14381                 nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey());
14382         assertEquals(0, ranking2.getSmartActions().size());
14383         assertEquals(0, ranking2.getSmartReplies().size());
14384     }
14385 
14386     private NotificationRecord getSensitiveNotificationRecord() {
14387         NotificationRecord record = new NotificationRecord(mContext,
14388                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14389         Bundle signals = new Bundle();
14390         signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true);
14391         Adjustment adjustment = new Adjustment("a", record.getKey(), signals, "", 0);
14392         record.addAdjustment(adjustment);
14393         record.applyAdjustments();
14394         return record;
14395     }
14396 
14397     @Test
14398     public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() {
14399         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
14400         when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
14401         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
14402         NotificationRecord pkgA = getSensitiveNotificationRecord();
14403         addSmartActionsAndReplies(pkgA);
14404 
14405         mService.addNotification(pkgA);
14406         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14407         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
14408         when(info.isSameUser(anyInt())).thenReturn(true);
14409         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14410         NotificationListenerService.Ranking ranking =
14411                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14412         assertEquals(1, ranking.getSmartActions().size());
14413         assertEquals(1, ranking.getSmartReplies().size());
14414     }
14415 
14416     @Test
14417     public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() {
14418         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
14419         NotificationRecord pkgA = new NotificationRecord(mContext,
14420                 generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
14421         addSmartActionsAndReplies(pkgA);
14422 
14423         mService.addNotification(pkgA);
14424         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
14425         when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
14426         when(info.isSameUser(anyInt())).thenReturn(true);
14427 
14428         // No sensitive content, no redaction
14429         when(mListeners.isUidTrusted(eq(1000))).thenReturn(false);
14430         when(mListeners.hasSensitiveContent(any())).thenReturn(false);
14431         NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
14432         NotificationListenerService.Ranking ranking =
14433                 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14434         assertEquals(1, ranking.getSmartActions().size());
14435         assertEquals(1, ranking.getSmartReplies().size());
14436 
14437         // trusted listener, no redaction
14438         when(mListeners.isUidTrusted(eq(1000))).thenReturn(true);
14439         when(mListeners.hasSensitiveContent(any())).thenReturn(true);
14440         nru = mService.makeRankingUpdateLocked(info);
14441         ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
14442         assertEquals(1, ranking.getSmartActions().size());
14443         assertEquals(1, ranking.getSmartReplies().size());
14444     }
14445 
14446     private void addSmartActionsAndReplies(NotificationRecord record) {
14447         Bundle b = new Bundle();
14448         ArrayList<Notification.Action> actions = new ArrayList<>();
14449         actions.add(new Notification.Action(0, "", null));
14450         b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions);
14451         ArrayList<CharSequence> replies = new ArrayList<>(List.of("test"));
14452         b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies);
14453         Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(),
14454                 b, "", record.getUserId());
14455         record.addAdjustment(a);
14456         record.applyAdjustments();
14457     }
14458 
14459     @Test
14460     public void testMaybeShowReviewPermissionsNotification_flagOff() {
14461         mService.setShowReviewPermissionsNotification(false);
14462         reset(mMockNm);
14463 
14464         // If state is SHOULD_SHOW, it would show, but not if the flag is off!
14465         Settings.Global.putInt(mContext.getContentResolver(),
14466                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14467                 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW);
14468         mService.maybeShowInitialReviewPermissionsNotification();
14469         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14470     }
14471 
14472     @Test
14473     public void testMaybeShowReviewPermissionsNotification_unknown() {
14474         mService.setShowReviewPermissionsNotification(true);
14475         reset(mMockNm);
14476 
14477         // Set up various possible states of the settings int and confirm whether or not the
14478         // notification is shown as expected
14479 
14480         // Initial state: default/unknown setting, make sure nothing happens
14481         Settings.Global.putInt(mContext.getContentResolver(),
14482                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14483                 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN);
14484         mService.maybeShowInitialReviewPermissionsNotification();
14485         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14486     }
14487 
14488     @Test
14489     public void testMaybeShowReviewPermissionsNotification_shouldShow() {
14490         mService.setShowReviewPermissionsNotification(true);
14491         reset(mMockNm);
14492 
14493         // If state is SHOULD_SHOW, it ... should show
14494         Settings.Global.putInt(mContext.getContentResolver(),
14495                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14496                 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW);
14497         mService.maybeShowInitialReviewPermissionsNotification();
14498         verify(mMockNm, times(1)).notify(eq(TAG),
14499                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
14500                 any(Notification.class));
14501     }
14502 
14503     @Test
14504     public void testMaybeShowReviewPermissionsNotification_alreadyShown() {
14505         mService.setShowReviewPermissionsNotification(true);
14506         reset(mMockNm);
14507 
14508         // If state is either USER_INTERACTED or DISMISSED, we should not show this on boot
14509         Settings.Global.putInt(mContext.getContentResolver(),
14510                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14511                 NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED);
14512         mService.maybeShowInitialReviewPermissionsNotification();
14513 
14514         Settings.Global.putInt(mContext.getContentResolver(),
14515                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14516                 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED);
14517         mService.maybeShowInitialReviewPermissionsNotification();
14518 
14519         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14520     }
14521 
14522     @Test
14523     public void testMaybeShowReviewPermissionsNotification_reshown() {
14524         mService.setShowReviewPermissionsNotification(true);
14525         reset(mMockNm);
14526 
14527         // If we have re-shown the notification and the user did not subsequently interacted with
14528         // it, then make sure we show when trying on boot
14529         Settings.Global.putInt(mContext.getContentResolver(),
14530                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14531                 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN);
14532         mService.maybeShowInitialReviewPermissionsNotification();
14533         verify(mMockNm, times(1)).notify(eq(TAG),
14534                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
14535                 any(Notification.class));
14536     }
14537 
14538     @Test
14539     public void testRescheduledReviewPermissionsNotification() {
14540         mService.setShowReviewPermissionsNotification(true);
14541         reset(mMockNm);
14542 
14543         // when rescheduled, the notification goes through the NotificationManagerInternal service
14544         // this call doesn't need to know anything about previously scheduled state -- if called,
14545         // it should send the notification & write the appropriate int to Settings
14546         mInternalService.sendReviewPermissionsNotification();
14547 
14548         // Notification should be sent
14549         verify(mMockNm, times(1)).notify(eq(TAG),
14550                 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS),
14551                 any(Notification.class));
14552 
14553         // write STATE_RESHOWN to settings
14554         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN,
14555                 Settings.Global.getInt(mContext.getContentResolver(),
14556                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
14557                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
14558     }
14559 
14560     @Test
14561     public void testRescheduledReviewPermissionsNotification_flagOff() {
14562         mService.setShowReviewPermissionsNotification(false);
14563         reset(mMockNm);
14564 
14565         // no notification should be sent if the flag is off
14566         mInternalService.sendReviewPermissionsNotification();
14567         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
14568     }
14569 
14570     private void verifyStickyHun(int permissionState, boolean appRequested,
14571             boolean isSticky) throws Exception {
14572 
14573         when(mPermissionHelper.hasRequestedPermission(Manifest.permission.USE_FULL_SCREEN_INTENT,
14574                 mPkg, mUserId)).thenReturn(appRequested);
14575 
14576         when(mPermissionManager.checkPermissionForDataDelivery(
14577                 eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any()))
14578                 .thenReturn(permissionState);
14579 
14580         Notification n = new Notification.Builder(mContext, "test")
14581                 .setFullScreenIntent(mActivityIntent, true)
14582                 .build();
14583 
14584         mService.fixNotification(n, mPkg, "tag", 9, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
14585 
14586         final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
14587 
14588         if (isSticky) {
14589             assertNotSame(0, stickyFlag);
14590         } else {
14591             assertSame(0, stickyFlag);
14592         }
14593     }
14594 
14595     @Test
14596     public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun()
14597             throws Exception {
14598 
14599         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_HARD_DENIED, true,
14600                 /* isSticky= */ true);
14601     }
14602 
14603     @Test
14604     public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun()
14605             throws Exception {
14606 
14607         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, true,
14608                 /* isSticky= */ true);
14609     }
14610 
14611     @Test
14612     public void testFixNotification_fsiPermissionSoftDenied_appNotRequest_noShowStickyHun()
14613             throws Exception {
14614         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, false,
14615                 /* isSticky= */ false);
14616     }
14617 
14618 
14619     @Test
14620     public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi()
14621             throws Exception {
14622 
14623         verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_GRANTED, true,
14624                 /* isSticky= */ false);
14625     }
14626 
14627     @Test
14628     public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception {
14629         final ApplicationInfo applicationInfo = new ApplicationInfo();
14630         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14631                 .thenReturn(applicationInfo);
14632 
14633         Notification n = new Notification.Builder(mContext, "test")
14634                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
14635                 .setFlag(FLAG_CAN_COLORIZE, true)
14636                 .build();
14637 
14638         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14639 
14640         assertFalse(n.isForegroundService());
14641         assertFalse(n.hasColorizedPermission());
14642     }
14643 
14644     @Test
14645     public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception {
14646         Person person = new Person.Builder().setName("caller").build();
14647         Notification n = new Notification.Builder(mContext, "test")
14648                 .setStyle(Notification.CallStyle.forOngoingCall(
14649                         person, mActivityIntent))
14650                 .build();
14651         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14652                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14653         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14654 
14655         try {
14656             mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14657                     r.getSbn().getId(), r.getSbn().getTag(), r, false, false);
14658             assertFalse("CallStyle should not be allowed without a valid use case", true);
14659         } catch (IllegalArgumentException error) {
14660             assertThat(error.getMessage()).contains("CallStyle");
14661         }
14662     }
14663 
14664     @Test
14665     public void checkCallStyleNotification_allowedForFgs() throws Exception {
14666         Person person = new Person.Builder().setName("caller").build();
14667         Notification n = new Notification.Builder(mContext, "test")
14668                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
14669                 .setStyle(Notification.CallStyle.forOngoingCall(
14670                         person, mActivityIntent))
14671                 .build();
14672         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14673                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14674         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14675 
14676         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14677                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14678     }
14679 
14680     private Notification createBigPictureNotification(boolean isBigPictureStyle, boolean hasImage,
14681             boolean isImageBitmap) {
14682         Notification.Builder builder = new Notification.Builder(mContext)
14683                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
14684         Notification.BigPictureStyle style = new Notification.BigPictureStyle();
14685 
14686         if (isBigPictureStyle && hasImage) {
14687             if (isImageBitmap) {
14688                 style = style.bigPicture(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888));
14689             } else {
14690                 style = style.bigPicture(Icon.createWithResource(mContext, R.drawable.btn_plus));
14691             }
14692         }
14693         if (isBigPictureStyle) {
14694             builder.setStyle(style);
14695         }
14696 
14697         Notification notification = builder.setChannelId(TEST_CHANNEL_ID).build();
14698 
14699         return notification;
14700     }
14701 
14702     private NotificationRecord createBigPictureRecord(boolean isBigPictureStyle, boolean hasImage,
14703             boolean isImageBitmap, boolean isExpired) {
14704         long timePostedMs = System.currentTimeMillis();
14705         if (isExpired) {
14706             timePostedMs -= BITMAP_DURATION.toMillis();
14707         }
14708         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14709                 createBigPictureNotification(isBigPictureStyle, hasImage, isImageBitmap),
14710                 UserHandle.getUserHandleForUid(mUid), null, timePostedMs);
14711 
14712         return new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14713     }
14714 
14715     private void addRecordAndRemoveBitmaps(NotificationRecord record) {
14716         mService.addNotification(record);
14717         mInternalService.removeBitmaps();
14718         waitForIdle();
14719     }
14720 
14721     @Test
14722     public void testRemoveBitmaps_canRemoveRevokedDelegate() throws Exception {
14723         Notification n = createBigPictureNotification(true, true, true);
14724         long timePostedMs = System.currentTimeMillis();
14725         timePostedMs -= BITMAP_DURATION.toMillis();
14726 
14727         when(mPermissionHelper.hasPermission(UID_O)).thenReturn(true);
14728         when(mPackageManagerInternal.isSameApp(PKG_O, UID_O, UserHandle.getUserId(UID_O)))
14729                 .thenReturn(true);
14730         mService.mPreferencesHelper.createNotificationChannel(PKG_O, UID_O,
14731                 mTestNotificationChannel, true /* fromTargetApp */, false, UID_O,
14732                 false);
14733         mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
14734                 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel)));
14735 
14736         StatusBarNotification sbn = new StatusBarNotification(PKG_O, "old.delegate", 8, "tag",
14737                 UID_O, 0, n, UserHandle.getUserHandleForUid(UID_O), null, timePostedMs);
14738 
14739         mService.addNotification(new NotificationRecord(mContext, sbn, mTestNotificationChannel));
14740         mInternalService.removeBitmaps();
14741 
14742         waitForIdle();
14743 
14744         verify(mWorkerHandler, times(1))
14745                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14746     }
14747 
14748     @Test
14749     public void testRemoveBitmaps_notBigPicture_noRepost() {
14750         addRecordAndRemoveBitmaps(
14751                 createBigPictureRecord(
14752                         /* isBigPictureStyle= */ false,
14753                         /* hasImage= */ false,
14754                         /* isImageBitmap= */ false,
14755                         /* isExpired= */ false));
14756         verify(mWorkerHandler, never())
14757                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14758     }
14759 
14760     @Test
14761     public void testRemoveBitmaps_bigPictureNoImage_noRepost() {
14762         addRecordAndRemoveBitmaps(
14763                 createBigPictureRecord(
14764                         /* isBigPictureStyle= */ true,
14765                         /* hasImage= */ false,
14766                         /* isImageBitmap= */ false,
14767                         /* isExpired= */ false));
14768         verify(mWorkerHandler, never())
14769                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14770     }
14771 
14772     @Test
14773     public void testRemoveBitmaps_notExpired_noRepost() {
14774         addRecordAndRemoveBitmaps(
14775                 createBigPictureRecord(
14776                         /* isBigPictureStyle= */ true,
14777                         /* hasImage= */ true,
14778                         /* isImageBitmap= */ true,
14779                         /* isExpired= */ false));
14780         verify(mWorkerHandler, never())
14781                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14782     }
14783 
14784     @Test
14785     public void testRemoveBitmaps_bitmapExpired_repost() {
14786         addRecordAndRemoveBitmaps(
14787                 createBigPictureRecord(
14788                         /* isBigPictureStyle= */ true,
14789                         /* hasImage= */ true,
14790                         /* isImageBitmap= */ true,
14791                         /* isExpired= */ true));
14792         verify(mWorkerHandler, times(1))
14793                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14794     }
14795 
14796     @Test
14797     public void testRemoveBitmaps_bitmapExpired_bitmapGone() {
14798         NotificationRecord record = createBigPictureRecord(
14799                 /* isBigPictureStyle= */ true,
14800                 /* hasImage= */ true,
14801                 /* isImageBitmap= */ true,
14802                 /* isExpired= */ true);
14803         addRecordAndRemoveBitmaps(record);
14804         assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE)).isTrue();
14805         final Parcelable picture = record.getNotification().extras.getParcelable(EXTRA_PICTURE);
14806         assertThat(picture).isNull();
14807     }
14808 
14809     @Test
14810     public void testRemoveBitmaps_bitmapExpired_silent() {
14811         NotificationRecord record = createBigPictureRecord(
14812                 /* isBigPictureStyle= */ true,
14813                 /* hasImage= */ true,
14814                 /* isImageBitmap= */ true,
14815                 /* isExpired= */ true);
14816         addRecordAndRemoveBitmaps(record);
14817         assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
14818     }
14819 
14820     @Test
14821     public void testRemoveBitmaps_iconExpired_repost() {
14822         addRecordAndRemoveBitmaps(
14823                 createBigPictureRecord(
14824                         /* isBigPictureStyle= */ true,
14825                         /* hasImage= */ true,
14826                         /* isImageBitmap= */ false,
14827                         /* isExpired= */ true));
14828         verify(mWorkerHandler, times(1))
14829                 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class));
14830     }
14831 
14832     @Test
14833     public void testRemoveBitmaps_iconExpired_iconGone() {
14834         NotificationRecord record = createBigPictureRecord(
14835                 /* isBigPictureStyle= */ true,
14836                 /* hasImage= */ true,
14837                 /* isImageBitmap= */ false,
14838                 /* isExpired= */ true);
14839         addRecordAndRemoveBitmaps(record);
14840         assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE_ICON)).isTrue();
14841         final Parcelable pictureIcon =
14842                 record.getNotification().extras.getParcelable(EXTRA_PICTURE_ICON);
14843         assertThat(pictureIcon).isNull();
14844     }
14845 
14846     @Test
14847     public void testRemoveBitmaps_iconExpired_silent() {
14848         NotificationRecord record = createBigPictureRecord(
14849                 /* isBigPictureStyle= */ true,
14850                 /* hasImage= */ true,
14851                 /* isImageBitmap= */ false,
14852                 /* isExpired= */ true);
14853         addRecordAndRemoveBitmaps(record);
14854         assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
14855     }
14856 
14857     @Test
14858     public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
14859         Person person = new Person.Builder().setName("caller").build();
14860         Notification n = new Notification.Builder(mContext, "test")
14861                 // Without FLAG_FOREGROUND_SERVICE.
14862                 //.setFlag(FLAG_FOREGROUND_SERVICE, true)
14863                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14864                 .build();
14865         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14866                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14867         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14868 
14869         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14870                 r.getSbn().getId(), r.getSbn().getTag(), r, false,
14871                 true /* byForegroundService */)).isTrue();
14872     }
14873 
14874     @Test
14875     public void checkCallStyleNotification_allowedForUij() throws Exception {
14876         Person person = new Person.Builder().setName("caller").build();
14877         Notification n = new Notification.Builder(mContext, "test")
14878                 .setFlag(FLAG_USER_INITIATED_JOB, true)
14879                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14880                 .build();
14881         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14882                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14883         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14884 
14885         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14886                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14887     }
14888 
14889     @Test
14890     public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception {
14891         Person person = new Person.Builder().setName("caller").build();
14892         Notification n = new Notification.Builder(mContext, "test")
14893                 .setFullScreenIntent(mActivityIntent, true)
14894                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14895                 .build();
14896         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14897                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14898         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14899 
14900         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14901                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14902     }
14903 
14904     @Test
14905     public void checkCallStyleNotification_allowedForFsiDenied() throws Exception {
14906         Person person = new Person.Builder().setName("caller").build();
14907         Notification n = new Notification.Builder(mContext, "test")
14908                 .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true)
14909                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
14910                 .build();
14911         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0,
14912                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
14913         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
14914 
14915         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
14916                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
14917     }
14918 
14919     @Test
14920     public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible()
14921             throws Exception {
14922         final ApplicationInfo ai = new ApplicationInfo();
14923         ai.packageName = "pkg";
14924         ai.uid = mUid;
14925         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
14926 
14927         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14928                 .thenReturn(ai);
14929         when(mAppOpsManager.checkOpNoThrow(
14930                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
14931                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
14932         // Given: a notification from an app on the system partition has the flag
14933         // FLAG_ONGOING_EVENT set
14934         Notification n = new Notification.Builder(mContext, "test")
14935                 .setOngoing(true)
14936                 .build();
14937 
14938         // When: fix the notification with NotificationManagerService
14939         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14940 
14941         // Then: the notification's flag FLAG_NO_DISMISS should not be set
14942         assertSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14943     }
14944 
14945     @Test
14946     public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible()
14947             throws Exception {
14948         // Given: a media notification has the flag FLAG_ONGOING_EVENT set
14949         Notification n = new Notification.Builder(mContext, "test")
14950                 .setOngoing(true)
14951                 .setStyle(new Notification.MediaStyle()
14952                         .setMediaSession(mock(MediaSession.Token.class)))
14953                 .build();
14954 
14955         // When: fix the notification with NotificationManagerService
14956         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14957 
14958         // Then: the notification's flag FLAG_NO_DISMISS should be set
14959         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14960     }
14961 
14962     @Test
14963     public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible()
14964             throws Exception {
14965         final ApplicationInfo ai = new ApplicationInfo();
14966         ai.packageName = SEARCH_SELECTOR_PKG;
14967         ai.uid = mUid;
14968         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
14969 
14970         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14971                 .thenReturn(ai);
14972         when(mAppOpsManager.checkOpNoThrow(
14973                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
14974                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
14975         // Given: a notification from an app on the system partition has the flag
14976         // FLAG_ONGOING_EVENT set
14977         Notification n = new Notification.Builder(mContext, "test")
14978                 .setOngoing(true)
14979                 .build();
14980 
14981         // When: fix the notification with NotificationManagerService
14982         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
14983 
14984         // Then: the notification's flag FLAG_NO_DISMISS should be set
14985         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
14986     }
14987 
14988     @Test
14989     public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible()
14990             throws Exception {
14991         final ApplicationInfo ai = new ApplicationInfo();
14992         ai.packageName = ADSERVICES_APK_PKG;
14993         ai.uid = mUid;
14994         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
14995 
14996         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
14997                 .thenReturn(ai);
14998         when(mAppOpsManager.checkOpNoThrow(
14999                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
15000                 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
15001         // Given: a notification from an app on the system partition has the flag
15002         // FLAG_ONGOING_EVENT set
15003         Notification n = new Notification.Builder(mContext, "test")
15004                 .setOngoing(true)
15005                 .build();
15006 
15007         // When: fix the notification with NotificationManagerService
15008         mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE,
15009                  true);
15010 
15011         // Then: the notification's flag FLAG_NO_DISMISS should be set
15012         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15013     }
15014 
15015     @Test
15016     public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible()
15017             throws Exception {
15018         // Given: a call notification has the flag FLAG_ONGOING_EVENT set
15019         Person person = new Person.Builder()
15020                 .setName("caller")
15021                 .build();
15022         Notification n = new Notification.Builder(mContext, "test")
15023                 .setOngoing(true)
15024                 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
15025                 .build();
15026 
15027         // When: fix the notification with NotificationManagerService
15028         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15029 
15030         // Then: the notification's flag FLAG_NO_DISMISS should be set
15031         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15032     }
15033 
15034 
15035     @Test
15036     public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception {
15037         // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
15038         Notification n = new Notification.Builder(mContext, "test")
15039                 .setOngoing(true)
15040                 .build();
15041 
15042         // When: fix the notification with NotificationManagerService
15043         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15044 
15045         // Then: the notification's flag FLAG_NO_DISMISS should not be set
15046         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
15047     }
15048 
15049     @Test
15050     public void fixNonExemptNotification_withNoDismissFlag_shouldBeDismissible()
15051             throws Exception {
15052         // Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is
15053         // not allowed)
15054         Notification n = new Notification.Builder(mContext, "test")
15055                 .build();
15056         n.flags |= Notification.FLAG_NO_DISMISS;
15057 
15058         // When: fix the notification with NotificationManagerService
15059         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15060 
15061         // Then: the notification's flag FLAG_NO_DISMISS should be cleared
15062         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
15063     }
15064 
15065     @Test
15066     public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception {
15067         // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set
15068         Notification n = new Notification.Builder(mContext, "test")
15069                 .setOngoing(false)
15070                 .setStyle(new Notification.MediaStyle()
15071                         .setMediaSession(mock(MediaSession.Token.class)))
15072                 .build();
15073 
15074         // When: fix the notification with NotificationManagerService
15075         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15076 
15077         // Then: the notification's flag FLAG_NO_DISMISS should not be set
15078         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
15079     }
15080 
15081     @Test
15082     public void fixMediaNotification_withoutOnGoingFlag_withNoDismissFlag_shouldBeDismissible()
15083             throws Exception {
15084         // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set,
15085         // but has the flag FLAG_NO_DISMISS set
15086         Notification n = new Notification.Builder(mContext, "test")
15087                 .setOngoing(false)
15088                 .setStyle(new Notification.MediaStyle()
15089                         .setMediaSession(mock(MediaSession.Token.class)))
15090                 .build();
15091         n.flags |= Notification.FLAG_NO_DISMISS;
15092 
15093         // When: fix the notification with NotificationManagerService
15094         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15095 
15096         // Then: the notification's flag FLAG_NO_DISMISS should be cleared
15097         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
15098     }
15099 
15100     @Test
15101     public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible()
15102             throws Exception {
15103         // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
15104         Notification n = new Notification.Builder(mContext, "test")
15105                 .setOngoing(false)
15106                 .build();
15107 
15108         // When: fix the notification with NotificationManagerService
15109         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15110 
15111         // Then: the notification's flag FLAG_NO_DISMISS should not be set
15112         assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
15113     }
15114 
15115     @Test
15116     public void fixOrganizationAdminNotification_withOnGoingFlag_shouldBeNonDismissible()
15117             throws Exception {
15118         when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true);
15119         // Given: a notification has the flag FLAG_ONGOING_EVENT set
15120         Notification n = new Notification.Builder(mContext, "test")
15121                 .setOngoing(true)
15122                 .build();
15123 
15124         // When: fix the notification with NotificationManagerService
15125         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15126 
15127         // Then: the notification's flag FLAG_NO_DISMISS should be set
15128         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15129     }
15130 
15131     @Test
15132     public void fixExemptAppOpNotification_withFlag_shouldBeNonDismissible()
15133             throws Exception {
15134         final ApplicationInfo ai = new ApplicationInfo();
15135         ai.packageName = mPkg;
15136         ai.uid = mUid;
15137         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
15138 
15139         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
15140                 .thenReturn(ai);
15141         when(mAppOpsManager.checkOpNoThrow(
15142                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
15143                 mPkg)).thenReturn(AppOpsManager.MODE_ALLOWED);
15144         // Given: a notification has the flag FLAG_ONGOING_EVENT set
15145         Notification n = new Notification.Builder(mContext, "test")
15146                 .setOngoing(true)
15147                 .build();
15148 
15149         // When: fix the notification with NotificationManagerService
15150         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15151 
15152         // Then: the notification's flag FLAG_NO_DISMISS should be set
15153         assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15154     }
15155 
15156     @Test
15157     public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible()
15158             throws Exception {
15159         when(mAppOpsManager.checkOpNoThrow(
15160                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
15161                 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED);
15162         // Given: a notification has the flag FLAG_ONGOING_EVENT set
15163         Notification n = new Notification.Builder(mContext, "test")
15164                 .setOngoing(true)
15165                 .build();
15166 
15167         // When: fix the notification with NotificationManagerService
15168         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15169 
15170         // Then: the notification's flag FLAG_NO_DISMISS should not be set
15171         assertSame(0, n.flags & Notification.FLAG_NO_DISMISS);
15172     }
15173 
15174     @Test
15175     public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception {
15176         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15177                 .thenReturn(true);
15178         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15179         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15180         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15181                 "testCancelAllNotifications_IgnoreUserInitiatedJob",
15182                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15183         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
15184         waitForIdle();
15185         StatusBarNotification[] notifs =
15186                 mBinderService.getActiveNotifications(sbn.getPackageName());
15187         assertEquals(1, notifs.length);
15188         assertEquals(1, mService.getNotificationRecordCount());
15189     }
15190 
15191     @Test
15192     public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception {
15193         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15194                 .thenReturn(false);
15195         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15196         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15197         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15198                 "testCancelAllNotifications_UijFlag_NoUij_Allowed",
15199                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15200         mBinderService.cancelAllNotifications(mPkg, sbn.getUserId());
15201         waitForIdle();
15202         StatusBarNotification[] notifs =
15203                 mBinderService.getActiveNotifications(sbn.getPackageName());
15204         assertEquals(0, notifs.length);
15205     }
15206 
15207     @Test
15208     public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception {
15209         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15210                 .thenReturn(true);
15211         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15212         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15213         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15214                 "testCancelAllNotifications_IgnoreOtherPackages",
15215                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15216         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
15217         waitForIdle();
15218         StatusBarNotification[] notifs =
15219                 mBinderService.getActiveNotifications(sbn.getPackageName());
15220         assertEquals(1, notifs.length);
15221         assertEquals(1, mService.getNotificationRecordCount());
15222     }
15223 
15224     @Test
15225     public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception {
15226         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15227                 .thenReturn(true);
15228         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
15229                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
15230                 .build();
15231         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
15232                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15233         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15234         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null,
15235                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15236         mInternalService.removeUserInitiatedJobFlagFromNotification(mPkg, sbn.getId(),
15237                 sbn.getUserId());
15238         waitForIdle();
15239         StatusBarNotification[] notifs =
15240                 mBinderService.getActiveNotifications(sbn.getPackageName());
15241         assertFalse(notifs[0].getNotification().isUserInitiatedJob());
15242     }
15243 
15244     @Test
15245     public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception {
15246         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15247         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB;
15248         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
15249                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15250         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
15251         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
15252                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15253         mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(),
15254                 sbn.getUserId());
15255         waitForIdle();
15256         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
15257         assertEquals(0, mService.getNotificationRecordCount());
15258     }
15259 
15260     @Test
15261     public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception {
15262         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15263                 .thenReturn(true);
15264         mService.isSystemUid = false;
15265         mService.isSystemAppId = false;
15266         final NotificationRecord parent = generateNotificationRecord(
15267                 mTestNotificationChannel, 1, "group", true);
15268         final NotificationRecord child = generateNotificationRecord(
15269                 mTestNotificationChannel, 2, "group", false);
15270         final NotificationRecord child2 = generateNotificationRecord(
15271                 mTestNotificationChannel, 3, "group", false);
15272         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15273         mService.addNotification(parent);
15274         mService.addNotification(child);
15275         mService.addNotification(child2);
15276         mService.getBinderService().cancelNotificationWithTag(
15277                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
15278                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
15279         waitForIdle();
15280         StatusBarNotification[] notifs =
15281                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15282         assertEquals(1, notifs.length);
15283     }
15284 
15285     @Test
15286     public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception {
15287         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15288                 .thenReturn(true);
15289         mService.isSystemUid = false;
15290         mService.isSystemAppId = false;
15291         final NotificationRecord parent = generateNotificationRecord(
15292                 mTestNotificationChannel, 1, "group", true);
15293         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15294         final NotificationRecord child = generateNotificationRecord(
15295                 mTestNotificationChannel, 2, "group", false);
15296         final NotificationRecord child2 = generateNotificationRecord(
15297                 mTestNotificationChannel, 3, "group", false);
15298         mService.addNotification(parent);
15299         mService.addNotification(child);
15300         mService.addNotification(child2);
15301         mService.getBinderService().cancelNotificationWithTag(
15302                 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(),
15303                 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId());
15304         waitForIdle();
15305         StatusBarNotification[] notifs =
15306                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15307         assertEquals(3, notifs.length);
15308     }
15309 
15310     @Test
15311     public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception {
15312         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15313                 .thenReturn(true);
15314         mService.isSystemUid = false;
15315         mService.isSystemAppId = false;
15316         final NotificationRecord parent = generateNotificationRecord(
15317                 mTestNotificationChannel, 1, "group", true);
15318         final NotificationRecord child = generateNotificationRecord(
15319                 mTestNotificationChannel, 2, "group", false);
15320         final NotificationRecord child2 = generateNotificationRecord(
15321                 mTestNotificationChannel, 3, "group", false);
15322         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15323         final NotificationRecord newGroup = generateNotificationRecord(
15324                 mTestNotificationChannel, 4, "group2", false);
15325         mService.addNotification(parent);
15326         mService.addNotification(child);
15327         mService.addNotification(child2);
15328         mService.addNotification(newGroup);
15329         mService.getBinderService().cancelAllNotifications(
15330                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
15331         waitForIdle();
15332         StatusBarNotification[] notifs =
15333                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15334         assertEquals(1, notifs.length);
15335     }
15336 
15337     @Test
15338     public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception {
15339         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15340                 .thenReturn(true);
15341         mService.isSystemUid = false;
15342         mService.isSystemAppId = false;
15343         final NotificationRecord parent = generateNotificationRecord(
15344                 mTestNotificationChannel, 1, "group", true);
15345         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15346         final NotificationRecord child = generateNotificationRecord(
15347                 mTestNotificationChannel, 2, "group", false);
15348         final NotificationRecord child2 = generateNotificationRecord(
15349                 mTestNotificationChannel, 3, "group", false);
15350         final NotificationRecord newGroup = generateNotificationRecord(
15351                 mTestNotificationChannel, 4, "group2", false);
15352         mService.addNotification(parent);
15353         mService.addNotification(child);
15354         mService.addNotification(child2);
15355         mService.addNotification(newGroup);
15356         mService.getBinderService().cancelAllNotifications(
15357                 parent.getSbn().getPackageName(), parent.getSbn().getUserId());
15358         waitForIdle();
15359         StatusBarNotification[] notifs =
15360                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15361         assertEquals(1, notifs.length);
15362     }
15363 
15364     @Test
15365     public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception {
15366         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15367                 .thenReturn(true);
15368         final NotificationRecord parent = generateNotificationRecord(
15369                 mTestNotificationChannel, 1, "group", true);
15370         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15371         final NotificationRecord child = generateNotificationRecord(
15372                 mTestNotificationChannel, 2, "group", false);
15373         final NotificationRecord child2 = generateNotificationRecord(
15374                 mTestNotificationChannel, 3, "group", false);
15375         final NotificationRecord newGroup = generateNotificationRecord(
15376                 mTestNotificationChannel, 4, "group2", false);
15377         mService.addNotification(parent);
15378         mService.addNotification(child);
15379         mService.addNotification(child2);
15380         mService.addNotification(newGroup);
15381         mService.getBinderService().cancelNotificationsFromListener(null, null);
15382         waitForIdle();
15383         StatusBarNotification[] notifs =
15384                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15385         assertEquals(0, notifs.length);
15386     }
15387 
15388     @Test
15389     public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception {
15390         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15391                 .thenReturn(true);
15392         final NotificationRecord parent = generateNotificationRecord(
15393                 mTestNotificationChannel, 1, "group", true);
15394         final NotificationRecord child = generateNotificationRecord(
15395                 mTestNotificationChannel, 2, "group", false);
15396         final NotificationRecord child2 = generateNotificationRecord(
15397                 mTestNotificationChannel, 3, "group", false);
15398         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15399         final NotificationRecord newGroup = generateNotificationRecord(
15400                 mTestNotificationChannel, 4, "group2", false);
15401         mService.addNotification(parent);
15402         mService.addNotification(child);
15403         mService.addNotification(child2);
15404         mService.addNotification(newGroup);
15405         mService.getBinderService().cancelNotificationsFromListener(null, null);
15406         waitForIdle();
15407         StatusBarNotification[] notifs =
15408                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15409         assertEquals(0, notifs.length);
15410     }
15411 
15412     @Test
15413     public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception {
15414         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15415                 .thenReturn(true);
15416         final NotificationRecord child2 = generateNotificationRecord(
15417                 mTestNotificationChannel, 3, null, false);
15418         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15419         mService.addNotification(child2);
15420         mService.getBinderService().cancelNotificationsFromListener(null, null);
15421         waitForIdle();
15422         StatusBarNotification[] notifs =
15423                 mBinderService.getActiveNotifications(child2.getSbn().getPackageName());
15424         assertEquals(0, notifs.length);
15425     }
15426 
15427     @Test
15428     public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception {
15429         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15430                 .thenReturn(true);
15431         final NotificationRecord parent = generateNotificationRecord(
15432                 mTestNotificationChannel, 1, "group", true);
15433         parent.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15434         final NotificationRecord child = generateNotificationRecord(
15435                 mTestNotificationChannel, 2, "group", false);
15436         final NotificationRecord child2 = generateNotificationRecord(
15437                 mTestNotificationChannel, 3, "group", false);
15438         final NotificationRecord newGroup = generateNotificationRecord(
15439                 mTestNotificationChannel, 4, "group2", false);
15440         mService.addNotification(parent);
15441         mService.addNotification(child);
15442         mService.addNotification(child2);
15443         mService.addNotification(newGroup);
15444         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
15445                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
15446         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15447         waitForIdle();
15448         StatusBarNotification[] notifs =
15449                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15450         assertEquals(0, notifs.length);
15451     }
15452 
15453     @Test
15454     public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception {
15455         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15456                 .thenReturn(true);
15457         final NotificationRecord parent = generateNotificationRecord(
15458                 mTestNotificationChannel, 1, "group", true);
15459         final NotificationRecord child = generateNotificationRecord(
15460                 mTestNotificationChannel, 2, "group", false);
15461         final NotificationRecord child2 = generateNotificationRecord(
15462                 mTestNotificationChannel, 3, "group", false);
15463         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15464         final NotificationRecord newGroup = generateNotificationRecord(
15465                 mTestNotificationChannel, 4, "group2", false);
15466         mService.addNotification(parent);
15467         mService.addNotification(child);
15468         mService.addNotification(child2);
15469         mService.addNotification(newGroup);
15470         String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(),
15471                 child2.getSbn().getKey(), newGroup.getSbn().getKey()};
15472         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15473         waitForIdle();
15474         StatusBarNotification[] notifs =
15475                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15476         assertEquals(0, notifs.length);
15477     }
15478 
15479     @Test
15480     public void testCancelNotificationsFromListener_byKey_Uij() throws Exception {
15481         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15482                 .thenReturn(true);
15483         final NotificationRecord child = generateNotificationRecord(
15484                 mTestNotificationChannel, 3, null, false);
15485         child.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15486         mService.addNotification(child);
15487         String[] keys = {child.getSbn().getKey()};
15488         mService.getBinderService().cancelNotificationsFromListener(null, keys);
15489         waitForIdle();
15490         StatusBarNotification[] notifs =
15491                 mBinderService.getActiveNotifications(child.getSbn().getPackageName());
15492         assertEquals(0, notifs.length);
15493     }
15494 
15495     @Test
15496     public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception {
15497         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15498                 .thenReturn(true);
15499         final NotificationRecord parent = generateNotificationRecord(
15500                 mTestNotificationChannel, 1, "group", true);
15501         final NotificationRecord child = generateNotificationRecord(
15502                 mTestNotificationChannel, 2, "group", false);
15503         final NotificationRecord child2 = generateNotificationRecord(
15504                 mTestNotificationChannel, 3, "group", false);
15505         child2.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15506         final NotificationRecord newGroup = generateNotificationRecord(
15507                 mTestNotificationChannel, 4, "group2", false);
15508         mService.addNotification(parent);
15509         mService.addNotification(child);
15510         mService.addNotification(child2);
15511         mService.addNotification(newGroup);
15512         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId());
15513         waitForIdle();
15514         StatusBarNotification[] notifs =
15515                 mBinderService.getActiveNotifications(parent.getSbn().getPackageName());
15516         assertEquals(0, notifs.length);
15517     }
15518 
15519     @Test
15520     public void testDeleteChannelGroupChecksForUijs() throws Exception {
15521         when(mCompanionMgr.getAssociations(mPkg, UserHandle.getUserId(mUid)))
15522                 .thenReturn(singletonList(mock(AssociationInfo.class)));
15523         CountDownLatch latch = new CountDownLatch(2);
15524         mService.createNotificationChannelGroup(mPkg, mUid,
15525                 new NotificationChannelGroup("group", "group"), true, false);
15526         new Thread(() -> {
15527             NotificationChannel notificationChannel = new NotificationChannel("id", "id",
15528                     NotificationManager.IMPORTANCE_HIGH);
15529             notificationChannel.setGroup("group");
15530             ParceledListSlice<NotificationChannel> pls =
15531                     new ParceledListSlice(ImmutableList.of(notificationChannel));
15532             try {
15533                 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
15534             } catch (RemoteException e) {
15535                 throw new RuntimeException(e);
15536             }
15537             latch.countDown();
15538         }).start();
15539         new Thread(() -> {
15540             try {
15541                 synchronized (this) {
15542                     wait(5000);
15543                 }
15544                 mService.createNotificationChannelGroup(mPkg, mUid,
15545                         new NotificationChannelGroup("new", "new group"), true, false);
15546                 NotificationChannel notificationChannel =
15547                         new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
15548                 notificationChannel.setGroup("new");
15549                 ParceledListSlice<NotificationChannel> pls =
15550                         new ParceledListSlice(ImmutableList.of(notificationChannel));
15551                 try {
15552                     mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls);
15553                     mBinderService.deleteNotificationChannelGroup(mPkg, "group");
15554                 } catch (RemoteException e) {
15555                     throw new RuntimeException(e);
15556                 }
15557             } catch (Exception e) {
15558                 e.printStackTrace();
15559             }
15560             latch.countDown();
15561         }).start();
15562 
15563         latch.await();
15564         verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs(
15565                 anyString(), anyInt(), anyString());
15566     }
15567 
15568     @Test
15569     public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() {
15570         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15571                 .thenReturn(true);
15572         Notification n = new Notification.Builder(mContext, "").build();
15573         n.flags |= FLAG_USER_INITIATED_JOB;
15574 
15575         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
15576                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15577         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15578 
15579         mService.addEnqueuedNotification(r);
15580 
15581         mInternalService.removeUserInitiatedJobFlagFromNotification(
15582                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15583 
15584         waitForIdle();
15585 
15586         verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
15587     }
15588 
15589     @Test
15590     public void testRemoveUserInitiatedJobFlagFromNotification_posted() {
15591         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15592                 .thenReturn(true);
15593         Notification n = new Notification.Builder(mContext, "").build();
15594         n.flags |= FLAG_USER_INITIATED_JOB;
15595 
15596         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
15597                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15598         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15599 
15600         mService.addNotification(r);
15601 
15602         mInternalService.removeUserInitiatedJobFlagFromNotification(
15603                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15604 
15605         waitForIdle();
15606 
15607         ArgumentCaptor<NotificationRecord> captor =
15608                 ArgumentCaptor.forClass(NotificationRecord.class);
15609         verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
15610 
15611         assertEquals(0, captor.getValue().getNotification().flags);
15612     }
15613 
15614     @Test
15615     public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() {
15616         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15617             Notification n = new Notification.Builder(mContext, "").build();
15618             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
15619                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
15620             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15621             mService.addEnqueuedNotification(r);
15622         }
15623         Notification n = new Notification.Builder(mContext, "").build();
15624         n.flags |= FLAG_USER_INITIATED_JOB;
15625 
15626         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
15627                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
15628                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15629         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15630 
15631         mService.addEnqueuedNotification(r);
15632 
15633         mInternalService.removeUserInitiatedJobFlagFromNotification(
15634                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15635 
15636         waitForIdle();
15637 
15638         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
15639                 mService.getNotificationRecordCount());
15640     }
15641 
15642     @Test
15643     public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() {
15644         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15645                 .thenReturn(true);
15646         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15647             Notification n = new Notification.Builder(mContext, "").build();
15648             StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0,
15649                     n, UserHandle.getUserHandleForUid(mUid), null, 0);
15650             NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15651             mService.addNotification(r);
15652         }
15653         Notification n = new Notification.Builder(mContext, "").build();
15654         n.flags |= FLAG_USER_INITIATED_JOB;
15655 
15656         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg,
15657                 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
15658                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
15659         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
15660 
15661         mService.addNotification(r);
15662 
15663         mInternalService.removeUserInitiatedJobFlagFromNotification(
15664                 mPkg, r.getSbn().getId(), r.getSbn().getUserId());
15665 
15666         waitForIdle();
15667 
15668         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
15669                 mService.getNotificationRecordCount());
15670     }
15671 
15672     @Test
15673     public void testCanPostUijWhenOverLimit() throws RemoteException {
15674         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15675                 .thenReturn(true);
15676         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15677             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
15678                     i, null, false).getSbn();
15679             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCanPostUijWhenOverLimit",
15680                     sbn.getId(), sbn.getNotification(), sbn.getUserId());
15681         }
15682 
15683         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
15684         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15685         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15686                 "testCanPostUijWhenOverLimit - uij over limit!",
15687                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15688 
15689         waitForIdle();
15690 
15691         StatusBarNotification[] notifs =
15692                 mBinderService.getActiveNotifications(sbn.getPackageName());
15693         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
15694         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
15695                 mService.getNotificationRecordCount());
15696     }
15697 
15698     @Test
15699     public void testCannotPostNonUijWhenOverLimit() throws RemoteException {
15700         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15701                 .thenReturn(true);
15702         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
15703             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
15704                     i, null, false).getSbn();
15705             mBinderService.enqueueNotificationWithTag(
15706                     mPkg,
15707                     mPkg,
15708                     "testCannotPostNonUijWhenOverLimit",
15709                     sbn.getId(),
15710                     sbn.getNotification(),
15711                     sbn.getUserId());
15712             waitForIdle();
15713         }
15714 
15715         final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
15716                 100, null, false).getSbn();
15717         sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15718         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15719                 "testCannotPostNonUijWhenOverLimit - uij over limit!",
15720                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
15721 
15722         final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
15723                 101, null, false).getSbn();
15724         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15725                 "testCannotPostNonUijWhenOverLimit - non uij over limit!",
15726                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
15727 
15728         when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString()))
15729                 .thenReturn(false);
15730         final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
15731                 101, null, false).getSbn();
15732         sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB;
15733         mBinderService.enqueueNotificationWithTag(mPkg, mPkg,
15734                 "testCannotPostNonUijWhenOverLimit - fake uij over limit!",
15735                 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
15736 
15737         waitForIdle();
15738 
15739         StatusBarNotification[] notifs =
15740                 mBinderService.getActiveNotifications(sbn.getPackageName());
15741         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
15742         assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
15743                 mService.getNotificationRecordCount());
15744     }
15745 
15746     @Test
15747     public void fixNotification_withUijFlag_butIsNotUij() throws Exception {
15748         final ApplicationInfo applicationInfo = new ApplicationInfo();
15749         when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
15750                 .thenReturn(applicationInfo);
15751 
15752         Notification n = new Notification.Builder(mContext, "test")
15753                 .setFlag(FLAG_USER_INITIATED_JOB, true)
15754                 .build();
15755 
15756         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
15757         assertFalse(n.isUserInitiatedJob());
15758     }
15759 
15760     @Test
15761     public void enqueue_updatesEnqueueRate() throws Exception {
15762         Notification n = generateNotificationRecord(null).getNotification();
15763 
15764         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
15765         // Don't waitForIdle() here. We want to verify the "intermediate" state.
15766 
15767         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15768         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15769         verify(mUsageStats, never()).registerPostedByApp(any());
15770 
15771         waitForIdle();
15772     }
15773 
15774     @Test
15775     public void enqueue_withPost_updatesEnqueueRateAndPost() throws Exception {
15776         Notification n = generateNotificationRecord(null).getNotification();
15777 
15778         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
15779         waitForIdle();
15780 
15781         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15782         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15783         verify(mUsageStats).registerPostedByApp(any());
15784     }
15785 
15786     @Test
15787     public void enqueueNew_whenOverEnqueueRate_accepts() throws Exception {
15788         Notification n = generateNotificationRecord(null).getNotification();
15789         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
15790                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f);
15791 
15792         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId);
15793         waitForIdle();
15794 
15795         assertThat(mService.mNotificationsByKey).hasSize(1);
15796         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15797         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15798         verify(mUsageStats).registerPostedByApp(any());
15799     }
15800 
15801     @Test
15802     public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception {
15803         // Post the first version.
15804         Notification original = generateNotificationRecord(null).getNotification();
15805         original.when = System.currentTimeMillis();
15806         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
15807         waitForIdle();
15808         assertThat(mService.mNotificationList).hasSize(1);
15809         assertThat(mService.mNotificationList.get(0).getNotification().when)
15810                 .isEqualTo(original.when);
15811 
15812         reset(mUsageStats);
15813         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
15814                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE - 1f);
15815 
15816         // Post the update.
15817         Notification update = generateNotificationRecord(null).getNotification();
15818         update.when = System.currentTimeMillis() + 111;
15819         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
15820         waitForIdle();
15821 
15822         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15823         verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg));
15824         verify(mUsageStats, never()).registerPostedByApp(any());
15825         verify(mUsageStats).registerUpdatedByApp(any(), any());
15826         assertThat(mService.mNotificationList).hasSize(1);
15827         assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when);
15828     }
15829 
15830     @Test
15831     public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception {
15832         // Post the first version.
15833         Notification original = generateNotificationRecord(null).getNotification();
15834         original.when = System.currentTimeMillis();
15835         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
15836         waitForIdle();
15837         assertThat(mService.mNotificationList).hasSize(1);
15838         assertThat(mService.mNotificationList.get(0).getNotification().when)
15839                 .isEqualTo(original.when);
15840 
15841         reset(mUsageStats);
15842         when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
15843                 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f);
15844 
15845         // Post the update.
15846         Notification update = generateNotificationRecord(null).getNotification();
15847         update.when = System.currentTimeMillis() + 111;
15848         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
15849         waitForIdle();
15850 
15851         verify(mUsageStats).registerEnqueuedByApp(eq(mPkg));
15852         verify(mUsageStats, never()).registerEnqueuedByAppAndAccepted(any());
15853         verify(mUsageStats, never()).registerPostedByApp(any());
15854         verify(mUsageStats, never()).registerUpdatedByApp(any(), any());
15855         assertThat(mService.mNotificationList).hasSize(1);
15856         assertThat(mService.mNotificationList.get(0).getNotification().when)
15857                 .isEqualTo(original.when); // old
15858     }
15859 
15860     @Test
15861     public void enqueueNotification_acceptsCorrectToken() throws RemoteException {
15862         Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15863                 .setContentIntent(createPendingIntent("content"))
15864                 .build();
15865         Notification received = parcelAndUnparcel(sent, Notification.CREATOR);
15866         assertThat(received.getAllowlistToken()).isEqualTo(
15867                 NotificationManagerService.ALLOWLIST_TOKEN);
15868 
15869         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
15870                 parcelAndUnparcel(received, Notification.CREATOR), mUserId);
15871         waitForIdle();
15872 
15873         assertThat(mService.mNotificationList).hasSize(1);
15874         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
15875                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
15876     }
15877 
15878     @Test
15879     public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException {
15880         Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15881                 .setContentIntent(createPendingIntent("content"))
15882                 .build();
15883         assertThat(receivedWithoutParceling.getAllowlistToken()).isNull();
15884 
15885         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
15886                 parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId);
15887         waitForIdle();
15888 
15889         assertThat(mService.mNotificationList).hasSize(1);
15890         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
15891                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
15892     }
15893 
15894     @Test
15895     public void enqueueNotification_directlyThroughRunnable_populatesAllowlistToken() {
15896         Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15897                 .setContentIntent(createPendingIntent("content"))
15898                 .build();
15899         NotificationRecord record = new NotificationRecord(
15900                 mContext,
15901                 new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 44, receivedWithoutParceling,
15902                         mUser, "groupKey", 0),
15903                 mTestNotificationChannel);
15904         assertThat(record.getNotification().getAllowlistToken()).isNull();
15905 
15906         mWorkerHandler.post(
15907                 mService.new EnqueueNotificationRunnable(mUserId, record, false, false,
15908                 mPostNotificationTrackerFactory.newTracker(null)));
15909         waitForIdle();
15910 
15911         assertThat(mService.mNotificationList).hasSize(1);
15912         assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken())
15913                 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN);
15914     }
15915 
15916     @Test
15917     public void enqueueNotification_rejectsOtherToken() throws RemoteException {
15918         Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15919                 .setContentIntent(createPendingIntent("content"))
15920                 .build();
15921         sent.overrideAllowlistToken(new Binder());
15922         Notification received = parcelAndUnparcel(sent, Notification.CREATOR);
15923         assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken());
15924 
15925         assertThrows(SecurityException.class, () ->
15926                 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
15927                         parcelAndUnparcel(received, Notification.CREATOR), mUserId));
15928         waitForIdle();
15929 
15930         assertThat(mService.mNotificationList).isEmpty();
15931     }
15932 
15933     @Test
15934     public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents()
15935             throws RemoteException {
15936         Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID)
15937                 .setContentIntent(createPendingIntent("content"))
15938                 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID)
15939                         .setContentIntent(createPendingIntent("public"))
15940                         .build())
15941                 .build();
15942         sentFromApp.publicVersion.overrideAllowlistToken(new Binder());
15943 
15944         // Instead of using the normal parceling, assume the caller parcels it by hand, including a
15945         // null token in the outer notification (as would be expected, and as is verified by
15946         // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets
15947         // propagated to the PendingIntents.
15948         Parcel parcelSentFromApp = Parcel.obtain();
15949         writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>(
15950                 Lists.newArrayList(sentFromApp.contentIntent,
15951                         sentFromApp.publicVersion.contentIntent)));
15952 
15953         // Use the unparceling as received in enqueueNotificationWithTag()
15954         parcelSentFromApp.setDataPosition(0);
15955         Notification receivedByNms = new Notification(parcelSentFromApp);
15956 
15957         // Verify that all the pendingIntents have the correct token.
15958         assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo(
15959                 NotificationManagerService.ALLOWLIST_TOKEN);
15960         assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo(
15961                 NotificationManagerService.ALLOWLIST_TOKEN);
15962     }
15963 
15964     /**
15965      * Replicates the behavior of {@link Notification#writeToParcel} but excluding the
15966      * "always use the same allowlist token as the root notification" parts.
15967      */
15968     private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif,
15969             ArraySet<PendingIntent> allPendingIntents) {
15970         int flags = 0;
15971         parcel.writeInt(1); // version?
15972 
15973         parcel.writeStrongBinder(notif.getAllowlistToken());
15974         parcel.writeLong(notif.when);
15975         parcel.writeLong(notif.creationTime);
15976         if (notif.getSmallIcon() != null) {
15977             parcel.writeInt(1);
15978             notif.getSmallIcon().writeToParcel(parcel, 0);
15979         } else {
15980             parcel.writeInt(0);
15981         }
15982         parcel.writeInt(notif.number);
15983         if (notif.contentIntent != null) {
15984             parcel.writeInt(1);
15985             notif.contentIntent.writeToParcel(parcel, 0);
15986         } else {
15987             parcel.writeInt(0);
15988         }
15989         if (notif.deleteIntent != null) {
15990             parcel.writeInt(1);
15991             notif.deleteIntent.writeToParcel(parcel, 0);
15992         } else {
15993             parcel.writeInt(0);
15994         }
15995         if (notif.tickerText != null) {
15996             parcel.writeInt(1);
15997             TextUtils.writeToParcel(notif.tickerText, parcel, flags);
15998         } else {
15999             parcel.writeInt(0);
16000         }
16001         if (notif.tickerView != null) {
16002             parcel.writeInt(1);
16003             notif.tickerView.writeToParcel(parcel, 0);
16004         } else {
16005             parcel.writeInt(0);
16006         }
16007         if (notif.contentView != null) {
16008             parcel.writeInt(1);
16009             notif.contentView.writeToParcel(parcel, 0);
16010         } else {
16011             parcel.writeInt(0);
16012         }
16013         if (notif.getLargeIcon() != null) {
16014             parcel.writeInt(1);
16015             notif.getLargeIcon().writeToParcel(parcel, 0);
16016         } else {
16017             parcel.writeInt(0);
16018         }
16019 
16020         parcel.writeInt(notif.defaults);
16021         parcel.writeInt(notif.flags);
16022 
16023         if (notif.sound != null) {
16024             parcel.writeInt(1);
16025             notif.sound.writeToParcel(parcel, 0);
16026         } else {
16027             parcel.writeInt(0);
16028         }
16029         parcel.writeInt(notif.audioStreamType);
16030 
16031         if (notif.audioAttributes != null) {
16032             parcel.writeInt(1);
16033             notif.audioAttributes.writeToParcel(parcel, 0);
16034         } else {
16035             parcel.writeInt(0);
16036         }
16037 
16038         parcel.writeLongArray(notif.vibrate);
16039         parcel.writeInt(notif.ledARGB);
16040         parcel.writeInt(notif.ledOnMS);
16041         parcel.writeInt(notif.ledOffMS);
16042         parcel.writeInt(notif.iconLevel);
16043 
16044         if (notif.fullScreenIntent != null) {
16045             parcel.writeInt(1);
16046             notif.fullScreenIntent.writeToParcel(parcel, 0);
16047         } else {
16048             parcel.writeInt(0);
16049         }
16050 
16051         parcel.writeInt(notif.priority);
16052 
16053         parcel.writeString8(notif.category);
16054 
16055         parcel.writeString8(notif.getGroup());
16056 
16057         parcel.writeString8(notif.getSortKey());
16058 
16059         parcel.writeBundle(notif.extras); // null ok
16060 
16061         parcel.writeTypedArray(notif.actions, 0); // null ok
16062 
16063         if (notif.bigContentView != null) {
16064             parcel.writeInt(1);
16065             notif.bigContentView.writeToParcel(parcel, 0);
16066         } else {
16067             parcel.writeInt(0);
16068         }
16069 
16070         if (notif.headsUpContentView != null) {
16071             parcel.writeInt(1);
16072             notif.headsUpContentView.writeToParcel(parcel, 0);
16073         } else {
16074             parcel.writeInt(0);
16075         }
16076 
16077         parcel.writeInt(notif.visibility);
16078 
16079         if (notif.publicVersion != null) {
16080             parcel.writeInt(1);
16081             writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>());
16082         } else {
16083             parcel.writeInt(0);
16084         }
16085 
16086         parcel.writeInt(notif.color);
16087 
16088         if (notif.getChannelId() != null) {
16089             parcel.writeInt(1);
16090             parcel.writeString8(notif.getChannelId());
16091         } else {
16092             parcel.writeInt(0);
16093         }
16094         parcel.writeLong(notif.getTimeoutAfter());
16095 
16096         if (notif.getShortcutId() != null) {
16097             parcel.writeInt(1);
16098             parcel.writeString8(notif.getShortcutId());
16099         } else {
16100             parcel.writeInt(0);
16101         }
16102 
16103         if (notif.getLocusId() != null) {
16104             parcel.writeInt(1);
16105             notif.getLocusId().writeToParcel(parcel, 0);
16106         } else {
16107             parcel.writeInt(0);
16108         }
16109 
16110         parcel.writeInt(notif.getBadgeIconType());
16111 
16112         if (notif.getSettingsText() != null) {
16113             parcel.writeInt(1);
16114             TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags);
16115         } else {
16116             parcel.writeInt(0);
16117         }
16118 
16119         parcel.writeInt(notif.getGroupAlertBehavior());
16120 
16121         if (notif.getBubbleMetadata() != null) {
16122             parcel.writeInt(1);
16123             notif.getBubbleMetadata().writeToParcel(parcel, 0);
16124         } else {
16125             parcel.writeInt(0);
16126         }
16127 
16128         parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions());
16129 
16130         parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior
16131 
16132         // mUsesStandardHeader is not written because it should be recomputed in listeners
16133 
16134         parcel.writeArraySet(allPendingIntents);
16135     }
16136 
16137     @Test
16138     @SuppressWarnings("unchecked")
16139     public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException {
16140         Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID)
16141                 .setContentIntent(createPendingIntent("content"))
16142                 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID)
16143                         .setContentIntent(createPendingIntent("public"))
16144                         .build())
16145                 .extend(new Notification.WearableExtender()
16146                         .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID)
16147                                 .setContentIntent(createPendingIntent("wearPage"))
16148                                 .build()))
16149                 .build();
16150         // Binder transition: app -> NMS
16151         Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR);
16152         assertThat(receivedByNms.getAllowlistToken()).isEqualTo(
16153                 NotificationManagerService.ALLOWLIST_TOKEN);
16154         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
16155                 parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId);
16156         waitForIdle();
16157         assertThat(mService.mNotificationList).hasSize(1);
16158         Notification posted = mService.mNotificationList.get(0).getNotification();
16159         assertThat(posted.getAllowlistToken()).isEqualTo(
16160                 NotificationManagerService.ALLOWLIST_TOKEN);
16161         assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo(
16162                 NotificationManagerService.ALLOWLIST_TOKEN);
16163 
16164         ParceledListSlice<StatusBarNotification> listSentFromNms =
16165                 mBinderService.getAppActiveNotifications(mPkg, mUserId);
16166         // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it
16167         // (having a different one would produce the same effect; the relevant thing is to not let
16168         // out ALLOWLIST_TOKEN).
16169         // Note: for other tests, this is restored by constructing TestableNMS in setup().
16170         Notification.processAllowlistToken = null;
16171         ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel(
16172                 listSentFromNms, ParceledListSlice.CREATOR);
16173         Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification();
16174 
16175         assertThat(gottenBackByApp.getAllowlistToken()).isNull();
16176         assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull();
16177         assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull();
16178         assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull();
16179         assertThat(new Notification.WearableExtender(gottenBackByApp).getPages()
16180                 .get(0).getAllowlistToken()).isNull();
16181         assertThat(new Notification.WearableExtender(gottenBackByApp).getPages()
16182                 .get(0).contentIntent.getWhitelistToken()).isNull();
16183     }
16184 
16185     @Test
16186     public void enqueueNotification_allowlistsPendingIntents() throws RemoteException {
16187         PendingIntent contentIntent = createPendingIntent("content");
16188         PendingIntent actionIntent1 = createPendingIntent("action1");
16189         PendingIntent actionIntent2 = createPendingIntent("action2");
16190         Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID)
16191                 .setContentIntent(contentIntent)
16192                 .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build())
16193                 .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build())
16194                 .build();
16195 
16196         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
16197                 parcelAndUnparcel(n, Notification.CREATOR), mUserId);
16198 
16199         verify(mAmi, times(3)).setPendingIntentAllowlistDuration(
16200                 any(), any(), anyLong(),
16201                 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
16202                 eq(REASON_NOTIFICATION_SERVICE), any());
16203         verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(),
16204                 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
16205         contentIntent.cancel();
16206         actionIntent2.cancel();
16207         actionIntent1.cancel();
16208     }
16209 
16210     @Test
16211     public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion()
16212             throws RemoteException {
16213         PendingIntent contentIntent = createPendingIntent("content");
16214         PendingIntent actionIntent = createPendingIntent("action");
16215         PendingIntent publicContentIntent = createPendingIntent("publicContent");
16216         PendingIntent publicActionIntent = createPendingIntent("publicAction");
16217         Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID)
16218                 .setContentIntent(contentIntent)
16219                 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
16220                 .setPublicVersion(new Notification.Builder(mContext, "channel")
16221                         .setContentIntent(publicContentIntent)
16222                         .addAction(new Notification.Action.Builder(
16223                                 null, "publicAction", publicActionIntent).build())
16224                         .build())
16225                 .build();
16226 
16227         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1,
16228                 parcelAndUnparcel(source, Notification.CREATOR), mUserId);
16229 
16230         verify(mAmi, times(4)).setPendingIntentAllowlistDuration(
16231                 any(), any(), anyLong(),
16232                 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
16233                 eq(REASON_NOTIFICATION_SERVICE), any());
16234         verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(),
16235                 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
16236         contentIntent.cancel();
16237         publicContentIntent.cancel();
16238         actionIntent.cancel();
16239         publicActionIntent.cancel();
16240     }
16241 
16242     @Test
16243     @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
16244     public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() {
16245         mService.mZenModeHelper = mock(ZenModeHelper.class);
16246         mService.setPreferencesHelper(mPreferencesHelper);
16247 
16248         UserInfo prevUser = new UserInfo();
16249         prevUser.id = 10;
16250         UserInfo newUser = new UserInfo();
16251         newUser.id = 20;
16252 
16253         mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser));
16254 
16255         InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
16256         inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
16257         inOrder.verify(mPreferencesHelper).syncHasPriorityChannels();
16258         inOrder.verifyNoMoreInteractions();
16259     }
16260 
16261     @Test
16262     @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
16263     public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() {
16264         Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
16265         intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
16266         mService.mZenModeHelper = mock(ZenModeHelper.class);
16267         mService.setPreferencesHelper(mPreferencesHelper);
16268 
16269         mUserIntentReceiver.onReceive(mContext, intent);
16270 
16271         InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
16272         inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
16273         inOrder.verify(mPreferencesHelper).syncHasPriorityChannels();
16274         inOrder.verifyNoMoreInteractions();
16275     }
16276 
16277     @Test
16278     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16279     public void onUserStopped_callBackToListeners() {
16280         Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
16281         intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
16282 
16283         mUserIntentReceiver.onReceive(mContext, intent);
16284 
16285         verify(mConditionProviders).onUserStopped(eq(20));
16286         verify(mListeners).onUserStopped(eq(20));
16287         verify(mAssistants).onUserStopped(eq(20));
16288     }
16289 
16290     @Test
16291     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16292     public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception {
16293         final String notReal = "NOT REAL";
16294         final var checker = mService.permissionChecker;
16295 
16296         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
16297                 PackageManager.NameNotFoundException.class);
16298 
16299         assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse();
16300         verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt());
16301         verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean());
16302         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt());
16303         verify(mListeners, never()).isComponentEnabledForPackage(any());
16304         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16305     }
16306 
16307     @Test
16308     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16309     public void isNotificationPolicyAccessGranted_invalidPackage_concurrent_multiUser()
16310                 throws Exception {
16311         final String notReal = "NOT REAL";
16312         final var checker = mService.permissionChecker;
16313 
16314         when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
16315                 PackageManager.NameNotFoundException.class);
16316 
16317         assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse();
16318         verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt());
16319         verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean());
16320         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt());
16321         verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt());
16322         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16323     }
16324 
16325     @Test
16326     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16327     public void isNotificationPolicyAccessGranted_hasPermission() throws Exception {
16328         final String packageName = "target";
16329         final int uid = 123;
16330         final var checker = mService.permissionChecker;
16331 
16332         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16333         when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true))
16334                 .thenReturn(PackageManager.PERMISSION_GRANTED);
16335 
16336         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16337         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16338         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16339         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt());
16340         verify(mListeners, never()).isComponentEnabledForPackage(any());
16341         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16342     }
16343 
16344     @Test
16345     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16346     public void isNotificationPolicyAccessGranted_hasPermission_concurrent_multiUser()
16347                 throws Exception {
16348         final String packageName = "target";
16349         final int uid = 123;
16350         final var checker = mService.permissionChecker;
16351 
16352         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16353         when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true))
16354                 .thenReturn(PackageManager.PERMISSION_GRANTED);
16355 
16356         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16357         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16358         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16359         verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt());
16360         verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt());
16361         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16362     }
16363 
16364     @Test
16365     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16366     public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception {
16367         final String packageName = "target";
16368         final int uid = 123;
16369         final var checker = mService.permissionChecker;
16370 
16371         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16372         when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt()))
16373                 .thenReturn(true);
16374 
16375         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16376         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16377         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16378         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16379         verify(mListeners, never()).isComponentEnabledForPackage(any());
16380         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16381     }
16382 
16383     @Test
16384     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16385     public void isNotificationPolicyAccessGranted_isPackageAllowed_concurrent_multiUser()
16386                 throws Exception {
16387         final String packageName = "target";
16388         final int uid = 123;
16389         final var checker = mService.permissionChecker;
16390 
16391         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16392         when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt()))
16393                 .thenReturn(true);
16394 
16395         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16396         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16397         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16398         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16399         verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt());
16400         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16401     }
16402 
16403     @Test
16404     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16405     public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception {
16406         final String packageName = "target";
16407         final int uid = 123;
16408         final var checker = mService.permissionChecker;
16409 
16410         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16411         when(mListeners.isComponentEnabledForPackage(packageName)).thenReturn(true);
16412 
16413         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16414         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16415         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16416         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16417         verify(mListeners).isComponentEnabledForPackage(packageName);
16418         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16419     }
16420 
16421     @Test
16422     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16423     public void isNotificationPolicyAccessGranted_isComponentEnabled_concurrent_multiUser()
16424                 throws Exception {
16425         final String packageName = "target";
16426         final int uid = 123;
16427         final var checker = mService.permissionChecker;
16428 
16429         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16430         when(mListeners.isComponentEnabledForPackage(packageName, mUserId)).thenReturn(true);
16431 
16432         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16433         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16434         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16435         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16436         verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
16437         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
16438     }
16439 
16440     @Test
16441     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16442     public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception {
16443         final String packageName = "target";
16444         final int uid = 123;
16445         final var checker = mService.permissionChecker;
16446 
16447         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16448         when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true);
16449 
16450         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16451         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16452         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16453         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16454         verify(mListeners).isComponentEnabledForPackage(packageName);
16455         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16456     }
16457 
16458     @Test
16459     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16460     public void isNotificationPolicyAccessGranted_isDeviceOwner_concurrent_multiUser()
16461             throws Exception {
16462         final String packageName = "target";
16463         final int uid = 123;
16464         final var checker = mService.permissionChecker;
16465 
16466         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16467         when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true);
16468 
16469         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
16470         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16471         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16472         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16473         verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
16474         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16475     }
16476 
16477     /**
16478      * b/292163859
16479      */
16480     @Test
16481     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16482     public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception {
16483         final String packageName = "target";
16484         final int uid = 123;
16485         final int callingUid = Binder.getCallingUid();
16486         final var checker = mService.permissionChecker;
16487 
16488         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16489         when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true);
16490 
16491         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
16492         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16493         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16494         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16495         verify(mListeners).isComponentEnabledForPackage(packageName);
16496         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16497         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid);
16498     }
16499 
16500     /**
16501      * b/292163859
16502      */
16503     @Test
16504     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16505     public void isNotificationPolicyAccessGranted_callerIsDeviceOwner_concurrent_multiUser()
16506                 throws Exception {
16507         final String packageName = "target";
16508         final int uid = 123;
16509         final int callingUid = Binder.getCallingUid();
16510         final var checker = mService.permissionChecker;
16511 
16512         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16513         when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true);
16514 
16515         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
16516         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16517         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16518         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16519         verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
16520         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16521         verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid);
16522     }
16523 
16524     @Test
16525     @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16526     public void isNotificationPolicyAccessGranted_notGranted() throws Exception {
16527         final String packageName = "target";
16528         final int uid = 123;
16529         final var checker = mService.permissionChecker;
16530 
16531         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16532 
16533         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
16534         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16535         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16536         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16537         verify(mListeners).isComponentEnabledForPackage(packageName);
16538         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16539     }
16540 
16541     @Test
16542     @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
16543     public void isNotificationPolicyAccessGranted_notGranted_concurrent_multiUser()
16544                 throws Exception {
16545         final String packageName = "target";
16546         final int uid = 123;
16547         final var checker = mService.permissionChecker;
16548 
16549         when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
16550 
16551         assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
16552         verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
16553         verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
16554         verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
16555         verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
16556         verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
16557     }
16558 
16559     @Test
16560     public void testResetDefaultDnd() {
16561         TestableNotificationManagerService service = spy(mService);
16562         UserInfo user = new UserInfo(0, "owner", 0);
16563         when(mUm.getAliveUsers()).thenReturn(List.of(user));
16564         doReturn(false).when(service).isDNDMigrationDone(anyInt());
16565 
16566         service.resetDefaultDndIfNecessary();
16567 
16568         verify(mConditionProviders, times(1)).removeDefaultFromConfig(user.id);
16569         verify(mConditionProviders, times(1)).resetDefaultFromConfig();
16570         verify(service, times(1)).allowDndPackages(user.id);
16571         verify(service, times(1)).setDNDMigrationDone(user.id);
16572     }
16573 
16574     @Test
16575     public void testProfileUnavailableIntent() throws RemoteException {
16576         mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE,
16577                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
16578         simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE);
16579         verify(mWorkerHandler).post(any(Runnable.class));
16580         verify(mSnoozeHelper).clearData(anyInt());
16581     }
16582 
16583 
16584     @Test
16585     public void testManagedProfileUnavailableIntent() throws RemoteException {
16586         mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE,
16587                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
16588         simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
16589         verify(mWorkerHandler).post(any(Runnable.class));
16590         verify(mSnoozeHelper).clearData(anyInt());
16591     }
16592 
16593     @Test
16594     public void setDeviceEffectsApplier_succeeds() throws Exception {
16595         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
16596 
16597         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
16598 
16599         mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
16600         // No exception!
16601     }
16602 
16603     @Test
16604     public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
16605         initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
16606 
16607         assertThrows(IllegalStateException.class, () ->
16608                 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
16609     }
16610 
16611     @Test
16612     public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
16613         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
16614 
16615         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
16616         assertThrows(IllegalStateException.class, () ->
16617                 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
16618     }
16619 
16620     @Test
16621     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16622     public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
16623         mService.setCallerIsNormalPackage();
16624         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
16625         mService.mZenModeHelper = zenHelper;
16626         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16627                 .thenReturn(true);
16628 
16629         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16630         mBinderService.setNotificationPolicy("package", policy, false);
16631 
16632         verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(any(), eq("package"), anyInt(),
16633                 eq(policy));
16634     }
16635 
16636     @Test
16637     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16638     public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException {
16639         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16640         mService.mZenModeHelper = zenModeHelper;
16641         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16642                 .thenReturn(true);
16643         mService.isSystemUid = true;
16644 
16645         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16646         mBinderService.setNotificationPolicy("package", policy, false);
16647 
16648         verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt());
16649     }
16650 
16651     @Test
16652     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16653     public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy()
16654             throws RemoteException {
16655         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16656                 AssociationRequest.DEVICE_PROFILE_WATCH, true);
16657     }
16658 
16659     @Test
16660     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16661     public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy()
16662             throws RemoteException {
16663         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16664                 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
16665     }
16666 
16667     @Test
16668     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16669     public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy()
16670             throws RemoteException {
16671         setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16672                 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
16673     }
16674 
16675     private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
16676             @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
16677             throws RemoteException {
16678         mService.setCallerIsNormalPackage();
16679         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16680         mService.mZenModeHelper = zenModeHelper;
16681         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16682                 .thenReturn(true);
16683         when(mCompanionMgr.getAssociations(anyString(), anyInt()))
16684                 .thenReturn(ImmutableList.of(
16685                         new AssociationInfo.Builder(1, mUserId, "package")
16686                                 .setDisplayName("My connected device")
16687                                 .setDeviceProfile(deviceProfile)
16688                                 .build()));
16689 
16690         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16691         mBinderService.setNotificationPolicy("package", policy, false);
16692 
16693         if (canSetGlobalPolicy) {
16694             verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt());
16695         } else {
16696             verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(any(), anyString(), anyInt(),
16697                     eq(policy));
16698         }
16699     }
16700 
16701     @Test
16702     @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16703     public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException {
16704         mService.setCallerIsNormalPackage();
16705         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16706         mService.mZenModeHelper = zenModeHelper;
16707         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16708                 .thenReturn(true);
16709 
16710         NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
16711         mBinderService.setNotificationPolicy("package", policy, false);
16712 
16713         verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt());
16714     }
16715 
16716     @Test
16717     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16718     public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException {
16719         mService.setCallerIsNormalPackage();
16720         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
16721         mService.mZenModeHelper = zenHelper;
16722         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16723                 .thenReturn(true);
16724 
16725         mBinderService.getNotificationPolicy("package");
16726 
16727         verify(zenHelper).getNotificationPolicyFromImplicitZenRule(any(), eq("package"));
16728     }
16729 
16730     @Test
16731     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16732     public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException {
16733         mService.setCallerIsNormalPackage();
16734         ZenModeHelper zenHelper = mock(ZenModeHelper.class);
16735         mService.mZenModeHelper = zenHelper;
16736         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16737                 .thenReturn(true);
16738 
16739         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
16740 
16741         verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("package"), anyInt(),
16742                 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
16743     }
16744 
16745     @Test
16746     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16747     public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException {
16748         mService.setCallerIsNormalPackage();
16749         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16750         mService.mZenModeHelper = zenModeHelper;
16751         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16752                 .thenReturn(true);
16753         mService.isSystemUid = true;
16754 
16755         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
16756 
16757         verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS),
16758                 eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), eq("package"), anyInt());
16759     }
16760 
16761     @Test
16762     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16763     public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException {
16764         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16765                 AssociationRequest.DEVICE_PROFILE_WATCH, true);
16766     }
16767 
16768     @Test
16769     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16770     public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException {
16771         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16772                 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true);
16773     }
16774 
16775     @Test
16776     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16777     public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen()
16778             throws RemoteException {
16779         setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16780                 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false);
16781     }
16782 
16783     private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
16784             @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
16785             throws RemoteException {
16786         ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
16787         mService.mZenModeHelper = zenModeHelper;
16788         mService.setCallerIsNormalPackage();
16789         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16790                 .thenReturn(true);
16791         when(mCompanionMgr.getAssociations(anyString(), anyInt()))
16792                 .thenReturn(ImmutableList.of(
16793                         new AssociationInfo.Builder(1, mUserId, "package")
16794                                 .setDisplayName("My connected device")
16795                                 .setDeviceProfile(deviceProfile)
16796                                 .build()));
16797 
16798         mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false);
16799 
16800         if (canSetGlobalPolicy) {
16801             verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS),
16802                     eq(null), eq(ZenModeConfig.ORIGIN_APP), anyString(), eq("package"), anyInt());
16803         } else {
16804             verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), anyString(), anyInt(),
16805                     eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
16806         }
16807     }
16808 
16809     @Test
16810     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16811     public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen()
16812             throws Exception {
16813         mService.setCallerIsNormalPackage();
16814         mService.mZenModeHelper = mock(ZenModeHelper.class);
16815         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
16816         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
16817         info.component = new ComponentName("pkg", "cls");
16818 
16819         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
16820                 INTERRUPTION_FILTER_PRIORITY);
16821 
16822         verify(mService.mZenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("pkg"),
16823                 eq(mUid), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
16824     }
16825 
16826     @Test
16827     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16828     public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen()
16829             throws Exception {
16830         mService.isSystemUid = true;
16831         mService.mZenModeHelper = mock(ZenModeHelper.class);
16832         ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
16833         when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
16834         info.component = new ComponentName("pkg", "cls");
16835 
16836         mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
16837                 INTERRUPTION_FILTER_PRIORITY);
16838 
16839         verify(mService.mZenModeHelper).setManualZenMode(any(),
16840                 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM),
16841                 anyString(), eq("pkg"), eq(mUid));
16842     }
16843 
16844     @Test
16845     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16846     public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception {
16847         setUpRealZenTest();
16848         mService.setCallerIsNormalPackage();
16849         assertThat(mBinderService.getAutomaticZenRules().getList()).isEmpty();
16850 
16851         // Create an implicit zen rule by calling setNotificationPolicy from an app.
16852         mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false);
16853         assertThat(mBinderService.getAutomaticZenRules().getList()).hasSize(1);
16854         AutomaticZenRule.AzrWithId rule = getOnlyElement(
16855                 (List<AutomaticZenRule.AzrWithId>) mBinderService.getAutomaticZenRules().getList());
16856         assertThat(rule.mRule.getOwner()).isNull();
16857         assertThat(rule.mRule.getConfigurationActivity()).isNull();
16858 
16859         // Now try to update said rule (e.g. disable it). Should fail.
16860         // We also validate the exception message because NPE could be thrown by all sorts of test
16861         // issues (e.g. misconfigured mocks).
16862         rule.mRule.setEnabled(false);
16863         NullPointerException e = assertThrows(NullPointerException.class,
16864                 () -> mBinderService.updateAutomaticZenRule(rule.mId, rule.mRule, false));
16865         assertThat(e.getMessage()).isEqualTo(
16866                 "Rule must have a ConditionProviderService and/or configuration activity");
16867     }
16868 
16869     @Test
16870     @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16871     public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception {
16872         setUpRealZenTest();
16873         mService.setCallerIsNormalPackage();
16874         assertThat(mBinderService.getAutomaticZenRules().getList()).isEmpty();
16875 
16876         // Create an implicit zen rule by calling setNotificationPolicy from an app.
16877         mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false);
16878         assertThat(mBinderService.getAutomaticZenRules().getList()).hasSize(1);
16879         AutomaticZenRule.AzrWithId rule = getOnlyElement(
16880                 (List<AutomaticZenRule.AzrWithId>) mBinderService.getAutomaticZenRules().getList());
16881         assertThat(rule.mRule.getOwner()).isNull();
16882         assertThat(rule.mRule.getConfigurationActivity()).isNull();
16883 
16884         // Now update said rule from Settings (e.g. disable it). Should work!
16885         mService.isSystemUid = true;
16886         rule.mRule.setEnabled(false);
16887         mBinderService.updateAutomaticZenRule(rule.mId, rule.mRule, false);
16888 
16889         AutomaticZenRule.AzrWithId updatedRule = getOnlyElement(
16890                 (List<AutomaticZenRule.AzrWithId>) mBinderService.getAutomaticZenRules().getList());
16891         assertThat(updatedRule.mRule.isEnabled()).isFalse();
16892     }
16893 
16894     @Test
16895     @EnableFlags(android.app.Flags.FLAG_MODES_UI)
16896     public void setNotificationPolicy_fromSystemApp_appliesPriorityChannelsAllowed()
16897             throws Exception {
16898         setUpRealZenTest();
16899         // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default").
16900         mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT,
16901                 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0),
16902                 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID);
16903 
16904         // The caller will supply states with "wrong" hasPriorityChannels.
16905         int stateBlockingPriorityChannels = Policy.policyState(false, false);
16906         mBinderService.setNotificationPolicy(mPkg,
16907                 new Policy(1, 0, 0, 0, stateBlockingPriorityChannels, 0), false);
16908 
16909         // hasPriorityChannels is untouched and allowPriorityChannels was updated.
16910         assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1);
16911         assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo(
16912                 Policy.policyState(true, false));
16913 
16914         // Same but setting allowPriorityChannels to true.
16915         int stateAllowingPriorityChannels = Policy.policyState(false, true);
16916         mBinderService.setNotificationPolicy(mPkg,
16917                 new Policy(2, 0, 0, 0, stateAllowingPriorityChannels, 0), false);
16918 
16919         assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(2);
16920         assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo(
16921                 Policy.policyState(true, true));
16922     }
16923 
16924     @Test
16925     @EnableFlags(android.app.Flags.FLAG_MODES_UI)
16926     @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
16927     public void setNotificationPolicy_fromRegularAppThatCanModifyPolicy_ignoresState()
16928             throws Exception {
16929         setUpRealZenTest();
16930         // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default").
16931         mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT,
16932                 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0),
16933                 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID);
16934         mService.setCallerIsNormalPackage();
16935 
16936         mBinderService.setNotificationPolicy(mPkg,
16937                 new Policy(1, 0, 0, 0, Policy.policyState(false, false), 0), false);
16938 
16939         // Policy was updated but the attempt to change state was ignored (it's a @hide API).
16940         assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1);
16941         assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo(
16942                 Policy.policyState(true, true));
16943     }
16944 
16945     /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */
16946     private void setUpRealZenTest() throws Exception {
16947         when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
16948                 .thenReturn(true);
16949 
16950         int iconResId = 79;
16951         String iconResName = "icon_79";
16952         String pkg = mContext.getPackageName();
16953         ApplicationInfo appInfoSpy = spy(new ApplicationInfo());
16954         appInfoSpy.icon = iconResId;
16955         when(appInfoSpy.loadLabel(any())).thenReturn("Test App");
16956         when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy);
16957 
16958         when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName);
16959         when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId);
16960         when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources);
16961 
16962         // Ensure that there is a zen configuration for the user running the test (won't be
16963         // USER_SYSTEM if running on HSUM).
16964         mService.mZenModeHelper.onUserSwitched(mUserId);
16965     }
16966 
16967     @Test
16968     @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
16969     public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception {
16970         Notification n = new Notification.Builder(mContext, "test")
16971                 .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true)
16972                 .build();
16973 
16974         assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
16975 
16976         mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
16977 
16978         assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
16979     }
16980 
16981     @Test
16982     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne()
16983             throws RemoteException {
16984         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
16985                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
16986 
16987         // Create recent notification.
16988         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
16989                 System.currentTimeMillis());
16990         mService.addNotification(nr1);
16991 
16992         // Create old notification.
16993         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
16994                 System.currentTimeMillis() - 60000);
16995         mService.addNotification(nr2);
16996 
16997         // Cancel specific notifications via listener.
16998         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
16999         mService.getBinderService().cancelNotificationsFromListener(null, keys);
17000         waitForIdle();
17001 
17002         // Notifications should not be active anymore.
17003         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
17004         assertThat(notifications).isEmpty();
17005         assertEquals(0, mService.getNotificationRecordCount());
17006         // Ensure cancel event is logged.
17007         verify(mAppOpsManager).noteOpNoThrow(
17008                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null);
17009     }
17010 
17011     @Test
17012     public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException {
17013         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
17014                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
17015 
17016         // Create old notifications.
17017         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
17018                 System.currentTimeMillis() - 60000);
17019         mService.addNotification(nr1);
17020 
17021         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
17022                 System.currentTimeMillis() - 60000);
17023         mService.addNotification(nr2);
17024 
17025         // Cancel specific notifications via listener.
17026         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
17027         mService.getBinderService().cancelNotificationsFromListener(null, keys);
17028         waitForIdle();
17029 
17030         // Notifications should not be active anymore.
17031         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
17032         assertThat(notifications).isEmpty();
17033         assertEquals(0, mService.getNotificationRecordCount());
17034         // Ensure cancel event is not logged.
17035         verify(mAppOpsManager, never()).noteOpNoThrow(
17036                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
17037                 any(), any());
17038     }
17039 
17040     @Test
17041     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled()
17042             throws RemoteException {
17043         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
17044                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
17045 
17046         // Create recent notification.
17047         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
17048                 System.currentTimeMillis());
17049         mService.addNotification(nr1);
17050 
17051         // Create old notification.
17052         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
17053                 System.currentTimeMillis() - 60000);
17054         mService.addNotification(nr2);
17055 
17056         // Cancel specific notifications via listener.
17057         String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
17058         mService.getBinderService().cancelNotificationsFromListener(null, keys);
17059         waitForIdle();
17060 
17061         // Notifications should not be active anymore.
17062         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
17063         assertThat(notifications).isEmpty();
17064         assertEquals(0, mService.getNotificationRecordCount());
17065         // Ensure cancel event is not logged due to flag being disabled.
17066         verify(mAppOpsManager, never()).noteOpNoThrow(
17067                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
17068                 any(), any());
17069     }
17070 
17071     @Test
17072     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll()
17073             throws RemoteException {
17074         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
17075                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
17076 
17077         // Create recent notification.
17078         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
17079                 System.currentTimeMillis());
17080         mService.addNotification(nr1);
17081 
17082         // Create old notification.
17083         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
17084                 System.currentTimeMillis() - 60000);
17085         mService.addNotification(nr2);
17086 
17087         // Cancel all notifications via listener.
17088         mService.getBinderService().cancelNotificationsFromListener(null, null);
17089         waitForIdle();
17090 
17091         // Notifications should not be active anymore.
17092         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
17093         assertThat(notifications).isEmpty();
17094         assertEquals(0, mService.getNotificationRecordCount());
17095         // Ensure cancel event is logged.
17096         verify(mAppOpsManager).noteOpNoThrow(
17097                 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null);
17098     }
17099 
17100     @Test
17101     public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException {
17102         mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
17103                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
17104 
17105         // Create old notifications.
17106         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
17107                 System.currentTimeMillis() - 60000);
17108         mService.addNotification(nr1);
17109 
17110         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
17111                 System.currentTimeMillis() - 60000);
17112         mService.addNotification(nr2);
17113 
17114         // Cancel all notifications via listener.
17115         mService.getBinderService().cancelNotificationsFromListener(null, null);
17116         waitForIdle();
17117 
17118         // Notifications should not be active anymore.
17119         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
17120         assertThat(notifications).isEmpty();
17121         assertEquals(0, mService.getNotificationRecordCount());
17122         // Ensure cancel event is not logged.
17123         verify(mAppOpsManager, never()).noteOpNoThrow(
17124                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
17125                 any(), any());
17126     }
17127 
17128     @Test
17129     public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled()
17130             throws RemoteException {
17131         mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
17132                 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
17133 
17134         // Create recent notification.
17135         final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
17136                 System.currentTimeMillis());
17137         mService.addNotification(nr1);
17138 
17139         // Create old notification.
17140         final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel,
17141                 System.currentTimeMillis() - 60000);
17142         mService.addNotification(nr2);
17143 
17144         // Cancel all notifications via listener.
17145         mService.getBinderService().cancelNotificationsFromListener(null, null);
17146         waitForIdle();
17147 
17148         // Notifications should not be active anymore.
17149         StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg);
17150         assertThat(notifications).isEmpty();
17151         assertEquals(0, mService.getNotificationRecordCount());
17152         // Ensure cancel event is not logged due to flag being disabled.
17153         verify(mAppOpsManager, never()).noteOpNoThrow(
17154                 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
17155                 any(), any());
17156     }
17157 
17158     @Test
17159     @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS)
17160     public void testSetPrivateNotificationsAllowed() throws Exception {
17161         when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS))
17162                 .thenReturn(PERMISSION_GRANTED);
17163         mBinderService.setPrivateNotificationsAllowed(false);
17164         Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED)
17165                 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false);
17166         ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class);
17167         verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE));
17168 
17169         assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction());
17170         assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true));
17171         assertFalse(mBinderService.getPrivateNotificationsAllowed());
17172     }
17173 
17174     @Test
17175     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
17176     public void testCallNotificationListener_NotifiedOnPostCallStyle() throws Exception {
17177         ICallNotificationEventCallback listener = mock(
17178                 ICallNotificationEventCallback.class);
17179         when(listener.asBinder()).thenReturn(mock(IBinder.class));
17180         mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.CURRENT, listener);
17181         waitForIdle();
17182 
17183         final UserHandle userHandle = UserHandle.getUserHandleForUid(mUid);
17184         final NotificationRecord r = createAndPostCallStyleNotification(mPkg, userHandle,
17185                 "testCallNotificationListener_NotifiedOnPostCallStyle");
17186 
17187         verify(listener, times(1)).onCallNotificationPosted(mPkg, userHandle);
17188 
17189         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
17190                 r.getSbn().getUserId());
17191         waitForIdle();
17192 
17193         verify(listener, times(1)).onCallNotificationRemoved(mPkg, userHandle);
17194     }
17195 
17196     @Test
17197     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
17198     public void testCallNotificationListener_NotNotifiedOnPostNonCallStyle() throws Exception {
17199         ICallNotificationEventCallback listener = mock(
17200                 ICallNotificationEventCallback.class);
17201         when(listener.asBinder()).thenReturn(mock(IBinder.class));
17202         mBinderService.registerCallNotificationEventListener(mPkg,
17203                 UserHandle.getUserHandleForUid(mUid), listener);
17204         waitForIdle();
17205 
17206         Notification.Builder nb = new Notification.Builder(mContext,
17207                 mTestNotificationChannel.getId()).setSmallIcon(android.R.drawable.sym_def_app_icon);
17208         final NotificationRecord r = createAndPostNotification(nb,
17209                 "testCallNotificationListener_NotNotifiedOnPostNonCallStyle");
17210 
17211         verify(listener, never()).onCallNotificationPosted(anyString(), any());
17212 
17213         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
17214                 r.getSbn().getUserId());
17215         waitForIdle();
17216 
17217         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
17218     }
17219 
17220     @Test
17221     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
17222     public void testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId()
17223             throws Exception {
17224         ICallNotificationEventCallback listener = mock(
17225                 ICallNotificationEventCallback.class);
17226         when(listener.asBinder()).thenReturn(mock(IBinder.class));
17227         mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.ALL, listener);
17228         waitForIdle();
17229 
17230         final UserHandle otherUser = UserHandle.of(2);
17231         final NotificationRecord r = createAndPostCallStyleNotification(mPkg,
17232                 otherUser, "testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId");
17233 
17234         verify(listener, times(1)).onCallNotificationPosted(mPkg, otherUser);
17235 
17236         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
17237                 r.getSbn().getUserId());
17238         waitForIdle();
17239 
17240         verify(listener, times(1)).onCallNotificationRemoved(mPkg, otherUser);
17241     }
17242 
17243     @Test
17244     @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API)
17245     public void testCallNotificationListener_differentPackage_notNotified() throws Exception {
17246         final String packageName = "package";
17247         ICallNotificationEventCallback listener = mock(
17248                 ICallNotificationEventCallback.class);
17249         when(listener.asBinder()).thenReturn(mock(IBinder.class));
17250         mBinderService.registerCallNotificationEventListener(packageName, UserHandle.ALL, listener);
17251         waitForIdle();
17252 
17253         final NotificationRecord r = createAndPostCallStyleNotification(mPkg,
17254                 UserHandle.of(mUserId),
17255                 "testCallNotificationListener_differentPackage_notNotified");
17256 
17257         verify(listener, never()).onCallNotificationPosted(anyString(), any());
17258 
17259         mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(),
17260                 r.getSbn().getUserId());
17261         waitForIdle();
17262 
17263         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
17264     }
17265 
17266     @Test
17267     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17268     public void rankingTime_newNotification_noisy_matchesSbn() throws Exception {
17269         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId);
17270 
17271         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17272                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17273         waitForIdle();
17274 
17275         NotificationRecord posted = mService.mNotificationList.get(0);
17276         long originalPostTime = posted.getSbn().getPostTime();
17277         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17278     }
17279 
17280     @Test
17281     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17282     public void rankingTime_newNotification_silent_matchesSbn() throws Exception {
17283         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17284         NotificationRecord nr = generateNotificationRecord(low, mUserId);
17285 
17286         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17287                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17288         waitForIdle();
17289 
17290         NotificationRecord posted = mService.mNotificationList.get(0);
17291         long originalPostTime = posted.getSbn().getPostTime();
17292         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17293     }
17294 
17295     @Test
17296     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17297     public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception {
17298         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17299         NotificationRecord nr = generateNotificationRecord(low, mUserId);
17300 
17301         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17302                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17303         waitForIdle();
17304         NotificationRecord posted = mService.mNotificationList.get(0);
17305         long originalPostTime = posted.getSbn().getPostTime();
17306         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17307 
17308         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17309                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17310         waitForIdle();
17311         assertThat(mService.mNotificationList.get(0).getRankingTimeMs())
17312                 .isEqualTo(originalPostTime);
17313     }
17314 
17315     @Test
17316     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17317     public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception {
17318         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17319         NotificationRecord nr = generateNotificationRecord(low, 0, mUserId);
17320 
17321         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17322                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17323         waitForIdle();
17324         NotificationRecord posted = mService.mNotificationList.get(0);
17325         long originalPostTime = posted.getSbn().getPostTime();
17326         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17327 
17328         NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar");
17329         // no attention helper mocked behavior needed because this does not make noise
17330         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17331                 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
17332                 nrUpdate.getSbn().getUserId());
17333         waitForIdle();
17334 
17335         posted = mService.mNotificationList.get(0);
17336         assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
17337         assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
17338     }
17339 
17340     @Test
17341     @EnableFlags(FLAG_SORT_SECTION_BY_TIME)
17342     public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception {
17343         NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
17344         NotificationRecord nr = generateNotificationRecord(low, mUserId);
17345 
17346         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17347                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
17348         waitForIdle();
17349         NotificationRecord posted = mService.mNotificationList.get(0);
17350         long originalPostTime = posted.getSbn().getPostTime();
17351         assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
17352 
17353         NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId);
17354         when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() {
17355             public Object answer(InvocationOnMock invocation) {
17356                 Object[] args = invocation.getArguments();
17357                 ((NotificationRecord) args[0]).resetRankingTime();
17358                 return 2; // beep
17359             }
17360         });
17361         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0",
17362                 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
17363                 nrUpdate.getSbn().getUserId());
17364         waitForIdle();
17365         posted = mService.mNotificationList.get(0);
17366         assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
17367         assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
17368     }
17369 
17370     @Test
17371     @EnableFlags(android.app.Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA)
17372     public void testRestrictAudioAttributes_listenersGetCorrectAttributes() throws Exception {
17373         NotificationChannel sound = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
17374         sound.setSound(Uri.EMPTY, new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build());
17375         mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(
17376                 Arrays.asList(sound)));
17377 
17378         Notification n = new Notification.Builder(mContext, "a")
17379                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17380                 .build();
17381         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17382                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17383 
17384         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
17385                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
17386         waitForIdle();
17387 
17388         ArgumentCaptor<NotificationRecord> captor =
17389                 ArgumentCaptor.forClass(NotificationRecord.class);
17390         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17391                 captor.capture(), any(), anyBoolean());
17392 
17393         assertThat(captor.getValue().getChannel().getAudioAttributes().getUsage())
17394                 .isEqualTo(USAGE_NOTIFICATION);
17395     }
17396 
17397     @Test
17398     @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
17399     public void testFixNotification_missingTtl() throws Exception {
17400         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17401                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17402                 .build();
17403 
17404         mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
17405 
17406         assertThat(n.getTimeoutAfter()).isEqualTo(NOTIFICATION_TTL);
17407     }
17408 
17409     @Test
17410     @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
17411     public void testFixNotification_doesNotOverwriteTtl() throws Exception {
17412         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17413                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17414                 .setTimeoutAfter(20)
17415                 .build();
17416 
17417         mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true);
17418 
17419         assertThat(n.getTimeoutAfter()).isEqualTo(20);
17420     }
17421 
17422     @Test
17423     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
17424     public void testRejectOldNotification_oldWhen() throws Exception {
17425         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17426                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17427                 .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis())
17428                 .build();
17429         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17430                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17431         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17432 
17433         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
17434                 .isFalse();
17435     }
17436 
17437     @Test
17438     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
17439     public void testRejectOldNotification_mediumOldWhen() throws Exception {
17440         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17441                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17442                 .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis())
17443                 .build();
17444         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17445                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17446         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17447 
17448         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
17449                 .isTrue();
17450     }
17451 
17452     @Test
17453     @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
17454     public void testRejectOldNotification_zeroWhen() throws Exception {
17455         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17456                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17457                 .setWhen(0)
17458                 .build();
17459         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17460                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17461         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17462 
17463         assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
17464                 .isTrue();
17465     }
17466 
17467     @Test
17468     public void testClearUIJFromUninstallingPackage() throws Exception {
17469         NotificationRecord r =
17470                 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar");
17471         mService.addNotification(r);
17472 
17473         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt()))
17474                 .thenThrow(PackageManager.NameNotFoundException.class);
17475         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17476 
17477         mInternalService.cancelNotification(mPkg, mPkg, mUid, 0, r.getSbn().getTag(),
17478                 r.getSbn().getId(), mUserId);
17479 
17480         // no exception
17481     }
17482 
17483     @Test
17484     public void testPostFromMissingPackage_throws() throws Exception {
17485         NotificationRecord r =
17486                 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar");
17487 
17488         when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt()))
17489                 .thenThrow(PackageManager.NameNotFoundException.class);
17490         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17491 
17492         try {
17493             mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(),
17494                     r.getSbn().getId(), r.getSbn().getNotification(),
17495                     r.getSbn().getUserId());
17496             fail("Allowed to post a notification for an absent package");
17497         } catch (SecurityException e) {
17498             // yay
17499         }
17500     }
17501 
17502     @Test
17503     public void testGetEffectsSuppressor_noSuppressor() throws Exception {
17504         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17505         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17506         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true);
17507         assertThat(mBinderService.getEffectsSuppressor()).isNull();
17508     }
17509 
17510     @Test
17511     public void testGetEffectsSuppressor_suppressorSameApp() throws Exception {
17512         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17513         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17514         mService.isSystemUid = false;
17515         mService.isSystemAppId = false;
17516         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
17517                 HINT_HOST_DISABLE_EFFECTS);
17518         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true);
17519         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
17520     }
17521 
17522     @Test
17523     public void testGetEffectsSuppressor_suppressorDiffApp() throws Exception {
17524         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17525         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17526         mService.isSystemUid = false;
17527         mService.isSystemAppId = false;
17528         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
17529                 HINT_HOST_DISABLE_EFFECTS);
17530         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17531         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(null);
17532     }
17533 
17534     @Test
17535     public void testGetEffectsSuppressor_suppressorDiffAppSystemCaller() throws Exception {
17536         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17537         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17538         mService.isSystemUid = true;
17539         mBinderService.requestHintsFromListener(mock(INotificationListener.class),
17540                 HINT_HOST_DISABLE_EFFECTS);
17541         when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
17542         assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
17543     }
17544 
17545     @Test
17546     @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST,
17547             Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS})
17548     public void requestHintsFromListener_changingEffectsButNotSuppressor_noBroadcast()
17549             throws Exception {
17550         // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each
17551         // path will do slightly different calls so we force one of them to simplify the test.
17552         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17553         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17554         INotificationListener token = mock(INotificationListener.class);
17555         mService.isSystemUid = true;
17556 
17557         mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS);
17558         mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY
17559         waitForIdle();
17560 
17561         verify(mContext, times(1)).sendBroadcastMultiplePermissions(
17562                 isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any());
17563 
17564         // Same suppressor suppresses something else.
17565         mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
17566         mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY
17567         waitForIdle();
17568 
17569         // Still 1 total calls (the previous one).
17570         verify(mContext, times(1)).sendBroadcastMultiplePermissions(
17571                 isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any());
17572     }
17573 
17574     @Test
17575     @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST,
17576             Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS})
17577     public void requestHintsFromListener_changingSuppressor_throttlesBroadcast() throws Exception {
17578         // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each
17579         // path will do slightly different calls so we force one of them to simplify the test.
17580         when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId});
17581         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
17582         INotificationListener token = mock(INotificationListener.class);
17583         mService.isSystemUid = true;
17584 
17585         // Several updates in quick succession.
17586         mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS);
17587         mBinderService.clearRequestedListenerHints(token);
17588         mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
17589         mBinderService.clearRequestedListenerHints(token);
17590         mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS);
17591         mBinderService.clearRequestedListenerHints(token);
17592         mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
17593 
17594         // No broadcasts yet!
17595         verify(mContext, never()).sendBroadcastMultiplePermissions(any(), any(), any(), any());
17596 
17597         mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY
17598         waitForIdle();
17599 
17600         // Only one broadcast after idle time.
17601         verify(mContext, times(1)).sendBroadcastMultiplePermissions(
17602                 isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any());
17603     }
17604 
17605     @Test
17606     @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
17607     public void testApplyAdjustment_keyType_validType() throws Exception {
17608         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
17609         mService.addNotification(r);
17610         NotificationManagerService.WorkerHandler handler = mock(
17611                 NotificationManagerService.WorkerHandler.class);
17612         mService.setHandler(handler);
17613         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
17614         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
17615 
17616         Bundle signals = new Bundle();
17617         signals.putInt(KEY_TYPE, TYPE_NEWS);
17618         Adjustment adjustment = new Adjustment(
17619                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
17620         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
17621         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17622 
17623         waitForIdle();
17624 
17625         r.applyAdjustments();
17626 
17627         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
17628 
17629         signals.putInt(KEY_TYPE, TYPE_PROMOTION);
17630         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17631         waitForIdle();
17632         r.applyAdjustments();
17633         assertThat(r.getChannel().getId()).isEqualTo(PROMOTIONS_ID);
17634 
17635         signals.putInt(KEY_TYPE, TYPE_SOCIAL_MEDIA);
17636         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17637         waitForIdle();
17638         r.applyAdjustments();
17639         assertThat(r.getChannel().getId()).isEqualTo(SOCIAL_MEDIA_ID);
17640 
17641         signals.putInt(KEY_TYPE, TYPE_CONTENT_RECOMMENDATION);
17642         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17643         waitForIdle();
17644         r.applyAdjustments();
17645         assertThat(r.getChannel().getId()).isEqualTo(RECS_ID);
17646     }
17647 
17648     @Test
17649     @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
17650             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
17651     public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception {
17652         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
17653         mService.addNotification(r);
17654         NotificationManagerService.WorkerHandler handler = mock(
17655                 NotificationManagerService.WorkerHandler.class);
17656         mService.setHandler(handler);
17657         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
17658         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
17659 
17660         Bundle signals = new Bundle();
17661         signals.putInt(KEY_TYPE, TYPE_NEWS);
17662         Adjustment adjustment = new Adjustment(
17663                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
17664         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
17665         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17666 
17667         waitForIdle();
17668 
17669         r.applyAdjustments();
17670 
17671         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
17672 
17673         // When we block adjustments for this package
17674         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(false);
17675 
17676         signals.putInt(KEY_TYPE, TYPE_PROMOTION);
17677         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
17678         waitForIdle();
17679         r.applyAdjustments();
17680         // Then the adjustment is not applied.
17681         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
17682     }
17683 
17684     @Test
17685     @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING,
17686             android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
17687             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
17688     public void testApplyAdjustment_promotedOngoingNotification_doesNotApply() throws Exception {
17689         // promoted ongoing notification which should not have the adjustment applied
17690         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17691                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17692                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17693                 .setColor(Color.WHITE)
17694                 .setColorized(true)
17695                 .setOngoing(true)
17696                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17697                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17698                 .build();
17699 
17700         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17701                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17702         final NotificationRecord r = new NotificationRecord(mContext, sbn,
17703                 mTestNotificationChannel);
17704 
17705         // regular notification record for contrast
17706         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel);
17707 
17708         mService.addNotification(r);
17709         mService.addNotification(r2);
17710         NotificationManagerService.WorkerHandler handler = mock(
17711                 NotificationManagerService.WorkerHandler.class);
17712         mService.setHandler(handler);
17713         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
17714         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
17715 
17716         Bundle signals = new Bundle();
17717         signals.putInt(KEY_TYPE, TYPE_NEWS);
17718         Bundle signals2 = new Bundle(signals);  // copy for the second adjustment
17719         Adjustment adjustment = new Adjustment(
17720                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
17721         Adjustment a2 = new Adjustment(r2.getSbn().getPackageName(), r2.getKey(), signals2, "",
17722                 r2.getUser().getIdentifier());
17723         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
17724         mBinderService.applyAdjustmentsFromAssistant(null, List.of(adjustment, a2));
17725 
17726         waitForIdle();
17727 
17728         r.applyAdjustments();
17729         r2.applyAdjustments();
17730 
17731         // promoted ongoing notification does not get bundled; regular one does
17732         assertThat(r.getChannel().getId()).isEqualTo(mTestNotificationChannel.getId());
17733         assertThat(r2.getChannel().getId()).isEqualTo(NEWS_ID);
17734     }
17735 
17736     @Test
17737     @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING})
17738     public void testSetCanBePromoted_granted_noui() throws Exception {
17739         testSetCanBePromoted_granted();
17740     }
17741 
17742     @Test
17743     @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING,
17744             android.app.Flags.FLAG_UI_RICH_ONGOING })
17745     public void testSetCanBePromoted_granted_ui() throws Exception {
17746         testSetCanBePromoted_granted();
17747     }
17748 
17749     private void testSetCanBePromoted_granted() throws Exception {
17750         // qualifying posted notification
17751         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17752                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17753                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17754                 .setColor(Color.WHITE)
17755                 .setColorized(true)
17756                 .setOngoing(true)
17757                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17758                 .build();
17759 
17760         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17761                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17762         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17763 
17764         // qualifying enqueued notification
17765         Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17766                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17767                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17768                 .setColor(Color.WHITE)
17769                 .setColorized(true)
17770                 .setOngoing(true)
17771                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17772                 .build();
17773         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0,
17774                 n1, UserHandle.getUserHandleForUid(mUid), null, 0);
17775         NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel);
17776 
17777         // another package but otherwise would qualify
17778         Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17779                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17780                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17781                 .setColor(Color.WHITE)
17782                 .setColorized(true)
17783                 .setOngoing(true)
17784                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17785                 .build();
17786         StatusBarNotification sbn2 = new StatusBarNotification(PKG_O, PKG_O, 7, null, UID_O, 0,
17787                 n2, UserHandle.getUserHandleForUid(UID_O), null, 0);
17788         NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel);
17789 
17790         // not-qualifying posted notification
17791         Notification n3 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17792                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17793                 .build();
17794 
17795         StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17796                 n3, UserHandle.getUserHandleForUid(mUid), null, 0);
17797         NotificationRecord r3 = new NotificationRecord(mContext, sbn3, mTestNotificationChannel);
17798 
17799         mService.addNotification(r3);
17800         mService.addNotification(r2);
17801         mService.addNotification(r);
17802         mService.addEnqueuedNotification(r1);
17803 
17804         // GIVEN - make sure the promoted value does not depend on the default value.
17805         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17806         waitForIdle();
17807         clearInvocations(mListeners);
17808 
17809         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17810 
17811         waitForIdle();
17812 
17813         ArgumentCaptor<NotificationRecord> captor =
17814                 ArgumentCaptor.forClass(NotificationRecord.class);
17815         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17816                 captor.capture(), any(), anyBoolean());
17817 
17818         // the posted one
17819         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17820                 FLAG_PROMOTED_ONGOING)).isTrue();
17821         // the enqueued one
17822         assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isTrue();
17823         // the other app
17824         assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17825         // same app, not qualifying
17826         assertThat(mService.hasFlag(r3.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17827     }
17828 
17829     @Test
17830     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17831     public void testSetCanBePromoted_granted_onlyNotifiesOnce_noui() throws Exception {
17832         testSetCanBePromoted_granted_onlyNotifiesOnce();
17833     }
17834 
17835     @Test
17836     @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING,
17837             android.app.Flags.FLAG_UI_RICH_ONGOING})
17838     public void testSetCanBePromoted_granted_onlyNotifiesOnce_ui() throws Exception {
17839         testSetCanBePromoted_granted_onlyNotifiesOnce();
17840     }
17841 
17842     private void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception {
17843         // qualifying posted notification
17844         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17845                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17846                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17847                 .setColor(Color.WHITE)
17848                 .setColorized(true)
17849                 .setOngoing(true)
17850                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17851                 .build();
17852 
17853         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17854                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17855         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17856 
17857         mService.addNotification(r);
17858         // GIVEN - make sure the promoted value does not depend on the default value.
17859         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17860         waitForIdle();
17861         clearInvocations(mListeners);
17862 
17863         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17864         waitForIdle();
17865         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17866         waitForIdle();
17867 
17868         ArgumentCaptor<NotificationRecord> captor =
17869                 ArgumentCaptor.forClass(NotificationRecord.class);
17870         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17871                 captor.capture(), any(), anyBoolean());
17872     }
17873 
17874     @Test
17875     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17876     public void testSetCanBePromoted_revoked() throws Exception {
17877         // start from true state
17878         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17879 
17880         // qualifying posted notification
17881         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17882                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17883                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17884                 .setColor(Color.WHITE)
17885                 .setColorized(true)
17886                 .setOngoing(true)
17887                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17888                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17889                 .build();
17890 
17891         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17892                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17893         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17894 
17895         // qualifying enqueued notification
17896         Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17897                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17898                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17899                 .setColor(Color.WHITE)
17900                 .setColorized(true)
17901                 .setOngoing(true)
17902                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17903                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17904                 .build();
17905         StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0,
17906                 n1, UserHandle.getUserHandleForUid(mUid), null, 0);
17907         NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel);
17908 
17909         // doesn't qualify, same package
17910         Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17911                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17912                 .build();
17913         StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
17914                 n2, UserHandle.getUserHandleForUid(UID_O), null, 0);
17915         NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel);
17916 
17917         mService.addNotification(r2);
17918         mService.addNotification(r);
17919         mService.addEnqueuedNotification(r1);
17920 
17921         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17922 
17923         waitForIdle();
17924 
17925         ArgumentCaptor<NotificationRecord> captor =
17926                 ArgumentCaptor.forClass(NotificationRecord.class);
17927         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17928                 captor.capture(), any(), anyBoolean());
17929 
17930         // the posted one
17931         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17932                 FLAG_PROMOTED_ONGOING)).isFalse();
17933         // the enqueued one
17934         assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17935         // the not qualifying one
17936         assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse();
17937     }
17938 
17939     @Test
17940     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17941     public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception {
17942         // start from true state
17943         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17944 
17945         // qualifying posted notification
17946         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17947                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17948                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17949                 .setColor(Color.WHITE)
17950                 .setColorized(true)
17951                 .setOngoing(true)
17952                 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post
17953                 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post
17954                 .build();
17955 
17956         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17957                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17958         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
17959 
17960         mService.addNotification(r);
17961 
17962         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17963         waitForIdle();
17964         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
17965         waitForIdle();
17966 
17967         ArgumentCaptor<NotificationRecord> captor =
17968                 ArgumentCaptor.forClass(NotificationRecord.class);
17969         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17970                 captor.capture(), any(), anyBoolean());
17971     }
17972 
17973     @Test
17974     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
17975     public void testPostPromotableNotification() throws Exception {
17976         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
17977         assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue();
17978 
17979         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
17980                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
17981                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
17982                 .setColor(Color.WHITE)
17983                 .setColorized(true)
17984                 .setOngoing(true)
17985                 .build();
17986         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
17987                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
17988 
17989         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
17990                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
17991         waitForIdle();
17992 
17993         ArgumentCaptor<NotificationRecord> captor =
17994                 ArgumentCaptor.forClass(NotificationRecord.class);
17995         verify(mListeners, times(1)).prepareNotifyPostedLocked(
17996                 captor.capture(), any(), anyBoolean());
17997 
17998         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
17999                 FLAG_PROMOTED_ONGOING)).isTrue();
18000     }
18001 
18002     @Test
18003     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
18004     public void testPostPromotableNotification_noPermission() throws Exception {
18005         mBinderService.setCanBePromoted(mPkg, mUid, false, true);
18006         assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isFalse();
18007 
18008         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
18009                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
18010                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
18011                 .setColor(Color.WHITE)
18012                 .setColorized(true)
18013                 .setOngoing(true)
18014                 .build();
18015 
18016         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
18017                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
18018 
18019         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
18020                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
18021         waitForIdle();
18022 
18023         ArgumentCaptor<NotificationRecord> captor =
18024                 ArgumentCaptor.forClass(NotificationRecord.class);
18025         verify(mListeners, times(1)).prepareNotifyPostedLocked(
18026                 captor.capture(), any(), anyBoolean());
18027 
18028         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
18029                 FLAG_PROMOTED_ONGOING)).isFalse();
18030     }
18031 
18032     @Test
18033     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
18034     public void testPostPromotableNotification_unimportantNotification() throws Exception {
18035         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
18036         Notification n = new Notification.Builder(mContext, mMinChannel.getId())
18037                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
18038                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
18039                 .setColor(Color.WHITE)
18040                 .setColorized(true)
18041                 .setOngoing(true)
18042                 .build();
18043 
18044         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
18045                 n, UserHandle.getUserHandleForUid(mUid), null, 0);
18046 
18047         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
18048                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
18049         waitForIdle();
18050 
18051         ArgumentCaptor<NotificationRecord> captor =
18052                 ArgumentCaptor.forClass(NotificationRecord.class);
18053         verify(mListeners, times(1)).prepareNotifyPostedLocked(
18054                 captor.capture(), any(), anyBoolean());
18055 
18056         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
18057                 FLAG_PROMOTED_ONGOING)).isFalse();
18058     }
18059 
18060     @Test
18061     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
18062     public void testAppCannotUseReservedBundleChannels() throws Exception {
18063         mService.mPreferencesHelper.createReservedChannel(mPkg, mUid, TYPE_NEWS);
18064         NotificationChannel news = mBinderService.getNotificationChannel(
18065                 mPkg, mContext.getUserId(), mPkg, NEWS_ID);
18066         assertThat(news).isNotNull();
18067 
18068         NotificationRecord nr = generateNotificationRecord(news);
18069         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
18070                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
18071         waitForIdle();
18072 
18073         assertThat(mService.mNotificationList).isEmpty();
18074     }
18075 
18076     @Test
18077     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18078             FLAG_NOTIFICATION_FORCE_GROUPING,
18079             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18080             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18081     public void testUnclassifyNotification_ungrouped_restoresOriginalChannel() throws Exception {
18082         NotificationManagerService.WorkerHandler handler = mock(
18083                 NotificationManagerService.WorkerHandler.class);
18084         mService.setHandler(handler);
18085         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18086         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18087         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18088         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18089 
18090         // Post a single notification
18091         final boolean hasOriginalSummary = false;
18092         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
18093         final String keyToUnbundle = r.getKey();
18094         mService.addNotification(r);
18095 
18096         // Classify notification into the NEWS bundle
18097         Bundle signals = new Bundle();
18098         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
18099         Adjustment adjustment = new Adjustment(
18100                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
18101         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18102         waitForIdle();
18103         r.applyAdjustments();
18104         // Check that the NotificationRecord channel is updated
18105         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
18106         // Check that the Notification mChannelId is not updated
18107         assertThat(r.getNotification().getChannelId()).isEqualTo(TEST_CHANNEL_ID);
18108         // Check that the bundleType is updated
18109         assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS);
18110 
18111         // Unclassify the notification
18112         mService.unclassifyNotification(keyToUnbundle);
18113 
18114         // Check that the original channel was restored
18115         assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18116         verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r), eq(hasOriginalSummary));
18117     }
18118 
18119     @Test
18120     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18121             FLAG_NOTIFICATION_FORCE_GROUPING,
18122             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18123             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18124     public void testUnclassifyNotification_grouped_restoresOriginalChannel() throws Exception {
18125         NotificationManagerService.WorkerHandler handler = mock(
18126                 NotificationManagerService.WorkerHandler.class);
18127         mService.setHandler(handler);
18128         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18129         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18130         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18131         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18132 
18133         // Post grouped notifications
18134         final String originalGroupName = "originalGroup";
18135         final int summaryId = 0;
18136         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
18137                 summaryId + 1, originalGroupName, false);
18138         mService.addNotification(r1);
18139         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
18140                 summaryId + 2, originalGroupName, false);
18141         mService.addNotification(r2);
18142         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
18143                 summaryId, originalGroupName, true);
18144         mService.addNotification(summary);
18145         final String originalGroupKey = summary.getGroupKey();
18146         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
18147 
18148         // Classify a child notification into the NEWS bundle
18149         final String keyToUnbundle = r1.getKey();
18150         final boolean hasOriginalSummary = true;
18151         Bundle signals = new Bundle();
18152         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
18153         Adjustment adjustment = new Adjustment(r1.getSbn().getPackageName(), r1.getKey(), signals,
18154                 "", r1.getUser().getIdentifier());
18155         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18156         waitForIdle();
18157         r1.applyAdjustments();
18158         assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID);
18159         assertThat(r1.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS);
18160 
18161         // Unclassify the notification
18162         mService.unclassifyNotification(keyToUnbundle);
18163 
18164         // Check that the original channel was restored
18165         assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18166         verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r1), eq(hasOriginalSummary));
18167     }
18168 
18169     @Test
18170     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18171             FLAG_NOTIFICATION_FORCE_GROUPING,
18172             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18173             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18174     public void testUnclassifyNotification_groupedSummaryCanceled_restoresOriginalChannel()
18175             throws Exception {
18176         NotificationManagerService.WorkerHandler handler = mock(
18177                 NotificationManagerService.WorkerHandler.class);
18178         mService.setHandler(handler);
18179         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18180         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18181         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18182         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18183 
18184         // Post grouped notifications
18185         final String originalGroupName = "originalGroup";
18186         final int summaryId = 0;
18187         final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
18188                 summaryId + 1, originalGroupName, false);
18189         mService.addNotification(r1);
18190         final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
18191                 summaryId + 2, originalGroupName, false);
18192         mService.addNotification(r2);
18193         final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
18194                 summaryId, originalGroupName, true);
18195         mService.addNotification(summary);
18196         final String originalGroupKey = summary.getGroupKey();
18197         assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
18198 
18199         // Classify a child notification into the NEWS bundle
18200         final String keyToUnbundle = r1.getKey();
18201         Bundle signals = new Bundle();
18202         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
18203         Adjustment adjustment = new Adjustment(r1.getSbn().getPackageName(), r1.getKey(), signals,
18204                 "", r1.getUser().getIdentifier());
18205         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18206         waitForIdle();
18207         r1.applyAdjustments();
18208         assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID);
18209         assertThat(r1.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS);
18210 
18211         // Cancel original summary
18212         final boolean hasOriginalSummary = false;
18213         mService.mSummaryByGroupKey.remove(summary.getGroupKey());
18214 
18215         // Unclassify the notification
18216         mService.unclassifyNotification(keyToUnbundle);
18217 
18218         // Check that the original channel was restored
18219         assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18220         verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r1), eq(hasOriginalSummary));
18221     }
18222 
18223     @Test
18224     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18225             FLAG_NOTIFICATION_FORCE_GROUPING,
18226             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18227             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18228     public void testReclassifyNotification_restoresBundleChannel() throws Exception {
18229         NotificationManagerService.WorkerHandler handler = mock(
18230                 NotificationManagerService.WorkerHandler.class);
18231         mService.setHandler(handler);
18232         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18233         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18234         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18235         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18236 
18237         // Post a single notification
18238         final boolean hasOriginalSummary = false;
18239         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
18240         final String keyToUnbundle = r.getKey();
18241         mService.addNotification(r);
18242 
18243         // Classify notification into the NEWS bundle
18244         Bundle signals = new Bundle();
18245         signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS);
18246         Adjustment adjustment = new Adjustment(
18247                 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
18248         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18249         waitForIdle();
18250         r.applyAdjustments();
18251         // Check that the NotificationRecord channel is updated
18252         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
18253         assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS);
18254 
18255         // Unbundle the notification
18256         mService.unclassifyNotification(keyToUnbundle);
18257 
18258         // Check that the original channel was restored
18259         assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18260         verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r), eq(hasOriginalSummary));
18261 
18262         Mockito.reset(mRankingHandler);
18263         Mockito.reset(mGroupHelper);
18264 
18265         // Rebundle the notification
18266         mService.reclassifyNotification(keyToUnbundle);
18267 
18268         // Actually apply the adjustments
18269         doAnswer(invocationOnMock -> {
18270             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18271             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18272             return null;
18273         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18274         mService.handleRankingSort();
18275         verify(handler, times(1)).scheduleSendRankingUpdate();
18276 
18277         // Check that the bundle channel was restored
18278         verify(mRankingHandler, times(1)).requestSort();
18279         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
18280     }
18281 
18282     @Test
18283     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18284             FLAG_NOTIFICATION_FORCE_GROUPING,
18285             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18286             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18287     public void testDisallowTypeAdj_unclassifiesAllNotifications() throws Exception {
18288         NotificationManagerService.WorkerHandler handler = mock(
18289                 NotificationManagerService.WorkerHandler.class);
18290         mService.setHandler(handler);
18291         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18292         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18293         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18294         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18295 
18296         // Post some notifications and classify in different bundles
18297         final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
18298         for (int i = 0; i < numNotifications; i++) {
18299             NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
18300             mService.addNotification(r);
18301             Bundle signals = new Bundle();
18302             final int adjustmentType = i + 1;
18303             signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
18304             Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18305                     "", r.getUser().getIdentifier());
18306             mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18307             waitForIdle();
18308             r.applyAdjustments();
18309             r.setBundleType(adjustmentType);
18310             // Check that the NotificationRecord channel is updated
18311             assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18312             assertThat(r.getBundleType()).isEqualTo(adjustmentType);
18313         }
18314 
18315         // Disallow KEY_TYPE adjustment
18316         mBinderService.disallowAssistantAdjustment(Adjustment.KEY_TYPE);
18317         waitForIdle();
18318 
18319         //Check that all notifications have been unbundled
18320         for (NotificationRecord record : mService.mNotificationList) {
18321             // Check that the original channel was restored
18322             assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18323             verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean());
18324         }
18325 
18326         // Re-allow KEY_TYPE adjustment
18327         Mockito.reset(mRankingHandler);
18328         Mockito.reset(mGroupHelper);
18329         mBinderService.allowAssistantAdjustment(Adjustment.KEY_TYPE);
18330         waitForIdle();
18331 
18332         // Actually apply the adjustments
18333         doAnswer(invocationOnMock -> {
18334             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18335             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18336             return null;
18337         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18338         mService.handleRankingSort();
18339 
18340         // Check that the bundle channel was restored for all notifications
18341         verify(handler, times(numNotifications)).scheduleSendRankingUpdate();
18342         verify(mRankingHandler, times(numNotifications)).requestSort();
18343         for (NotificationRecord record : mService.mNotificationList) {
18344             assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18345         }
18346     }
18347 
18348     @Test
18349     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18350             FLAG_NOTIFICATION_FORCE_GROUPING,
18351             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18352             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18353     public void testDisableBundleAdjustmentByType_unclassifiesNotifications() throws Exception {
18354         NotificationManagerService.WorkerHandler handler = mock(
18355                 NotificationManagerService.WorkerHandler.class);
18356         mService.setHandler(handler);
18357         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18358         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18359         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18360         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18361 
18362         // Post some notifications and classify in different bundles
18363         final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
18364         final int numNewsNotifications = 1;
18365         List<String> postedNotificationKeys = new ArrayList();
18366         for (int i = 0; i < numNotifications; i++) {
18367             NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
18368             mService.addNotification(r);
18369             postedNotificationKeys.add(r.getKey());
18370             Bundle signals = new Bundle();
18371             final int adjustmentType = i + 1;
18372             signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
18373             Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18374                     "", r.getUser().getIdentifier());
18375             mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18376             waitForIdle();
18377             r.applyAdjustments();
18378             r.setBundleType(adjustmentType);
18379             // Check that the NotificationRecord channel is updated
18380             assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18381             assertThat(r.getBundleType()).isEqualTo(adjustmentType);
18382         }
18383 
18384         // Disable TYPE_NEWS bundle
18385         mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false);
18386         waitForIdle();
18387 
18388         //Check that all notifications classified as TYPE_NEWS have been unbundled
18389         for (String key : postedNotificationKeys) {
18390             NotificationRecord record= mService.mNotificationsByKey.get(key);
18391             // Check that the original channel was restored
18392             // for notifications classified as TYPE_NEWS
18393             if (record.getBundleType() == TYPE_NEWS) {
18394                 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18395                 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean());
18396             }
18397         }
18398 
18399         // Re-enable TYPE_NEWS bundle
18400         Mockito.reset(mRankingHandler);
18401         Mockito.reset(mGroupHelper);
18402         mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true);
18403         waitForIdle();
18404 
18405         // Actually apply the adjustments
18406         doAnswer(invocationOnMock -> {
18407             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18408             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18409             return null;
18410         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18411         mService.handleRankingSort();
18412 
18413         // Check that the bundle channel was restored
18414         verify(mRankingHandler, times(numNewsNotifications)).requestSort();
18415         for (String key : postedNotificationKeys) {
18416             NotificationRecord record= mService.mNotificationsByKey.get(key);
18417             assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18418         }
18419     }
18420 
18421     @Test
18422     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18423             FLAG_NOTIFICATION_FORCE_GROUPING,
18424             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18425             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18426     public void testDisableBundleAdjustmentByPkg_unclassifiesNotifications() throws Exception {
18427         NotificationManagerService.WorkerHandler handler = mock(
18428                 NotificationManagerService.WorkerHandler.class);
18429         mService.setHandler(handler);
18430         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18431         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18432         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18433         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18434 
18435         // Post some notifications and classify in different bundles
18436         final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
18437         for (int i = 0; i < numNotifications; i++) {
18438             NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
18439             mService.addNotification(r);
18440             Bundle signals = new Bundle();
18441             final int adjustmentType = i + 1;
18442             signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
18443             Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18444                     "", r.getUser().getIdentifier());
18445             mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18446             waitForIdle();
18447             r.applyAdjustments();
18448             r.setBundleType(adjustmentType);
18449             // Check that the NotificationRecord channel is updated
18450             assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18451             assertThat(r.getBundleType()).isEqualTo(adjustmentType);
18452         }
18453 
18454         // Disable TYPE_NEWS bundle
18455         mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, false);
18456         waitForIdle();
18457 
18458         //Check that all notifications were unbundled
18459         for (NotificationRecord record : mService.mNotificationList) {
18460             assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18461             verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean());
18462         }
18463 
18464         // Re-enable bundles for package
18465         Mockito.reset(mRankingHandler);
18466         Mockito.reset(mGroupHelper);
18467         mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, true);
18468         waitForIdle();
18469 
18470         // Actually apply the adjustments
18471         doAnswer(invocationOnMock -> {
18472             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18473             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18474             return null;
18475         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18476         mService.handleRankingSort();
18477 
18478         // Check that the bundle channel was restored
18479         verify(mRankingHandler, times(numNotifications)).requestSort();
18480         for (NotificationRecord record : mService.mNotificationList) {
18481             assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18482         }
18483     }
18484 
18485     @Test
18486     @EnableFlags({FLAG_NM_SUMMARIZATION})
18487     public void testDisableBundleAdjustmentByPkg_unsummarizesNotifications() throws Exception {
18488         NotificationManagerService.WorkerHandler handler = mock(
18489                 NotificationManagerService.WorkerHandler.class);
18490         mService.setHandler(handler);
18491         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18492         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18493         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18494         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18495 
18496         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId);
18497         mService.addNotification(r);
18498         Bundle signals = new Bundle();
18499         signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello");
18500         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18501                 "", r.getUser().getIdentifier());
18502         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18503         waitForIdle();
18504         r.applyAdjustments();
18505         Mockito.clearInvocations(mRankingHandler);
18506 
18507         // Disable summarization for package
18508         mBinderService.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, mPkg, false);
18509         verify(mRankingHandler).requestSort();
18510         mService.handleRankingSort();
18511 
18512         assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull();
18513     }
18514 
18515     @Test
18516     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18517             FLAG_NOTIFICATION_FORCE_GROUPING,
18518             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18519             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18520     public void testDisableBundleAdjustmentByPkg_unclassifiesEnqueuedNotifications()
18521             throws Exception {
18522         NotificationManagerService.WorkerHandler handler = mock(
18523                 NotificationManagerService.WorkerHandler.class);
18524         mService.setHandler(handler);
18525         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18526         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18527         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18528         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18529 
18530         // Enqueue some notifications and classify in different bundles
18531         final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
18532         for (int i = 0; i < numNotifications; i++) {
18533             NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
18534             mService.addEnqueuedNotification(r);
18535             Bundle signals = new Bundle();
18536             final int adjustmentType = i + 1;
18537             signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
18538             Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18539                     "", r.getUser().getIdentifier());
18540             mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
18541             waitForIdle();
18542             r.applyAdjustments();
18543             r.setBundleType(adjustmentType);
18544             // Check that the NotificationRecord channel is updated
18545             assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18546             assertThat(r.getBundleType()).isEqualTo(adjustmentType);
18547         }
18548 
18549         // Disable type adjustment for the package
18550         mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, false);
18551         waitForIdle();
18552 
18553         //Check that all notifications were unbundled
18554         for (NotificationRecord record : mService.mEnqueuedNotifications) {
18555             assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18556             verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean());
18557         }
18558 
18559         // Re-enable bundles for package
18560         Mockito.reset(mRankingHandler);
18561         Mockito.reset(mGroupHelper);
18562         mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, true);
18563         waitForIdle();
18564 
18565         // Actually apply the adjustments
18566         doAnswer(invocationOnMock -> {
18567             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18568             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18569             return null;
18570         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18571         mService.handleRankingSort();
18572 
18573         // Check that the bundle channel was restored
18574         verify(mRankingHandler, times(numNotifications)).requestSort();
18575         for (NotificationRecord record : mService.mEnqueuedNotifications) {
18576             record.applyAdjustments();
18577             assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18578         }
18579     }
18580 
18581     @Test
18582     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18583             FLAG_NOTIFICATION_FORCE_GROUPING,
18584             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18585             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18586     public void testDisableBundleAdjustmentByType_unclassifiesEnqueuedNotifications()
18587             throws Exception {
18588         NotificationManagerService.WorkerHandler handler = mock(
18589                 NotificationManagerService.WorkerHandler.class);
18590         mService.setHandler(handler);
18591         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18592         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18593         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18594         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18595 
18596         // Enqueue some notifications and classify in different bundles
18597         final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
18598         final int numNewsNotifications = 1;
18599         for (int i = 0; i < numNotifications; i++) {
18600             NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
18601             mService.addEnqueuedNotification(r);
18602             Bundle signals = new Bundle();
18603             final int adjustmentType = i + 1;
18604             signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
18605             Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18606                     "", r.getUser().getIdentifier());
18607             mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
18608             waitForIdle();
18609             r.applyAdjustments();
18610             r.setBundleType(adjustmentType);
18611             // Check that the NotificationRecord channel is updated
18612             assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18613             assertThat(r.getBundleType()).isEqualTo(adjustmentType);
18614         }
18615 
18616         // Disable TYPE_NEWS bundle
18617         mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false);
18618         waitForIdle();
18619 
18620         //Check that all notifications were unbundled
18621         for (NotificationRecord record : mService.mEnqueuedNotifications) {
18622             // Check that the original channel was restored
18623             // for notifications classified as TYPE_NEWS
18624             if (record.getBundleType() == TYPE_NEWS) {
18625                 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18626                 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean());
18627             }
18628         }
18629 
18630         // Re-enable bundles for package
18631         Mockito.reset(mRankingHandler);
18632         Mockito.reset(mGroupHelper);
18633         mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true);
18634         waitForIdle();
18635 
18636         // Actually apply the adjustments
18637         doAnswer(invocationOnMock -> {
18638             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18639             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18640             return null;
18641         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18642         mService.handleRankingSort();
18643 
18644         // Check that the bundle channel was restored
18645         verify(mRankingHandler, times(numNewsNotifications)).requestSort();
18646         for (NotificationRecord record : mService.mEnqueuedNotifications) {
18647             record.applyAdjustments();
18648             assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18649         }
18650     }
18651 
18652     @Test
18653     @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
18654             FLAG_NOTIFICATION_FORCE_GROUPING,
18655             FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
18656             android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
18657     public void testDisallowTypeAdj_unclassifiesAllEnqueuedNotifications() throws Exception {
18658         NotificationManagerService.WorkerHandler handler = mock(
18659                 NotificationManagerService.WorkerHandler.class);
18660         mService.setHandler(handler);
18661         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18662         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18663         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18664         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18665 
18666         // Enqueue some notifications and classify in different bundles
18667         final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
18668         for (int i = 0; i < numNotifications; i++) {
18669             NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
18670             mService.addEnqueuedNotification(r);
18671             Bundle signals = new Bundle();
18672             final int adjustmentType = i + 1;
18673             signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
18674             Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18675                     "", r.getUser().getIdentifier());
18676             mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
18677             waitForIdle();
18678             r.applyAdjustments();
18679             r.setBundleType(adjustmentType);
18680             // Check that the NotificationRecord channel is updated
18681             assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18682             assertThat(r.getBundleType()).isEqualTo(adjustmentType);
18683         }
18684 
18685         // Disable KEY_TYPE adjustment
18686         mBinderService.disallowAssistantAdjustment(Adjustment.KEY_TYPE);
18687         waitForIdle();
18688 
18689         //Check that all notifications were unbundled
18690         for (NotificationRecord record : mService.mEnqueuedNotifications) {
18691             assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID);
18692             verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean());
18693         }
18694 
18695         // Re-enable bundles
18696         Mockito.reset(mRankingHandler);
18697         Mockito.reset(mGroupHelper);
18698         mBinderService.allowAssistantAdjustment(Adjustment.KEY_TYPE);
18699         waitForIdle();
18700 
18701         // Actually apply the adjustments
18702         doAnswer(invocationOnMock -> {
18703             ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
18704             ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
18705             return null;
18706         }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
18707         mService.handleRankingSort();
18708 
18709         // Check that the bundle channel was restored
18710         verify(mRankingHandler, times(numNotifications)).requestSort();
18711         for (NotificationRecord record : mService.mEnqueuedNotifications) {
18712             record.applyAdjustments();
18713             assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
18714         }
18715     }
18716 
18717     @Test
18718     @EnableFlags({FLAG_NM_SUMMARIZATION})
18719     public void testDisableBundleAdjustment_unsummarizesNotifications() throws Exception {
18720         NotificationManagerService.WorkerHandler handler = mock(
18721                 NotificationManagerService.WorkerHandler.class);
18722         mService.setHandler(handler);
18723         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
18724         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
18725         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
18726         when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
18727 
18728         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId);
18729         mService.addNotification(r);
18730         Bundle signals = new Bundle();
18731         signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello");
18732         Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
18733                 "", r.getUser().getIdentifier());
18734         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
18735         waitForIdle();
18736         r.applyAdjustments();
18737         Mockito.clearInvocations(mRankingHandler);
18738 
18739         // Disable summarization for package
18740         mBinderService.disallowAssistantAdjustment(KEY_SUMMARIZATION);
18741         verify(mRankingHandler).requestSort();
18742         mService.handleRankingSort();
18743 
18744         assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull();
18745     }
18746 
18747     @Test
18748     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
18749     public void clearAll_fromUser_willSendDeleteIntentForCachedSummaries() throws Exception {
18750         NotificationRecord n = generateNotificationRecord(
18751                 mTestNotificationChannel, 1, "group", true);
18752         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
18753                 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId());
18754         waitForIdle();
18755         n = Iterables.getOnlyElement(mService.mNotificationList);
18756 
18757         mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), n.getUserId());
18758         waitForIdle();
18759 
18760         verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(true));
18761     }
18762 
18763     @Test
18764     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
18765     public void cancel_fromApp_willNotSendDeleteIntentForCachedSummaries() throws Exception {
18766         NotificationRecord n = generateNotificationRecord(
18767                 mTestNotificationChannel, 1, "group", true);
18768         mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag",
18769                 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId());
18770         waitForIdle();
18771         n = Iterables.getOnlyElement(mService.mNotificationList);
18772 
18773         mBinderService.cancelAllNotifications(mPkg, mUserId);
18774         waitForIdle();
18775 
18776         verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(false));
18777     }
18778 
18779     @Test
18780     public void onDisplayRemoveSystemDecorations_cancelToasts() throws RemoteException {
18781         final String testPackage = "testPackageName";
18782         final INotificationManager service = ((INotificationManager) mService.mService);
18783         final IBinder firstExternal = new Binder();
18784         final IBinder secondExternal = new Binder();
18785         final IBinder firstBuiltin = new Binder();
18786         service.enqueueTextToast(testPackage,
18787                 firstExternal, "First external", TOAST_DURATION,
18788                 /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
18789         service.enqueueTextToast(testPackage,
18790                 secondExternal, "Second external", TOAST_DURATION,
18791                 /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
18792         service.enqueueTextToast(testPackage,
18793                 firstBuiltin, "First built-in", TOAST_DURATION, /* isUiContext= */ true,
18794                 /* displayId= */ DEFAULT_DISPLAY, /* callback= */ null);
18795 
18796         mInternalService.onDisplayRemoveSystemDecorations(10);
18797 
18798         verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstExternal),
18799                 any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
18800         verify(mStatusBar).hideToast(eq(testPackage), eq(firstExternal));
18801         // The second toast has not been shown but invokes hide() anyway as
18802         // NotificationManagerService does not remembered if it invoked show().
18803         verify(mStatusBar, never()).showToast(anyInt(), eq(testPackage), eq(secondExternal),
18804                 any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
18805         verify(mStatusBar).hideToast(eq(testPackage), eq(secondExternal));
18806         // The toast on the default display is shown as other notifications are cancelled.
18807         verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstBuiltin), any(String.class),
18808                 any(IBinder.class), anyInt(), any(), eq(DEFAULT_DISPLAY));
18809         verify(mStatusBar, never()).hideToast(eq(testPackage), eq(firstBuiltin));
18810     }
18811 }
18812