1 /*
2  * Copyright (C) 2018 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 package com.android.server.notification;
17 
18 import static android.app.AppOpsManager.MODE_ALLOWED;
19 import static android.app.AppOpsManager.MODE_DEFAULT;
20 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
21 import static android.app.Flags.FLAG_MODES_UI;
22 import static android.app.Notification.VISIBILITY_PRIVATE;
23 import static android.app.Notification.VISIBILITY_SECRET;
24 import static android.app.NotificationChannel.ALLOW_BUBBLE_ON;
25 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
26 import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE;
27 import static android.app.NotificationChannel.NEWS_ID;
28 import static android.app.NotificationChannel.PROMOTIONS_ID;
29 import static android.app.NotificationChannel.RECS_ID;
30 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
31 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
32 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
33 import static android.app.NotificationChannel.USER_LOCKED_LIGHTS;
34 import static android.app.NotificationChannel.USER_LOCKED_PRIORITY;
35 import static android.app.NotificationChannel.USER_LOCKED_SHOW_BADGE;
36 import static android.app.NotificationChannel.USER_LOCKED_SOUND;
37 import static android.app.NotificationChannel.USER_LOCKED_VIBRATION;
38 import static android.app.NotificationChannel.USER_LOCKED_VISIBILITY;
39 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
40 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
41 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
42 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
43 import static android.app.NotificationManager.IMPORTANCE_HIGH;
44 import static android.app.NotificationManager.IMPORTANCE_LOW;
45 import static android.app.NotificationManager.IMPORTANCE_MAX;
46 import static android.app.NotificationManager.IMPORTANCE_NONE;
47 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
48 import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
49 import static android.content.ContentResolver.SCHEME_ANDROID_RESOURCE;
50 import static android.content.ContentResolver.SCHEME_CONTENT;
51 import static android.content.ContentResolver.SCHEME_FILE;
52 import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION;
53 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
54 import static android.os.UserHandle.USER_ALL;
55 import static android.os.UserHandle.USER_SYSTEM;
56 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
57 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
58 import static android.service.notification.Adjustment.TYPE_NEWS;
59 import static android.service.notification.Adjustment.TYPE_OTHER;
60 import static android.service.notification.Adjustment.TYPE_PROMOTION;
61 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
62 import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
63 import static android.service.notification.Flags.notificationClassification;
64 
65 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS;
66 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
67 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
68 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
69 import static com.android.server.notification.Flags.FLAG_NOTIFICATION_VERIFY_CHANNEL_SOUND_URI;
70 import static com.android.server.notification.Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA;
71 import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER;
72 import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
73 import static com.android.server.notification.PreferencesHelper.LockableAppFields.USER_LOCKED_PROMOTABLE;
74 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
75 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT;
76 import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
77 
78 import static com.google.common.truth.Truth.assertThat;
79 
80 import static junit.framework.Assert.assertNull;
81 import static junit.framework.Assert.fail;
82 
83 import static org.junit.Assert.assertEquals;
84 import static org.junit.Assert.assertFalse;
85 import static org.junit.Assert.assertNotNull;
86 import static org.junit.Assert.assertThrows;
87 import static org.junit.Assert.assertTrue;
88 import static org.mockito.ArgumentMatchers.any;
89 import static org.mockito.ArgumentMatchers.anyBoolean;
90 import static org.mockito.ArgumentMatchers.anyInt;
91 import static org.mockito.ArgumentMatchers.anyString;
92 import static org.mockito.ArgumentMatchers.eq;
93 import static org.mockito.Mockito.clearInvocations;
94 import static org.mockito.Mockito.doAnswer;
95 import static org.mockito.Mockito.doReturn;
96 import static org.mockito.Mockito.doThrow;
97 import static org.mockito.Mockito.mock;
98 import static org.mockito.Mockito.never;
99 import static org.mockito.Mockito.reset;
100 import static org.mockito.Mockito.times;
101 import static org.mockito.Mockito.verify;
102 import static org.mockito.Mockito.verifyZeroInteractions;
103 import static org.mockito.Mockito.when;
104 
105 import android.app.AppOpsManager;
106 import android.app.Notification;
107 import android.app.NotificationChannel;
108 import android.app.NotificationChannelGroup;
109 import android.app.NotificationManager;
110 import android.app.ZenBypassingApp;
111 import android.content.AttributionSource;
112 import android.content.ContentProvider;
113 import android.content.ContentResolver;
114 import android.content.Context;
115 import android.content.IContentProvider;
116 import android.content.pm.ApplicationInfo;
117 import android.content.pm.PackageInfo;
118 import android.content.pm.PackageManager;
119 import android.content.pm.Signature;
120 import android.content.pm.UserInfo;
121 import android.content.res.Resources;
122 import android.graphics.Color;
123 import android.media.AudioAttributes;
124 import android.net.Uri;
125 import android.os.AsyncTask;
126 import android.os.Build;
127 import android.os.Bundle;
128 import android.os.Parcel;
129 import android.os.Process;
130 import android.os.RemoteCallback;
131 import android.os.RemoteException;
132 import android.os.UserHandle;
133 import android.os.UserManager;
134 import android.permission.PermissionManager;
135 import android.platform.test.annotations.DisableFlags;
136 import android.platform.test.annotations.EnableFlags;
137 import android.platform.test.flag.junit.FlagsParameterization;
138 import android.platform.test.flag.junit.SetFlagsRule;
139 import android.provider.Settings;
140 import android.provider.Settings.Global;
141 import android.provider.Settings.Secure;
142 import android.service.notification.ConversationChannelWrapper;
143 import android.service.notification.nano.RankingHelperProto;
144 import android.testing.TestableContentResolver;
145 import android.text.format.DateUtils;
146 import android.util.ArrayMap;
147 import android.util.ArraySet;
148 import android.util.IntArray;
149 import android.util.Pair;
150 import android.util.StatsEvent;
151 import android.util.StatsEventTestUtils;
152 import android.util.Xml;
153 import android.util.proto.ProtoOutputStream;
154 
155 import androidx.test.InstrumentationRegistry;
156 import androidx.test.filters.SmallTest;
157 
158 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
159 import com.android.internal.config.sysui.TestableFlagResolver;
160 import com.android.modules.utils.TypedXmlPullParser;
161 import com.android.modules.utils.TypedXmlSerializer;
162 import com.android.os.AtomsProto;
163 import com.android.os.AtomsProto.PackageNotificationChannelPreferences;
164 import com.android.os.AtomsProto.PackageNotificationPreferences;
165 import com.android.server.UiServiceTestCase;
166 import com.android.server.notification.PermissionHelper.PackagePermission;
167 
168 import com.google.common.collect.ImmutableList;
169 import com.google.common.collect.ImmutableSet;
170 import com.google.protobuf.InvalidProtocolBufferException;
171 
172 import org.json.JSONArray;
173 import org.json.JSONObject;
174 import org.junit.After;
175 import org.junit.Before;
176 import org.junit.Rule;
177 import org.junit.Test;
178 import org.junit.runner.RunWith;
179 import org.mockito.Mock;
180 import org.mockito.MockitoAnnotations;
181 
182 import java.io.BufferedInputStream;
183 import java.io.BufferedOutputStream;
184 import java.io.ByteArrayInputStream;
185 import java.io.ByteArrayOutputStream;
186 import java.io.FileNotFoundException;
187 import java.io.PrintWriter;
188 import java.io.StringWriter;
189 import java.time.Clock;
190 import java.time.Duration;
191 import java.util.ArrayList;
192 import java.util.Arrays;
193 import java.util.HashMap;
194 import java.util.LinkedList;
195 import java.util.List;
196 import java.util.Map;
197 import java.util.Objects;
198 import java.util.Set;
199 import java.util.concurrent.CountDownLatch;
200 import java.util.concurrent.ThreadLocalRandom;
201 
202 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
203 import platform.test.runner.parameterized.Parameters;
204 
205 @SmallTest
206 @RunWith(ParameterizedAndroidJunit4.class)
207 @EnableFlags(FLAG_PERSIST_INCOMPLETE_RESTORE_DATA)
208 public class PreferencesHelperTest extends UiServiceTestCase {
209     private static final int UID_HEADLESS = 1000000;
210     private static final UserHandle USER = UserHandle.of(0);
211     private static final String SYSTEM_PKG = "android";
212     private static final int SYSTEM_UID = 1000;
213     private static final UserHandle USER2 = UserHandle.of(10);
214     private static final String TEST_AUTHORITY = "test";
215     private static final Uri SOUND_URI =
216             Uri.parse("content://" + TEST_AUTHORITY + "/internal/audio/media/10");
217     private static final Uri CANONICAL_SOUND_URI =
218             Uri.parse("content://" + TEST_AUTHORITY
219                     + "/internal/audio/media/10?title=Test&canonical=1");
220 
221     private static final Uri ANDROID_RES_SOUND_URI =
222             Uri.parse("android.resource://" + TEST_AUTHORITY + "/raw/test");
223 
224     private static final Uri FILE_SOUND_URI =
225             Uri.parse("file://" + TEST_AUTHORITY + "/product/media/test.ogg");
226 
227     private static final Uri DEFAULT_SOUND_URI = Uri.parse(
228             "content://settings/system/notification_sound");
229 
230     @Mock PermissionHelper mPermissionHelper;
231     @Mock RankingHandler mHandler;
232     @Mock PackageManager mPm;
233     IContentProvider mTestIContentProvider;
234     @Mock Context mContext;
235     @Mock ZenModeHelper mMockZenModeHelper;
236     @Mock AppOpsManager mAppOpsManager;
237     @Mock ManagedServices.UserProfiles mUserProfiles;
238     @Mock PermissionManager mPermissionManager;
239 
240     private NotificationManager.Policy mTestNotificationPolicy;
241 
242     private PreferencesHelper mHelper;
243     // fresh object for testing xml reading
244     private PreferencesHelper mXmlHelper;
245     private AudioAttributes mAudioAttributes;
246     private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
247 
248     @Rule
249     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
250 
251     @Mock
252     Clock mClock;
253 
254     @Parameters(name = "{0}")
getParams()255     public static List<FlagsParameterization> getParams() {
256         return FlagsParameterization.allCombinationsOf(
257                 android.app.Flags.FLAG_API_RICH_ONGOING,
258                 FLAG_NOTIFICATION_CLASSIFICATION, FLAG_MODES_UI);
259     }
260 
PreferencesHelperTest(FlagsParameterization flags)261     public PreferencesHelperTest(FlagsParameterization flags) {
262         mSetFlagsRule.setFlagsParameterization(flags);
263     }
264 
265     @Before
setUp()266     public void setUp() throws Exception {
267         MockitoAnnotations.initMocks(this);
268 
269         final ApplicationInfo legacy = new ApplicationInfo();
270         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
271         final ApplicationInfo upgrade = new ApplicationInfo();
272         upgrade.targetSdkVersion = Build.VERSION_CODES.O;
273         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
274         when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(upgrade);
275         when(mPm.getApplicationInfoAsUser(eq(PKG_P), anyInt(), anyInt())).thenReturn(upgrade);
276         when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade);
277         when(mPm.getPackageUidAsUser(eq(PKG_N_MR1), anyInt())).thenReturn(UID_N_MR1);
278         when(mPm.getPackageUidAsUser(eq(PKG_O), anyInt())).thenReturn(UID_O);
279         when(mPm.getPackageUidAsUser(eq(PKG_P), anyInt())).thenReturn(UID_P);
280         when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID);
281         PackageInfo info = mock(PackageInfo.class);
282         info.signatures = new Signature[] {mock(Signature.class)};
283         when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info);
284         when(mPm.getPackageInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt()))
285                 .thenReturn(mock(PackageInfo.class));
286         when(mContext.getResources()).thenReturn(
287                 InstrumentationRegistry.getContext().getResources());
288         when(mContext.getContentResolver()).thenReturn(
289                 InstrumentationRegistry.getContext().getContentResolver());
290         when(mPm.getPermissionFlags(any(), any(), any()))
291                 .thenReturn(PackageManager.FLAG_PERMISSION_USER_SET);
292         when(mContext.getPackageManager()).thenReturn(mPm);
293         when(mContext.getApplicationInfo()).thenReturn(legacy);
294         // most tests assume badging is enabled
295         TestableContentResolver contentResolver = getContext().getContentResolver();
296         contentResolver.setFallbackToExisting(false);
297         Secure.putIntForUser(contentResolver,
298                 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1));
299         Secure.putIntForUser(contentResolver, Secure.NOTIFICATION_BUBBLES, 1,
300                 UserHandle.getUserId(UID_N_MR1));
301 
302         ContentProvider testContentProvider = mock(ContentProvider.class);
303         mTestIContentProvider = mock(IContentProvider.class, invocation -> {
304             throw new UnsupportedOperationException("unimplemented mock method");
305         });
306         doAnswer(invocation -> {
307             AttributionSource attributionSource = invocation.getArgument(0);
308             Uri uri = invocation.getArgument(1);
309             RemoteCallback cb = invocation.getArgument(2);
310             IContentProvider mock = (IContentProvider) (invocation.getMock());
311             AsyncTask.SERIAL_EXECUTOR.execute(() -> {
312                 final Bundle bundle = new Bundle();
313                 try {
314                     bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
315                             mock.canonicalize(attributionSource, uri));
316                 } catch (RemoteException e) { /* consume */ }
317                 cb.sendResult(bundle);
318             });
319             return null;
320         }).when(mTestIContentProvider).canonicalizeAsync(any(), any(), any());
321         doAnswer(invocation -> {
322             AttributionSource attributionSource = invocation.getArgument(0);
323             Uri uri = invocation.getArgument(1);
324             RemoteCallback cb = invocation.getArgument(2);
325             IContentProvider mock = (IContentProvider) (invocation.getMock());
326             AsyncTask.SERIAL_EXECUTOR.execute(() -> {
327                 final Bundle bundle = new Bundle();
328                 try {
329                     bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
330                             mock.uncanonicalize(attributionSource, uri));
331                 } catch (RemoteException e) { /* consume */ }
332                 cb.sendResult(bundle);
333             });
334             return null;
335         }).when(mTestIContentProvider).uncanonicalizeAsync(any(), any(), any());
336         doAnswer(invocation -> {
337             Uri uri = invocation.getArgument(0);
338             RemoteCallback cb = invocation.getArgument(1);
339             IContentProvider mock = (IContentProvider) (invocation.getMock());
340             AsyncTask.SERIAL_EXECUTOR.execute(() -> {
341                 final Bundle bundle = new Bundle();
342                 try {
343                     bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, mock.getType(uri));
344                 } catch (RemoteException e) { /* consume */ }
345                 cb.sendResult(bundle);
346             });
347             return null;
348         }).when(mTestIContentProvider).getTypeAsync(any(), any());
349 
350         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
351         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
352 
353         doReturn(CANONICAL_SOUND_URI)
354                 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
355         doReturn(CANONICAL_SOUND_URI)
356                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
357         doReturn(SOUND_URI)
358                 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
359 
360         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
361                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
362         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
363         when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(),
364                 anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT);
365 
366         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
367         appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
368         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(true, false));
369         appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
370 
371         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
372                 .thenReturn(appPermissions);
373 
374         IntArray currentProfileIds = IntArray.wrap(new int[]{0});
375         if (UserManager.isHeadlessSystemUserMode()) {
376             currentProfileIds.add(UserHandle.getUserId(UID_HEADLESS));
377         }
378         when(mUserProfiles.getCurrentProfileIds()).thenReturn(currentProfileIds);
379         when(mClock.millis()).thenReturn(System.currentTimeMillis());
380 
381         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
382                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
383                 mUgmInternal, false, mClock);
384         mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
385                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
386                 mUgmInternal, false, mClock);
387         resetZenModeHelper();
388 
389         mAudioAttributes = new AudioAttributes.Builder()
390                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
391                 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
392                 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
393                 .build();
394 
395         // make sure that the settings for review notification permissions are unset to begin with
396         Settings.Global.putInt(mContext.getContentResolver(),
397                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
398                 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN);
399     }
400 
401     @After
tearDown()402     public void tearDown() {
403         SystemUiSystemPropertiesFlags.TEST_RESOLVER = null;
404     }
405 
writeXmlAndPurge( String pkg, int uid, boolean forBackup, int userId, String... channelIds)406     private ByteArrayOutputStream writeXmlAndPurge(
407             String pkg, int uid, boolean forBackup, int userId, String... channelIds)
408             throws Exception {
409         TypedXmlSerializer serializer = Xml.newFastSerializer();
410         ByteArrayOutputStream baos = new ByteArrayOutputStream();
411         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
412         serializer.startDocument(null, true);
413         mHelper.writeXml(serializer, forBackup, userId);
414         serializer.endDocument();
415         serializer.flush();
416         for (String channelId : channelIds) {
417             mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
418         }
419         return baos;
420     }
421 
loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId)422     private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId)
423             throws Exception {
424         loadByteArrayXml(stream.toByteArray(), forRestore, userId);
425     }
426 
loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)427     private void loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)
428             throws Exception {
429         TypedXmlPullParser parser = Xml.newFastPullParser();
430         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null);
431         parser.nextTag();
432         mXmlHelper.readXml(parser, forRestore, userId);
433     }
434 
compareChannels(NotificationChannel expected, NotificationChannel actual)435     private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
436         assertEquals(expected.getId(), actual.getId());
437         assertEquals(expected.getName(), actual.getName());
438         assertEquals(expected.getDescription(), actual.getDescription());
439         assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
440         assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
441         assertEquals(expected.getImportance(), actual.getImportance());
442         assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
443         assertEquals(expected.getSound(), actual.getSound());
444         assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
445         assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
446         assertEquals(expected.getVibrationEffect(), actual.getVibrationEffect());
447         assertEquals(expected.getGroup(), actual.getGroup());
448         assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes());
449         assertEquals(expected.getLightColor(), actual.getLightColor());
450         assertEquals(expected.getParentChannelId(), actual.getParentChannelId());
451         assertEquals(expected.getConversationId(), actual.getConversationId());
452         assertEquals(expected.isDemoted(), actual.isDemoted());
453     }
454 
compareChannelsParentChild(NotificationChannel parent, NotificationChannel actual, String conversationId)455     private void compareChannelsParentChild(NotificationChannel parent,
456             NotificationChannel actual, String conversationId) {
457         assertEquals(parent.getName(), actual.getName());
458         assertEquals(parent.getDescription(), actual.getDescription());
459         assertEquals(parent.shouldVibrate(), actual.shouldVibrate());
460         assertEquals(parent.shouldShowLights(), actual.shouldShowLights());
461         assertEquals(parent.getImportance(), actual.getImportance());
462         assertEquals(parent.getLockscreenVisibility(), actual.getLockscreenVisibility());
463         assertEquals(parent.getSound(), actual.getSound());
464         assertEquals(parent.canBypassDnd(), actual.canBypassDnd());
465         assertTrue(Arrays.equals(parent.getVibrationPattern(), actual.getVibrationPattern()));
466         assertEquals(parent.getVibrationEffect(), actual.getVibrationEffect());
467         assertEquals(parent.getGroup(), actual.getGroup());
468         assertEquals(parent.getAudioAttributes(), actual.getAudioAttributes());
469         assertEquals(parent.getLightColor(), actual.getLightColor());
470         assertEquals(parent.getId(), actual.getParentChannelId());
471         assertEquals(conversationId, actual.getConversationId());
472     }
473 
compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual)474     private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
475         assertEquals(expected.getId(), actual.getId());
476         assertEquals(expected.getName(), actual.getName());
477         assertEquals(expected.getDescription(), actual.getDescription());
478         assertEquals(expected.isBlocked(), actual.isBlocked());
479     }
480 
getChannel()481     private NotificationChannel getChannel() {
482         return new NotificationChannel("id", "name", IMPORTANCE_LOW);
483     }
484 
findChannel(List<NotificationChannel> channels, String id)485     private NotificationChannel findChannel(List<NotificationChannel> channels, String id) {
486         for (NotificationChannel channel : channels) {
487             if (channel.getId().equals(id)) {
488                 return channel;
489             }
490         }
491         return null;
492     }
493 
resetZenModeHelper()494     private void resetZenModeHelper() {
495         reset(mMockZenModeHelper);
496         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
497     }
498 
setUpPackageWithUid(String packageName, int uid)499     private void setUpPackageWithUid(String packageName, int uid) throws Exception {
500         when(mPm.getApplicationInfoAsUser(eq(packageName), anyInt(), anyInt()))
501                 .thenReturn(new ApplicationInfo());
502         when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
503     }
504 
testThreadSafety(Runnable operationToTest, int nThreads, int nRunsPerThread)505     private static void testThreadSafety(Runnable operationToTest, int nThreads,
506             int nRunsPerThread) throws Exception {
507         final CountDownLatch startLatch = new CountDownLatch(1);
508         final CountDownLatch doneLatch = new CountDownLatch(nThreads);
509 
510         for (int i = 0; i < nThreads; i++) {
511             Runnable threadRunnable = () -> {
512                 try {
513                     startLatch.await();
514                     for (int j = 0; j < nRunsPerThread; j++) {
515                         operationToTest.run();
516                     }
517                 } catch (InterruptedException e) {
518                     e.printStackTrace();
519                 } finally {
520                     doneLatch.countDown();
521                 }
522             };
523             new Thread(threadRunnable, "Test Thread #" + i).start();
524         }
525 
526         // Ready set go
527         startLatch.countDown();
528 
529         // Wait for all test threads to be done.
530         doneLatch.await();
531     }
532 
cloneChannel(NotificationChannel original)533     private static NotificationChannel cloneChannel(NotificationChannel original) {
534         Parcel parcel = Parcel.obtain();
535         try {
536             original.writeToParcel(parcel, 0);
537             parcel.setDataPosition(0);
538             return NotificationChannel.CREATOR.createFromParcel(parcel);
539         } finally {
540             parcel.recycle();
541         }
542     }
543 
544     @Test
testWriteXml_onlyBackupsTargetUser()545     public void testWriteXml_onlyBackupsTargetUser() throws Exception {
546         // Setup package notifications.
547         String package0 = "test.package.user0";
548         int uid0 = 1001;
549         setUpPackageWithUid(package0, uid0);
550         NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
551         assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false,
552                 uid0, false));
553 
554         String package10 = "test.package.user10";
555         int uid10 = 1001001;
556         setUpPackageWithUid(package10, uid10);
557         NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH);
558         assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false,
559                 uid10, false));
560 
561         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
562         appPermissions.put(new Pair<>(uid0, package0), new Pair<>(false, false));
563         appPermissions.put(new Pair<>(uid10, package10), new Pair<>(true, false));
564 
565         when(mPermissionHelper.getNotificationPermissionValues(10))
566                 .thenReturn(appPermissions);
567 
568         ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10);
569 
570         // Reset state.
571         mHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0});
572         mHelper.onPackagesChanged(true, 10, new String[] {package10}, new int[] {uid10});
573 
574         // Parse backup data.
575         loadStreamXml(baos, true, 0);
576         loadStreamXml(baos, true, 10);
577 
578         assertEquals(channel10,
579                 mXmlHelper.getNotificationChannel(package10, uid10, channel10.getId(), false));
580         assertNull(mXmlHelper.getNotificationChannel(package0, uid0, channel0.getId(), false));
581     }
582 
583     @Test
testReadXml_onlyRestoresTargetUser()584     public void testReadXml_onlyRestoresTargetUser() throws Exception {
585         // Setup package in user 0.
586         String package0 = "test.package.user0";
587         int uid0 = 1001;
588         setUpPackageWithUid(package0, uid0);
589         NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
590         assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false,
591                 uid0, false));
592 
593         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
594         appPermissions.put(new Pair<>(uid0, package0), new Pair<>(true, false));
595 
596         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
597                 .thenReturn(appPermissions);
598 
599         ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0);
600 
601         // Reset state.
602         mXmlHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0});
603 
604         // Restore should convert the uid according to the target user.
605         int expectedUid = 1001001;
606         setUpPackageWithUid(package0, expectedUid);
607         // Parse backup data.
608         loadStreamXml(baos, true, 10);
609 
610         assertEquals(channel0,
611                 mXmlHelper.getNotificationChannel(package0, expectedUid, channel0.getId(), false));
612         assertNull(mXmlHelper.getNotificationChannel(package0, uid0, channel0.getId(), false));
613     }
614 
615     @Test
testChannelXml()616     public void testChannelXml() throws Exception {
617         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
618         ncg.setBlocked(true);
619         ncg.setDescription("group desc");
620         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
621         NotificationChannel channel1 =
622                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
623         NotificationChannel channel2 =
624                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
625         channel2.setDescription("descriptions for all");
626         channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
627         channel2.enableLights(true);
628         channel2.setBypassDnd(true);
629         channel2.setLockscreenVisibility(VISIBILITY_SECRET);
630         channel2.enableVibration(true);
631         channel2.setGroup(ncg.getId());
632         channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
633         channel2.setLightColor(Color.BLUE);
634         channel2.setConversationId("id1", "conversation");
635         channel2.setDemoted(true);
636 
637         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
638                 UID_N_MR1, false);
639         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
640                 UID_N_MR1, false);
641         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
642                 UID_N_MR1, false));
643         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
644                 UID_N_MR1, false));
645 
646         NotificationChannel updateNews = null;
647         if (notificationClassification()) {
648             mHelper.createReservedChannel(PKG_N_MR1, UID_N_MR1, TYPE_NEWS);
649             // change one of the reserved bundle channels to ensure changes are persisted across
650             // boot
651             updateNews = mHelper.getNotificationChannel(
652                     PKG_N_MR1, UID_N_MR1, NEWS_ID, false).copy();
653             updateNews.setImportance(IMPORTANCE_NONE);
654             mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, updateNews, true, 1000, true);
655         }
656 
657         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
658         if (android.app.Flags.uiRichOngoing()) {
659             mHelper.setCanBePromoted(PKG_N_MR1, UID_N_MR1, true, true);
660         }
661 
662         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
663                 UserHandle.USER_ALL, channel1.getId(), channel2.getId(),
664                 NotificationChannel.DEFAULT_CHANNEL_ID);
665         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
666                 UID_N_MR1});
667 
668         loadStreamXml(baos, false, UserHandle.USER_ALL);
669 
670         assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
671         if (android.app.Flags.uiRichOngoing()) {
672             assertThat(mXmlHelper.canBePromoted(PKG_N_MR1, UID_N_MR1)).isTrue();
673             assertThat(mXmlHelper.getAppLockedFields(PKG_N_MR1, UID_N_MR1) & USER_LOCKED_PROMOTABLE)
674                     .isNotEqualTo(0);
675         }
676         assertEquals(channel1,
677                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
678         compareChannels(channel2,
679                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
680         if (notificationClassification()) {
681             assertThat(mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, updateNews.getId(),
682                     false)).isNotNull();
683             assertThat(mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, updateNews.getId(),
684                             false)).isEqualTo(updateNews);
685         }
686 
687         List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups(
688                 PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList();
689         boolean foundNcg = false;
690         for (NotificationChannelGroup actual : actualGroups) {
691             if (ncg.getId().equals(actual.getId())) {
692                 foundNcg = true;
693                 compareGroups(ncg, actual);
694             } else if (ncg2.getId().equals(actual.getId())) {
695                 compareGroups(ncg2, actual);
696             }
697         }
698         assertTrue(foundNcg);
699 
700         boolean foundChannel2Group = false;
701         for (NotificationChannelGroup actual : actualGroups) {
702             if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
703                 foundChannel2Group = true;
704                 break;
705             }
706         }
707         assertTrue(foundChannel2Group);
708     }
709 
710     @Test
testChannelXmlForBackup()711     public void testChannelXmlForBackup() throws Exception {
712         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
713         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
714         NotificationChannel channel1 =
715                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
716         NotificationChannel channel2 =
717                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
718         channel2.setDescription("descriptions for all");
719         channel2.setSound(CANONICAL_SOUND_URI, mAudioAttributes);
720         channel2.enableLights(true);
721         channel2.setBypassDnd(true);
722         channel2.setLockscreenVisibility(VISIBILITY_SECRET);
723         channel2.enableVibration(false);
724         channel2.setGroup(ncg.getId());
725         channel2.setLightColor(Color.BLUE);
726         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
727         channel3.enableVibration(true);
728 
729         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
730                 UID_N_MR1, false);
731         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
732                 UID_N_MR1, false);
733         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
734                 UID_N_MR1, false);
735         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
736                 SYSTEM_UID, true);
737         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false,
738                 SYSTEM_UID, true);
739         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
740                 UID_N_MR1, false);
741 
742         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
743         mHelper.setInvalidMessageSent(PKG_P, UID_P);
744         mHelper.setValidMessageSent(PKG_P, UID_P);
745         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
746         mHelper.setValidBubbleSent(PKG_P, UID_P);
747 
748         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
749                 USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
750                 NotificationChannel.DEFAULT_CHANNEL_ID);
751         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1, PKG_O},
752                 new int[]{UID_N_MR1, UID_O});
753 
754         mHelper.setShowBadge(PKG_O, UID_O, true);
755 
756         loadStreamXml(baos, true, USER_SYSTEM);
757 
758         assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
759         assertTrue(mXmlHelper.hasSentInvalidMsg(PKG_P, UID_P));
760         assertFalse(mXmlHelper.hasSentInvalidMsg(PKG_N_MR1, UID_N_MR1));
761         assertTrue(mXmlHelper.hasSentValidMsg(PKG_P, UID_P));
762         assertTrue(mXmlHelper.didUserEverDemoteInvalidMsgApp(PKG_P, UID_P));
763         assertTrue(mXmlHelper.hasSentValidBubble(PKG_P, UID_P));
764         assertEquals(channel1,
765                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
766         compareChannels(channel2,
767                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
768         compareChannels(channel3,
769                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
770 
771         List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups(
772                 PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList();
773         boolean foundNcg = false;
774         for (NotificationChannelGroup actual : actualGroups) {
775             if (ncg.getId().equals(actual.getId())) {
776                 foundNcg = true;
777                 compareGroups(ncg, actual);
778             } else if (ncg2.getId().equals(actual.getId())) {
779                 compareGroups(ncg2, actual);
780             }
781         }
782         assertTrue(foundNcg);
783 
784         boolean foundChannel2Group = false;
785         for (NotificationChannelGroup actual : actualGroups) {
786             if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
787                 foundChannel2Group = true;
788                 break;
789             }
790         }
791         assertTrue(foundChannel2Group);
792     }
793 
794     @Test
testReadXml_oldXml_migrates()795     public void testReadXml_oldXml_migrates() throws Exception {
796         mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
797                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
798                 mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock);
799 
800         String xml = "<ranking version=\"2\">\n"
801                 + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1
802                 + "\" show_badge=\"true\">\n"
803                 + "<channel id=\"idn\" name=\"name\" importance=\"2\" />\n"
804                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
805                 + "</package>\n"
806                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" importance=\"0\">\n"
807                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
808                 + "</package>\n"
809                 + "<package name=\"" + PKG_P + "\" uid=\"" + UID_P + "\" importance=\"2\">\n"
810                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
811                 + "</package>\n"
812                 + "</ranking>\n";
813 
814         loadByteArrayXml(xml.getBytes(), false, USER_SYSTEM);
815 
816         // expected values
817         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
818         idn.setSound(null, new AudioAttributes.Builder()
819                 .setUsage(USAGE_NOTIFICATION)
820                 .setContentType(CONTENT_TYPE_SONIFICATION)
821                 .setFlags(0)
822                 .build());
823         idn.setShowBadge(false);
824         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
825         ido.setShowBadge(true);
826         ido.setSound(null, new AudioAttributes.Builder()
827                 .setUsage(USAGE_NOTIFICATION)
828                 .setContentType(CONTENT_TYPE_SONIFICATION)
829                 .setFlags(0)
830                 .build());
831         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
832         idp.lockFields(2);
833         idp.setSound(null, new AudioAttributes.Builder()
834                 .setUsage(USAGE_NOTIFICATION)
835                 .setContentType(CONTENT_TYPE_SONIFICATION)
836                 .setFlags(0)
837                 .build());
838 
839         // verify data
840         assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
841 
842         assertEquals(idn,
843                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
844         compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
845         compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
846 
847         // verify that we also write a state for review_permissions_notification to eventually
848         // show a notification
849         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW,
850                 Settings.Global.getInt(mContext.getContentResolver(),
851                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
852                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
853     }
854 
855     @Test
testReadXml_oldXml_backup_migratesWhenPkgInstalled()856     public void testReadXml_oldXml_backup_migratesWhenPkgInstalled() throws Exception {
857         when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
858         when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
859         when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
860         when(mPm.getApplicationInfoAsUser(eq("pkg1"), anyInt(), anyInt())).thenThrow(
861                 new PackageManager.NameNotFoundException());
862         when(mPm.getApplicationInfoAsUser(eq("pkg2"), anyInt(), anyInt())).thenThrow(
863                 new PackageManager.NameNotFoundException());
864         when(mPm.getApplicationInfoAsUser(eq("pkg3"), anyInt(), anyInt())).thenThrow(
865                 new PackageManager.NameNotFoundException());
866 
867         String xml = "<ranking version=\"2\">\n"
868                 + "<package name=\"pkg1\" show_badge=\"true\">\n"
869                 + "<channel id=\"idn\" name=\"name\" importance=\"2\" />\n"
870                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
871                 + "</package>\n"
872                 + "<package name=\"pkg2\" importance=\"0\">\n"
873                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
874                 + "</package>\n"
875                 + "<package name=\"pkg3\" importance=\"2\">\n"
876                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
877                 + "</package>\n"
878                 + "</ranking>\n";
879         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
880         idn.setSound(null, new AudioAttributes.Builder()
881                 .setUsage(USAGE_NOTIFICATION)
882                 .setContentType(CONTENT_TYPE_SONIFICATION)
883                 .setFlags(0)
884                 .build());
885         idn.setShowBadge(false);
886         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
887         ido.setShowBadge(true);
888         ido.setSound(null, new AudioAttributes.Builder()
889                 .setUsage(USAGE_NOTIFICATION)
890                 .setContentType(CONTENT_TYPE_SONIFICATION)
891                 .setFlags(0)
892                 .build());
893         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
894         idp.lockFields(2);
895         idp.setSound(null, new AudioAttributes.Builder()
896                 .setUsage(USAGE_NOTIFICATION)
897                 .setContentType(CONTENT_TYPE_SONIFICATION)
898                 .setFlags(0)
899                 .build());
900 
901         // Notifications enabled, not user set
902         PackagePermission pkg1Expected = new PackagePermission("pkg1", 0, true, false);
903         // Notifications not enabled, so user set
904         PackagePermission pkg2Expected = new PackagePermission("pkg2", 0, false, true);
905         // Notifications enabled, user set b/c channel modified
906         PackagePermission pkg3Expected = new PackagePermission("pkg3", 0, true, true);
907 
908         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
909 
910         verify(mPermissionHelper, never()).setNotificationPermission(any());
911 
912         when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(11);
913         when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(12);
914         when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(13);
915 
916         mXmlHelper.onPackagesChanged(
917                 false, 0, new String[]{"pkg1", "pkg2", "pkg3"}, new int[] {11, 12, 13});
918 
919         assertTrue(mXmlHelper.canShowBadge("pkg1", 11));
920 
921         assertEquals(idn, mXmlHelper.getNotificationChannel("pkg1", 11, idn.getId(), false));
922         compareChannels(ido, mXmlHelper.getNotificationChannel("pkg2", 12, ido.getId(), false));
923         compareChannels(idp, mXmlHelper.getNotificationChannel("pkg3", 13, idp.getId(), false));
924 
925         verify(mPermissionHelper).setNotificationPermission(pkg1Expected);
926         verify(mPermissionHelper).setNotificationPermission(pkg2Expected);
927         verify(mPermissionHelper).setNotificationPermission(pkg3Expected);
928     }
929 
930     @Test
testReadXml_newXml_noMigration_showPermissionNotification()931     public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
932         mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
933                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
934                 mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock);
935 
936         String xml = "<ranking version=\"3\">\n"
937                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
938                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
939                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
940                 + "</package>\n"
941                 + "<package name=\"" + PKG_O + "\" >\n"
942                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
943                 + "</package>\n"
944                 + "<package name=\"" + PKG_P + "\" >\n"
945                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
946                 + "</package>\n"
947                 + "</ranking>\n";
948         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
949         idn.setSound(null, new AudioAttributes.Builder()
950                 .setUsage(USAGE_NOTIFICATION)
951                 .setContentType(CONTENT_TYPE_SONIFICATION)
952                 .setFlags(0)
953                 .build());
954         idn.setShowBadge(false);
955         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
956         ido.setShowBadge(true);
957         ido.setSound(null, new AudioAttributes.Builder()
958                 .setUsage(USAGE_NOTIFICATION)
959                 .setContentType(CONTENT_TYPE_SONIFICATION)
960                 .setFlags(0)
961                 .build());
962         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
963         idp.lockFields(2);
964         idp.setSound(null, new AudioAttributes.Builder()
965                 .setUsage(USAGE_NOTIFICATION)
966                 .setContentType(CONTENT_TYPE_SONIFICATION)
967                 .setFlags(0)
968                 .build());
969 
970         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
971 
972         assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
973 
974         assertEquals(idn,
975                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
976         compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
977         compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
978 
979         verify(mPermissionHelper, never()).setNotificationPermission(any());
980 
981         // verify that we do, however, write a state for review_permissions_notification to
982         // eventually show a notification, since this XML version is older than the notification
983         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW,
984                 Settings.Global.getInt(mContext.getContentResolver(),
985                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
986                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
987     }
988 
989     @Test
testReadXml_newXml_permissionNotificationOff()990     public void testReadXml_newXml_permissionNotificationOff() throws Exception {
991         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
992                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
993                 mUgmInternal, /* showReviewPermissionsNotification= */ false, mClock);
994 
995         String xml = "<ranking version=\"3\">\n"
996                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
997                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
998                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
999                 + "</package>\n"
1000                 + "<package name=\"" + PKG_O + "\" >\n"
1001                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
1002                 + "</package>\n"
1003                 + "<package name=\"" + PKG_P + "\" >\n"
1004                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
1005                 + "</package>\n"
1006                 + "</ranking>\n";
1007         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
1008         idn.setSound(null, new AudioAttributes.Builder()
1009                 .setUsage(USAGE_NOTIFICATION)
1010                 .setContentType(CONTENT_TYPE_SONIFICATION)
1011                 .setFlags(0)
1012                 .build());
1013         idn.setShowBadge(false);
1014         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
1015         ido.setShowBadge(true);
1016         ido.setSound(null, new AudioAttributes.Builder()
1017                 .setUsage(USAGE_NOTIFICATION)
1018                 .setContentType(CONTENT_TYPE_SONIFICATION)
1019                 .setFlags(0)
1020                 .build());
1021         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
1022         idp.lockFields(2);
1023         idp.setSound(null, new AudioAttributes.Builder()
1024                 .setUsage(USAGE_NOTIFICATION)
1025                 .setContentType(CONTENT_TYPE_SONIFICATION)
1026                 .setFlags(0)
1027                 .build());
1028 
1029         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1030 
1031         assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
1032 
1033         assertEquals(idn,
1034                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
1035         compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
1036         compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
1037 
1038         verify(mPermissionHelper, never()).setNotificationPermission(any());
1039 
1040         // while this is the same case as above, if the permission helper is set to not show the
1041         // review permissions notification it should not write anything to the settings int
1042         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN,
1043                 Settings.Global.getInt(mContext.getContentResolver(),
1044                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
1045                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
1046     }
1047 
1048     @Test
testReadXml_newXml_noMigration_noPermissionNotification()1049     public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
1050         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1051                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
1052                 mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock);
1053 
1054         String xml = "<ranking version=\"4\">\n"
1055                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
1056                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
1057                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
1058                 + "</package>\n"
1059                 + "<package name=\"" + PKG_O + "\" >\n"
1060                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
1061                 + "</package>\n"
1062                 + "<package name=\"" + PKG_P + "\" >\n"
1063                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
1064                 + "</package>\n"
1065                 + "</ranking>\n";
1066         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
1067         idn.setSound(null, new AudioAttributes.Builder()
1068                 .setUsage(USAGE_NOTIFICATION)
1069                 .setContentType(CONTENT_TYPE_SONIFICATION)
1070                 .setFlags(0)
1071                 .build());
1072         idn.setShowBadge(false);
1073         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
1074         ido.setShowBadge(true);
1075         ido.setSound(null, new AudioAttributes.Builder()
1076                 .setUsage(USAGE_NOTIFICATION)
1077                 .setContentType(CONTENT_TYPE_SONIFICATION)
1078                 .setFlags(0)
1079                 .build());
1080         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
1081         idp.lockFields(2);
1082         idp.setSound(null, new AudioAttributes.Builder()
1083                 .setUsage(USAGE_NOTIFICATION)
1084                 .setContentType(CONTENT_TYPE_SONIFICATION)
1085                 .setFlags(0)
1086                 .build());
1087 
1088         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1089 
1090         assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
1091 
1092         assertEquals(idn,
1093                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
1094         compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
1095         compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
1096 
1097         verify(mPermissionHelper, never()).setNotificationPermission(any());
1098 
1099         // this XML is new enough, we should not be attempting to show a notification or anything
1100         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN,
1101                 Settings.Global.getInt(mContext.getContentResolver(),
1102                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
1103                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
1104     }
1105 
1106     @Test
testReadXml_oldXml_migration_NoUid()1107     public void testReadXml_oldXml_migration_NoUid() throws Exception {
1108         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1109         String xml = "<ranking version=\"2\">\n"
1110                 + "<package name=\"something\" show_badge=\"true\">\n"
1111                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
1112                 + "</package>\n"
1113                 + "</ranking>\n";
1114         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
1115         idn.setSound(null, new AudioAttributes.Builder()
1116                 .setUsage(USAGE_NOTIFICATION)
1117                 .setContentType(CONTENT_TYPE_SONIFICATION)
1118                 .setFlags(0)
1119                 .build());
1120         idn.setShowBadge(false);
1121 
1122         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1123         verify(mPermissionHelper, never()).setNotificationPermission(any());
1124 
1125         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234);
1126         final ApplicationInfo app = new ApplicationInfo();
1127         app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
1128         when(mPm.getApplicationInfoAsUser(
1129                 eq("something"), anyInt(), eq(USER_SYSTEM))).thenReturn(app);
1130 
1131         mXmlHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234});
1132 
1133         verify(mPermissionHelper, times(1)).setNotificationPermission(any());
1134     }
1135 
1136     @Test
testReadXml_newXml_noMigration_NoUid()1137     public void testReadXml_newXml_noMigration_NoUid() throws Exception {
1138         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1139         String xml = "<ranking version=\"3\">\n"
1140                 + "<package name=\"something\" show_badge=\"true\">\n"
1141                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
1142                 + "</package>\n"
1143                 + "</ranking>\n";
1144         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
1145         idn.setSound(null, new AudioAttributes.Builder()
1146                 .setUsage(USAGE_NOTIFICATION)
1147                 .setContentType(CONTENT_TYPE_SONIFICATION)
1148                 .setFlags(0)
1149                 .build());
1150         idn.setShowBadge(false);
1151 
1152         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1153 
1154         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234);
1155         final ApplicationInfo app = new ApplicationInfo();
1156         app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
1157         when(mPm.getApplicationInfoAsUser(eq("something"), anyInt(), anyInt())).thenReturn(app);
1158 
1159         mXmlHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234});
1160 
1161         verify(mPermissionHelper, never()).setNotificationPermission(any());
1162     }
1163 
1164     @Test
testChannelXmlForNonBackup_postMigration()1165     public void testChannelXmlForNonBackup_postMigration() throws Exception {
1166         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1167         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
1168         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false));
1169         appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
1170         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false));
1171         appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
1172 
1173         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1174                 .thenReturn(appPermissions);
1175 
1176         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1177         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1178         NotificationChannel channel1 =
1179                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1180         channel1.setSound(null, null);
1181         NotificationChannel channel2 =
1182                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1183         channel2.setDescription("descriptions for all");
1184         channel2.setSound(null, null);
1185         channel2.enableLights(true);
1186         channel2.setBypassDnd(true);
1187         channel2.setLockscreenVisibility(VISIBILITY_SECRET);
1188         channel2.enableVibration(false);
1189         channel2.setGroup(ncg.getId());
1190         channel2.setLightColor(Color.BLUE);
1191         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
1192         channel3.enableVibration(true);
1193 
1194         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
1195                 UID_N_MR1, false);
1196         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
1197                 UID_N_MR1, false);
1198         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
1199                 UID_N_MR1, false);
1200         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
1201                 SYSTEM_UID, true);
1202         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false,
1203                 SYSTEM_UID, true);
1204         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
1205                 UID_N_MR1, false);
1206 
1207         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
1208         mHelper.setInvalidMessageSent(PKG_P, UID_P);
1209         mHelper.setValidMessageSent(PKG_P, UID_P);
1210         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
1211 
1212         ByteArrayOutputStream baos = writeXmlAndPurge(
1213                 PKG_N_MR1, UID_N_MR1, false, USER_SYSTEM);
1214         String expected = "<ranking version=\"4\">\n"
1215                 + "<package name=\"com.example.o\" show_badge=\"true\" "
1216                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1217                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
1218                 + "=\"false\" uid=\"10002\">\n"
1219                 + "<channel id=\"id\" name=\"name\" importance=\"2\" "
1220                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1221                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
1222                 + "</package>\n"
1223                 + "<package name=\"com.example.n_mr1\" show_badge=\"true\" "
1224                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1225                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
1226                 + "=\"false\" uid=\"10001\">\n"
1227                 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
1228                 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
1229                 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
1230                 + "orig_imp=\"4\" />\n"
1231                 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
1232                 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" "
1233                 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n"
1234                 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" "
1235                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1236                 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
1237                 + "orig_imp=\"4\" />\n"
1238                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
1239                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1240                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1241                 + "</package>\n"
1242                 + "<package name=\"com.example.p\" show_badge=\"true\" "
1243                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
1244                 + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" uid=\"10003\"";
1245         assertThat(baos.toString()).contains(expected);
1246     }
1247 
1248     @Test
testChannelXmlForBackup_postMigration()1249     public void testChannelXmlForBackup_postMigration() throws Exception {
1250         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1251         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
1252         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false));
1253         appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
1254         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false));
1255         appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
1256 
1257         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1258                 .thenReturn(appPermissions);
1259 
1260         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1261         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1262         NotificationChannel channel1 =
1263                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1264         channel1.setSound(null, null);
1265         NotificationChannel channel2 =
1266                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1267         channel2.setDescription("descriptions for all");
1268         channel2.setSound(null, null);
1269         channel2.enableLights(true);
1270         channel2.setBypassDnd(true);
1271         channel2.setLockscreenVisibility(VISIBILITY_SECRET);
1272         channel2.enableVibration(false);
1273         channel2.setGroup(ncg.getId());
1274         channel2.setLightColor(Color.BLUE);
1275         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
1276         channel3.enableVibration(true);
1277 
1278         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
1279                 UID_N_MR1, false);
1280         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
1281                 UID_N_MR1, false);
1282         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
1283                 UID_N_MR1, false);
1284         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
1285                 SYSTEM_UID, true);
1286         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false,
1287                 SYSTEM_UID, true);
1288         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
1289                 UID_N_MR1, false);
1290 
1291         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
1292         mHelper.setInvalidMessageSent(PKG_P, UID_P);
1293         mHelper.setValidMessageSent(PKG_P, UID_P);
1294         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
1295 
1296         ByteArrayOutputStream baos = writeXmlAndPurge(
1297                 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM);
1298         String expected = "<ranking version=\"4\">\n"
1299                 // Importance 0 because off in permissionhelper
1300                 + "<package name=\"com.example.o\" importance=\"0\" show_badge=\"true\" "
1301                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1302                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
1303                 + "=\"false\">\n"
1304                 + "<channel id=\"id\" name=\"name\" importance=\"2\" "
1305                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1306                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
1307                 + "</package>\n"
1308                 // Importance default because on in permission helper
1309                 + "<package name=\"com.example.n_mr1\" importance=\"3\" show_badge=\"true\" "
1310                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1311                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
1312                 + "=\"false\">\n"
1313                 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
1314                 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
1315                 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
1316                 + "orig_imp=\"4\" />\n"
1317                 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
1318                 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" "
1319                 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n"
1320                 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" "
1321                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1322                 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
1323                 + "orig_imp=\"4\" />\n"
1324                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
1325                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1326                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1327                 + "</package>\n"
1328                 // Importance default because on in permission helper
1329                 + "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" "
1330                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
1331                 + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\"";
1332         assertThat(baos.toString()).contains(expected);
1333         // Packages that exist solely in permissionhelper
1334         assertThat(baos.toString()).contains("<package name=\"first\" importance=\"3\"");
1335         assertThat(baos.toString()).contains("<package name=\"third\" importance=\"0\"");
1336     }
1337 
1338     @Test
testChannelXmlForBackup_postMigration_noExternal()1339     public void testChannelXmlForBackup_postMigration_noExternal() throws Exception {
1340         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1341         appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
1342         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false));
1343         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1344                 .thenReturn(appPermissions);
1345 
1346         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1347         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1348         NotificationChannel channel1 =
1349                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1350         channel1.setSound(null, null);
1351         NotificationChannel channel2 =
1352                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1353         channel2.setDescription("descriptions for all");
1354         channel2.setSound(null, null);
1355         channel2.enableLights(true);
1356         channel2.setBypassDnd(true);
1357         channel2.setLockscreenVisibility(VISIBILITY_SECRET);
1358         channel2.enableVibration(false);
1359         channel2.setGroup(ncg.getId());
1360         channel2.setLightColor(Color.BLUE);
1361         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
1362         channel3.enableVibration(true);
1363 
1364         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
1365                 UID_N_MR1, false);
1366         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
1367                 UID_N_MR1, false);
1368         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
1369                 UID_N_MR1, false);
1370         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
1371                 SYSTEM_UID, true);
1372         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false,
1373                 SYSTEM_UID, true);
1374         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
1375                 UID_N_MR1, false);
1376 
1377         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
1378         mHelper.setInvalidMessageSent(PKG_P, UID_P);
1379         mHelper.setValidMessageSent(PKG_P, UID_P);
1380         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
1381 
1382         ByteArrayOutputStream baos = writeXmlAndPurge(
1383                 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM);
1384         String expected = "<ranking version=\"4\">\n"
1385                 // Importance 0 because off in permissionhelper
1386                 + "<package name=\"com.example.o\" importance=\"0\" show_badge=\"true\" "
1387                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1388                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
1389                 + "=\"false\">\n"
1390                 + "<channel id=\"id\" name=\"name\" importance=\"2\" "
1391                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1392                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
1393                 + "</package>\n"
1394                 // Importance 0 because missing from permission helper
1395                 + "<package name=\"com.example.n_mr1\" importance=\"0\" show_badge=\"true\" "
1396                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1397                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
1398                 + "=\"false\">\n"
1399                 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
1400                 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
1401                 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
1402                 + "orig_imp=\"4\" />\n"
1403                 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
1404                 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" "
1405                 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n"
1406                 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" "
1407                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1408                 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
1409                 + "orig_imp=\"4\" />\n"
1410                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
1411                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1412                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1413                 + "</package>\n"
1414                 // Importance default because on in permission helper
1415                 + "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" "
1416                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
1417                 + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\"";
1418         assertThat(baos.toString()).contains(expected);
1419     }
1420 
1421     @Test
testChannelXmlForBackup_postMigration_noLocalSettings()1422     public void testChannelXmlForBackup_postMigration_noLocalSettings() throws Exception {
1423         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1424         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
1425         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false));
1426         appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
1427         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false));
1428         appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
1429 
1430         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1431                 .thenReturn(appPermissions);
1432 
1433         ByteArrayOutputStream baos = writeXmlAndPurge(
1434                 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM);
1435         String expected = "<ranking version=\"4\">\n"
1436                 // Packages that exist solely in permissionhelper
1437                 + "<package name=\"" + PKG_P + "\" importance=\"3\" />\n"
1438                 + "<package name=\"" + PKG_O + "\" importance=\"0\" />\n"
1439                 + "<package name=\"" + PKG_N_MR1 + "\" importance=\"3\" />\n"
1440                 + "<package name=\"first\" importance=\"3\" />\n"
1441                 + "<package name=\"third\" importance=\"0\" />\n"
1442                 + "</ranking>";
1443         assertThat(baos.toString()).contains(expected);
1444     }
1445 
1446     @Test
testBackupXml_backupCanonicalizedSoundUri()1447     public void testBackupXml_backupCanonicalizedSoundUri() throws Exception {
1448         NotificationChannel channel =
1449                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1450         channel.setSound(SOUND_URI, mAudioAttributes);
1451         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1452                 UID_N_MR1, false);
1453 
1454         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1455                 USER_SYSTEM, channel.getId());
1456 
1457         // Testing that in restore we are given the canonical version
1458         loadStreamXml(baos, true, USER_SYSTEM);
1459         verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
1460     }
1461 
1462     @Test
testRestoreXml_withExistentCanonicalizedSoundUri()1463     public void testRestoreXml_withExistentCanonicalizedSoundUri() throws Exception {
1464         Uri localUri = Uri.parse("content://" + TEST_AUTHORITY + "/local/url");
1465         Uri canonicalBasedOnLocal = localUri.buildUpon()
1466                 .appendQueryParameter("title", "Test")
1467                 .appendQueryParameter("canonical", "1")
1468                 .build();
1469         doReturn(canonicalBasedOnLocal)
1470                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
1471         doReturn(localUri)
1472                 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
1473         doReturn(localUri)
1474                 .when(mTestIContentProvider).uncanonicalize(any(), eq(canonicalBasedOnLocal));
1475         doReturn(canonicalBasedOnLocal)
1476                 .when(mTestIContentProvider).canonicalize(any(), eq(localUri));
1477 
1478         NotificationChannel channel =
1479                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1480         channel.setSound(SOUND_URI, mAudioAttributes);
1481         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1482                 UID_N_MR1, false);
1483         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1484                 USER_SYSTEM, channel.getId());
1485 
1486         loadStreamXml(baos, true, USER_SYSTEM);
1487 
1488         NotificationChannel actualChannel = mXmlHelper.getNotificationChannel(
1489                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1490         assertEquals(canonicalBasedOnLocal, actualChannel.getSound());
1491     }
1492 
1493     @Test
testRestoreXml_withNonExistentCanonicalizedSoundUri()1494     public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
1495         Thread.sleep(3000);
1496         doReturn(null)
1497                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
1498         doReturn(null)
1499                 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
1500 
1501         NotificationChannel channel =
1502                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1503         channel.setSound(SOUND_URI, mAudioAttributes);
1504         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1505                 UID_N_MR1, false);
1506         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1507                 USER_SYSTEM, channel.getId());
1508 
1509         loadStreamXml(baos, true, USER_SYSTEM);
1510 
1511         NotificationChannel actualChannel = mXmlHelper.getNotificationChannel(
1512                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1513         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
1514     }
1515 
1516     /**
1517      * Test sound Uri restore retry behavior when channel is restored before package
1518      *  and then package is installed.
1519      */
1520     @Test
testRestoreXml_withNonExistentCanonicalizedSoundUriAndMissingPackage()1521     public void testRestoreXml_withNonExistentCanonicalizedSoundUriAndMissingPackage()
1522             throws Exception {
1523         // canonicalization returns CANONICAL_SOUND_URI for getSoundForBackup (backup part)
1524         doReturn(CANONICAL_SOUND_URI)
1525                 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
1526 
1527         NotificationChannel channel =
1528                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1529         channel.setSound(SOUND_URI, mAudioAttributes);
1530         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1531                 UID_N_MR1, false);
1532         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1533                 USER_SYSTEM, channel.getId());
1534 
1535         // canonicalization / uncanonicalization returns null for the restore part
1536         doReturn(null)
1537                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
1538         doReturn(null)
1539                 .when(mTestIContentProvider).uncanonicalize(any(), any());
1540 
1541         // simulate package not installed
1542         when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1543         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenThrow(
1544                 new PackageManager.NameNotFoundException());
1545 
1546         loadStreamXml(baos, true, USER_SYSTEM);
1547 
1548         // 1st restore pass fails
1549         NotificationChannel actualChannel = mXmlHelper.getNotificationChannel(
1550                 PKG_N_MR1, UNKNOWN_UID, channel.getId(), false);
1551         // sound is CANONICAL_SOUND_URI, unchanged from backup
1552         assertEquals(CANONICAL_SOUND_URI, actualChannel.getSound());
1553         // sound is flagged as not restored
1554         assertFalse(actualChannel.isSoundRestored());
1555 
1556         // package is "installed"
1557         when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UID_N_MR1);
1558 
1559         // Trigger 2nd restore pass
1560         mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1},
1561                 new int[]{UID_N_MR1});
1562 
1563         // sound is flagged as restored and set to default URI
1564         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
1565         assertTrue(actualChannel.isSoundRestored());
1566     }
1567 
1568     @Test
1569     @EnableFlags(Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA)
testRestoreXml_delayedRestore()1570     public void testRestoreXml_delayedRestore() throws Exception {
1571         // simulate package not installed
1572         when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1573         when(mPm.getApplicationInfoAsUser(eq(PKG_R), anyInt(), anyInt())).thenThrow(
1574                 new PackageManager.NameNotFoundException());
1575         when(mClock.millis()).thenReturn(System.currentTimeMillis());
1576 
1577         String id = "id";
1578         String xml = "<ranking version=\"1\">\n"
1579                 + "<package name=\"" + PKG_R + "\" show_badge=\"true\">\n"
1580                 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
1581                 + "show_badge=\"true\" />\n"
1582                 + "</package>\n"
1583                 + "</ranking>\n";
1584 
1585         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1586 
1587         // settings are not available with real uid because pkg is not installed
1588         assertThat(mXmlHelper.getNotificationChannel(PKG_R, UID_P, id, false)).isNull();
1589         // but the settings are in memory with unknown_uid
1590         assertThat(mXmlHelper.getNotificationChannel(PKG_R, UNKNOWN_UID, id, false)).isNotNull();
1591 
1592         // package is "installed"
1593         when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UID_P);
1594 
1595         // Trigger 2nd restore pass
1596         mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_R},
1597                 new int[]{UID_P});
1598 
1599         NotificationChannel channel = mXmlHelper.getNotificationChannel(PKG_R, UID_P, id,
1600                 false);
1601         assertThat(channel.getImportance()).isEqualTo(2);
1602         assertThat(channel.canShowBadge()).isTrue();
1603         assertThat(channel.canBypassDnd()).isFalse();
1604 
1605         // removed from 'pending install' set
1606         assertThat(mXmlHelper.getNotificationChannel(PKG_R, UNKNOWN_UID, id,false)).isNull();
1607     }
1608 
1609     @Test
1610     @EnableFlags(Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA)
testRestoreXml_delayedRestore_afterReboot()1611     public void testRestoreXml_delayedRestore_afterReboot() throws Exception {
1612         // load restore data
1613         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1614         appPermissions.put(new Pair<>(UID_R, PKG_R), new Pair<>(true, false));
1615         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1616                 .thenReturn(appPermissions);
1617 
1618         // simulate package not installed
1619         when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1620         when(mPm.getApplicationInfoAsUser(eq(PKG_R), anyInt(), anyInt())).thenThrow(
1621                 new PackageManager.NameNotFoundException());
1622         when(mClock.millis()).thenReturn(System.currentTimeMillis());
1623 
1624         String id = "id";
1625         String xml = "<ranking version=\"1\">\n"
1626                 + "<package name=\"" + PKG_R + "\" show_badge=\"true\">\n"
1627                 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
1628                 + "show_badge=\"true\" />\n"
1629                 + "</package>\n"
1630                 + "</ranking>\n";
1631 
1632         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1633 
1634         // simulate write to disk
1635         TypedXmlSerializer serializer = Xml.newFastSerializer();
1636         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1637         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
1638         serializer.startDocument(null, true);
1639         mXmlHelper.writeXml(serializer, false, USER_SYSTEM);
1640         serializer.endDocument();
1641         serializer.flush();
1642 
1643         // simulate load after reboot
1644         mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1645                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
1646                 mUgmInternal, false, mClock);
1647         loadByteArrayXml(baos.toByteArray(), false, USER_ALL);
1648 
1649         // Trigger 2nd restore pass
1650         when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UID_R);
1651         mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_R},
1652                 new int[]{UID_R});
1653 
1654         NotificationChannel channel = mXmlHelper.getNotificationChannel(PKG_R, UID_R, id,
1655                 false);
1656         assertThat(channel.getImportance()).isEqualTo(2);
1657         assertThat(channel.canShowBadge()).isTrue();
1658         assertThat(channel.canBypassDnd()).isFalse();
1659     }
1660 
1661     @Test
1662     @EnableFlags(Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA)
testRestoreXml_delayedRestore_packageMissingAfterTwoDays()1663     public void testRestoreXml_delayedRestore_packageMissingAfterTwoDays() throws Exception {
1664         // load restore data
1665         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1666         appPermissions.put(new Pair<>(UID_R, PKG_R), new Pair<>(true, false));
1667         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1668                 .thenReturn(appPermissions);
1669 
1670         // simulate package not installed
1671         when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1672         when(mPm.getApplicationInfoAsUser(eq(PKG_R), anyInt(), anyInt())).thenThrow(
1673                 new PackageManager.NameNotFoundException());
1674 
1675         String id = "id";
1676         String xml = "<ranking version=\"1\">\n"
1677                 + "<package name=\"" + PKG_R + "\" show_badge=\"true\">\n"
1678                 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
1679                 + "show_badge=\"true\" />\n"
1680                 + "</package>\n"
1681                 + "</ranking>\n";
1682 
1683         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
1684 
1685         // simulate write to disk
1686         TypedXmlSerializer serializer = Xml.newFastSerializer();
1687         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1688         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
1689         serializer.startDocument(null, true);
1690         mXmlHelper.writeXml(serializer, false, USER_SYSTEM);
1691         serializer.endDocument();
1692         serializer.flush();
1693 
1694         // advance time by 2 days
1695         when(mClock.millis()).thenReturn(
1696                 Duration.ofDays(2).toMillis() + System.currentTimeMillis());
1697 
1698         // simulate load after reboot
1699         mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1700                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
1701                 mUgmInternal, false, mClock);
1702         loadByteArrayXml(xml.getBytes(), false, USER_ALL);
1703 
1704         // Trigger 2nd restore pass
1705         mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_R},
1706                 new int[]{UID_P});
1707 
1708         // verify the 2nd restore pass failed because the restore data had been removed
1709         assertThat(mXmlHelper.getNotificationChannel(PKG_R, UNKNOWN_UID, id, false)).isNull();
1710     }
1711 
1712     /**
1713      * Although we don't make backups with uncanonicalized uris anymore, we used to, so we have to
1714      * handle its restore properly.
1715      */
1716     @Test
testRestoreXml_withUncanonicalizedNonLocalSoundUri()1717     public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
1718         // Not a local uncanonicalized uri, simulating that it fails to exist locally
1719         doReturn(null)
1720                 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
1721         String id = "id";
1722         String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
1723                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
1724                 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
1725                 + "sound=\"" + SOUND_URI + "\" "
1726                 + "usage=\"6\" content_type=\"0\" flags=\"1\" show_badge=\"true\" />\n"
1727                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" "
1728                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1729                 + "</package>\n"
1730                 + "</ranking>\n";
1731 
1732         loadByteArrayXml(
1733                 backupWithUncanonicalizedSoundUri.getBytes(), true, USER_SYSTEM);
1734 
1735         NotificationChannel actualChannel =
1736                 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
1737 
1738         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
1739         assertTrue(actualChannel.isSoundRestored());
1740     }
1741 
1742     @Test
testBackupRestoreXml_withNullSoundUri()1743     public void testBackupRestoreXml_withNullSoundUri() throws Exception {
1744         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1745         appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
1746 
1747         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1748                 .thenReturn(appPermissions);
1749 
1750         NotificationChannel channel =
1751                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1752         channel.setSound(null, mAudioAttributes);
1753         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1754                 UID_N_MR1, false);
1755         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1756                 USER_SYSTEM, channel.getId());
1757 
1758         loadStreamXml(baos, true, USER_SYSTEM);
1759 
1760         NotificationChannel actualChannel = mXmlHelper.getNotificationChannel(
1761                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1762         assertEquals(null, actualChannel.getSound());
1763     }
1764 
1765     @Test
testBackupRestoreXml_withAndroidResourceSoundUri()1766     public void testBackupRestoreXml_withAndroidResourceSoundUri() throws Exception {
1767         // Mock ContentResolver.getResourceId:
1768         // throw exception on restore 1st pass => simulate app not installed yet
1769         // then return a valid resource on package update => sim. app installed
1770         ContentResolver contentResolver = mock(ContentResolver.class);
1771         when(mContext.getContentResolver()).thenReturn(contentResolver);
1772         ContentResolver.OpenResourceIdResult resId = mock(
1773                 ContentResolver.OpenResourceIdResult.class);
1774         when(contentResolver.getResourceId(ANDROID_RES_SOUND_URI)).thenReturn(resId).thenThrow(
1775                 new FileNotFoundException("")).thenReturn(resId);
1776 
1777         mHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
1778                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
1779                 mUgmInternal, false, mClock);
1780         mXmlHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
1781                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
1782                 mUgmInternal, false, mClock);
1783 
1784         NotificationChannel channel =
1785                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1786         channel.setSound(ANDROID_RES_SOUND_URI, mAudioAttributes);
1787         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1788                 UID_N_MR1, false);
1789         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1790                 USER_SYSTEM, channel.getId());
1791 
1792         // simulate package not installed
1793         when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
1794         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenThrow(
1795                 new PackageManager.NameNotFoundException());
1796 
1797         loadStreamXml(baos, true, USER_SYSTEM);
1798 
1799         NotificationChannel actualChannel = mXmlHelper.getNotificationChannel(
1800                 PKG_N_MR1, UNKNOWN_UID, channel.getId(), false);
1801         // sound is ANDROID_RES_SOUND_URI, unchanged from backup
1802         assertEquals(ANDROID_RES_SOUND_URI, actualChannel.getSound());
1803         // sound is flagged as not restored
1804         assertFalse(actualChannel.isSoundRestored());
1805 
1806         // package is "installed"
1807         when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UID_N_MR1);
1808 
1809         // Trigger 2nd restore pass
1810         mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1},
1811                 new int[]{UID_N_MR1});
1812 
1813         // sound is flagged as restored
1814         assertEquals(ANDROID_RES_SOUND_URI, actualChannel.getSound());
1815         assertTrue(actualChannel.isSoundRestored());
1816     }
1817 
1818     @Test
testBackupRestoreXml_withFileResourceSoundUri()1819     public void testBackupRestoreXml_withFileResourceSoundUri() throws Exception {
1820         NotificationChannel channel =
1821                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1822         channel.setSound(FILE_SOUND_URI, mAudioAttributes);
1823         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
1824                 UID_N_MR1, false);
1825         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1826                 USER_SYSTEM, channel.getId());
1827 
1828         loadStreamXml(baos, true, USER_SYSTEM);
1829 
1830         NotificationChannel actualChannel = mXmlHelper.getNotificationChannel(
1831                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1832         // sound is FILE_SOUND_URI, unchanged from backup
1833         assertEquals(FILE_SOUND_URI, actualChannel.getSound());
1834         // sound is flagged as restored
1835         assertTrue(actualChannel.isSoundRestored());
1836     }
1837 
1838     @Test
testChannelXml_backup()1839     public void testChannelXml_backup() throws Exception {
1840         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1841         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1842         NotificationChannel channel1 =
1843                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1844         NotificationChannel channel2 =
1845                 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
1846         NotificationChannel channel3 =
1847                 new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
1848         channel3.setGroup(ncg.getId());
1849 
1850         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
1851                 UID_N_MR1, false);
1852         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
1853                 UID_N_MR1, false);
1854         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
1855                 UID_N_MR1, false);
1856         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
1857                 SYSTEM_UID, true);
1858         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
1859                 UID_N_MR1, false);
1860 
1861         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(),
1862                 UID_N_MR1, false);
1863         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId(),
1864                 UID_N_MR1, false);
1865         assertEquals(channel2,
1866                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
1867 
1868         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1869                 USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
1870                 NotificationChannel.DEFAULT_CHANNEL_ID);
1871         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
1872                 UID_N_MR1});
1873 
1874         TypedXmlPullParser parser = Xml.newFastPullParser();
1875         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
1876                 null);
1877         parser.nextTag();
1878         mHelper.readXml(parser, true, USER_SYSTEM);
1879 
1880         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
1881         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
1882         assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG_N_MR1, UID_N_MR1));
1883         assertEquals(channel2,
1884                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
1885     }
1886 
1887     @Test
testChannelXml_defaultChannelLegacyApp_noUserSettings()1888     public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
1889         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1890                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
1891 
1892         loadStreamXml(baos, false, UserHandle.USER_ALL);
1893 
1894         final NotificationChannel updated = mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
1895                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
1896         assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
1897         assertFalse(updated.canBypassDnd());
1898         assertEquals(VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
1899         assertEquals(0, updated.getUserLockedFields());
1900     }
1901 
1902     @Test
testChannelXml_defaultChannelUpdatedApp_userSettings()1903     public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
1904         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
1905                 UID_N_MR1,
1906                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
1907         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
1908         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true,
1909                 UID_N_MR1, false);
1910 
1911         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1912                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
1913 
1914         loadStreamXml(baos, false, UserHandle.USER_ALL);
1915 
1916         assertEquals(NotificationManager.IMPORTANCE_LOW, mXmlHelper.getNotificationChannel(
1917                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false)
1918                 .getImportance());
1919     }
1920 
1921     @Test
testChannelXml_upgradeCreateDefaultChannel()1922     public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
1923         final String preupgradeXml = "<ranking version=\"1\">\n"
1924                 + "<package name=\"" + PKG_N_MR1
1925                 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
1926                 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
1927                 + VISIBILITY_SECRET + "\"" + " uid=\"" + UID_N_MR1 + "\" />\n"
1928                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\""
1929                 + VISIBILITY_PRIVATE + "\" />\n"
1930                 + "</ranking>";
1931         TypedXmlPullParser parser = Xml.newFastPullParser();
1932         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
1933                 null);
1934         parser.nextTag();
1935         mHelper.readXml(parser, false, UserHandle.USER_ALL);
1936 
1937         final NotificationChannel updated1 = mHelper.getNotificationChannel(
1938                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
1939         assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
1940         assertTrue(updated1.canBypassDnd());
1941         assertEquals(VISIBILITY_SECRET, updated1.getLockscreenVisibility());
1942         assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
1943                 | USER_LOCKED_PRIORITY
1944                 | USER_LOCKED_VISIBILITY,
1945                 updated1.getUserLockedFields());
1946 
1947         // No Default Channel created for updated packages
1948         assertEquals(null, mHelper.getNotificationChannel(PKG_O, UID_O,
1949                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
1950     }
1951 
1952     @Test
testChannelXml_upgradeDeletesDefaultChannel()1953     public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception {
1954         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
1955                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
1956         assertTrue(defaultChannel != null);
1957         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1958                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
1959         // Load package at higher sdk.
1960         final ApplicationInfo upgraded = new ApplicationInfo();
1961         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
1962         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
1963         loadStreamXml(baos, false, UserHandle.USER_ALL);
1964 
1965         // Default Channel should be gone.
1966         assertEquals(null, mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
1967                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
1968     }
1969 
1970     @Test
testDeletesDefaultChannelAfterChannelIsCreated()1971     public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception {
1972         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1973                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false,
1974                 UID_N_MR1, false);
1975         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1976                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
1977 
1978         // Load package at higher sdk.
1979         final ApplicationInfo upgraded = new ApplicationInfo();
1980         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
1981         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
1982         loadStreamXml(baos, false, UserHandle.USER_ALL);
1983 
1984         // Default Channel should be gone.
1985         assertEquals(null, mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
1986                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
1987     }
1988 
1989     @Test
testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels()1990     public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
1991         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1992                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
1993         mXmlHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1994                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false,
1995                 UID_N_MR1, false);
1996 
1997         loadStreamXml(baos, false, UserHandle.USER_ALL);
1998 
1999         // Should still have the newly created channel that wasn't in the xml.
2000         assertTrue(mXmlHelper.getNotificationChannel(
2001                 PKG_N_MR1, UID_N_MR1, "bananas", false) != null);
2002     }
2003 
2004     @Test
testCreateChannel_badImportance()2005     public void testCreateChannel_badImportance() throws Exception {
2006         try {
2007             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2008                     new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1),
2009                     true, false, UID_N_MR1, false);
2010             fail("Was allowed to create a channel with invalid importance");
2011         } catch (IllegalArgumentException e) {
2012             // yay
2013         }
2014         try {
2015             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2016                     new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED),
2017                     true, false, UID_N_MR1, false);
2018             fail("Was allowed to create a channel with invalid importance");
2019         } catch (IllegalArgumentException e) {
2020             // yay
2021         }
2022         try {
2023             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2024                     new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1),
2025                     true, false, UID_N_MR1, false);
2026             fail("Was allowed to create a channel with invalid importance");
2027         } catch (IllegalArgumentException e) {
2028             // yay
2029         }
2030         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2031                 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false,
2032                 UID_N_MR1, false));
2033         assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2034                 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false,
2035                 UID_N_MR1, false));
2036     }
2037 
2038     @Test
testUpdateChannel_downgradeImportance()2039     public void testUpdateChannel_downgradeImportance() {
2040         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2041                 new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT),
2042                 true, false, UID_N_MR1, false);
2043 
2044         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2045                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false,
2046                 UID_N_MR1, false));
2047     }
2048 
2049     @Test
testUpdateChannel_upgradeImportance_ignored()2050     public void testUpdateChannel_upgradeImportance_ignored() {
2051         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2052                 new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT),
2053                 true, false, UID_N_MR1, false);
2054 
2055         assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2056                 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false,
2057                 UID_N_MR1, false));
2058     }
2059 
2060     @Test
testUpdateChannel_badImportance()2061     public void testUpdateChannel_badImportance() {
2062         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2063                 new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT),
2064                 true, false, UID_N_MR1, false);
2065 
2066         assertThrows(IllegalArgumentException.class,
2067                 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2068                         new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true,
2069                         false, UID_N_MR1, false));
2070 
2071         assertThrows(IllegalArgumentException.class,
2072                 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2073                         new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true,
2074                         false, UID_N_MR1, false));
2075 
2076         assertThrows(IllegalArgumentException.class,
2077                 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
2078                         new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true,
2079                         false, UID_N_MR1, false));
2080     }
2081 
2082     @Test
testUpdate()2083     public void testUpdate() throws Exception {
2084         // no fields locked by user
2085         final NotificationChannel channel =
2086                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2087         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
2088         channel.enableLights(true);
2089         channel.setBypassDnd(true);
2090         channel.setLockscreenVisibility(VISIBILITY_SECRET);
2091 
2092         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false,
2093                 SYSTEM_UID, true));
2094 
2095         // same id, try to update all fields
2096         final NotificationChannel channel2 =
2097                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
2098         channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
2099         channel2.enableLights(false);
2100         channel2.setBypassDnd(false);
2101         channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
2102 
2103         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true,
2104                 SYSTEM_UID, true);
2105 
2106         // all fields should be changed
2107         assertEquals(channel2,
2108                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false));
2109 
2110         verify(mHandler, times(1)).requestSort();
2111     }
2112 
2113     @Test
testUpdate_preUpgrade_updatesAppFields()2114     public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
2115         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
2116         assertEquals(Notification.PRIORITY_DEFAULT,
2117                 mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
2118         assertEquals(VISIBILITY_NO_OVERRIDE,
2119                 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
2120 
2121         NotificationChannel defaultChannel = mHelper.getNotificationChannel(
2122                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
2123 
2124         defaultChannel.setShowBadge(false);
2125         defaultChannel.setImportance(IMPORTANCE_NONE);
2126         defaultChannel.setBypassDnd(true);
2127         defaultChannel.setLockscreenVisibility(VISIBILITY_SECRET);
2128 
2129         mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
2130         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true,
2131                 SYSTEM_UID, true);
2132 
2133         // ensure app level fields are changed
2134         assertFalse(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
2135         assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
2136         assertEquals(VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1,
2137                 UID_N_MR1));
2138     }
2139 
2140     @Test
testUpdate_postUpgrade_noUpdateAppFields()2141     public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception {
2142         final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2143 
2144         mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false,
2145                 SYSTEM_UID, true);
2146         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
2147         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
2148         assertEquals(VISIBILITY_NO_OVERRIDE,
2149                 mHelper.getPackageVisibility(PKG_O, UID_O));
2150 
2151         channel.setShowBadge(false);
2152         channel.setImportance(IMPORTANCE_NONE);
2153         channel.setBypassDnd(true);
2154         channel.setLockscreenVisibility(VISIBILITY_SECRET);
2155 
2156         mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true,
2157                 SYSTEM_UID, true);
2158 
2159         // ensure app level fields are not changed
2160         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
2161         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
2162         assertEquals(VISIBILITY_NO_OVERRIDE,
2163                 mHelper.getPackageVisibility(PKG_O, UID_O));
2164     }
2165 
2166     @Test
testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels()2167     public void testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels() throws Exception {
2168         final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2169 
2170         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false,
2171                 SYSTEM_UID, true);
2172         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
2173         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
2174         assertEquals(VISIBILITY_NO_OVERRIDE,
2175                 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
2176 
2177         channel.setShowBadge(false);
2178         channel.setImportance(IMPORTANCE_NONE);
2179         channel.setBypassDnd(true);
2180         channel.setLockscreenVisibility(VISIBILITY_SECRET);
2181 
2182         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true,
2183                 SYSTEM_UID, true);
2184 
2185         NotificationChannel defaultChannel = mHelper.getNotificationChannel(
2186                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
2187 
2188         defaultChannel.setShowBadge(false);
2189         defaultChannel.setImportance(IMPORTANCE_NONE);
2190         defaultChannel.setBypassDnd(true);
2191         defaultChannel.setLockscreenVisibility(VISIBILITY_SECRET);
2192 
2193         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true,
2194                 SYSTEM_UID, true);
2195 
2196         // ensure app level fields are not changed
2197         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
2198         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
2199         assertEquals(VISIBILITY_NO_OVERRIDE,
2200                 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
2201     }
2202 
2203     @Test
testGetNotificationChannel_ReturnsNullForUnknownChannel()2204     public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception {
2205         assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "garbage", false));
2206     }
2207 
2208     @Test
testCreateChannel_CannotChangeHiddenFields()2209     public void testCreateChannel_CannotChangeHiddenFields() {
2210         final NotificationChannel channel =
2211                 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
2212         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
2213         channel.enableLights(true);
2214         channel.setBypassDnd(true);
2215         channel.setLockscreenVisibility(VISIBILITY_SECRET);
2216         channel.setShowBadge(true);
2217         channel.setAllowBubbles(false);
2218         channel.setImportantConversation(true);
2219         int lockMask = 0;
2220         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
2221             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
2222         }
2223         channel.lockFields(lockMask);
2224 
2225         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2226                 UID_N_MR1, false));
2227 
2228         NotificationChannel savedChannel =
2229                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
2230 
2231         assertEquals(channel.getName(), savedChannel.getName());
2232         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
2233         assertFalse(savedChannel.canBypassDnd());
2234         assertFalse(VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
2235         assertFalse(channel.isImportantConversation());
2236         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
2237         assertEquals(channel.canBubble(), savedChannel.canBubble());
2238 
2239         verify(mHandler, never()).requestSort();
2240     }
2241 
2242     @Test
testCreateChannel_CannotChangeHiddenFieldsAssistant()2243     public void testCreateChannel_CannotChangeHiddenFieldsAssistant() {
2244         final NotificationChannel channel =
2245                 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
2246         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
2247         channel.enableLights(true);
2248         channel.setBypassDnd(true);
2249         channel.setLockscreenVisibility(VISIBILITY_SECRET);
2250         channel.setShowBadge(true);
2251         channel.setAllowBubbles(false);
2252         int lockMask = 0;
2253         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
2254             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
2255         }
2256         channel.lockFields(lockMask);
2257 
2258         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2259                 UID_N_MR1, false);
2260 
2261         NotificationChannel savedChannel =
2262                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
2263 
2264         assertEquals(channel.getName(), savedChannel.getName());
2265         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
2266         assertFalse(savedChannel.canBypassDnd());
2267         assertFalse(VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
2268         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
2269         assertEquals(channel.canBubble(), savedChannel.canBubble());
2270     }
2271 
2272     @Test
testClearLockedFields()2273     public void testClearLockedFields() {
2274         final NotificationChannel channel = getChannel();
2275         mHelper.clearLockedFieldsLocked(channel);
2276         assertEquals(0, channel.getUserLockedFields());
2277 
2278         channel.lockFields(USER_LOCKED_PRIORITY
2279                 | NotificationChannel.USER_LOCKED_IMPORTANCE);
2280         mHelper.clearLockedFieldsLocked(channel);
2281         assertEquals(0, channel.getUserLockedFields());
2282     }
2283 
2284     @Test
testLockFields_soundAndVibration()2285     public void testLockFields_soundAndVibration() {
2286         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
2287                 UID_N_MR1, false);
2288 
2289         final NotificationChannel update1 = getChannel();
2290         update1.setSound(new Uri.Builder().scheme("test").build(),
2291                 new AudioAttributes.Builder().build());
2292         update1.lockFields(USER_LOCKED_PRIORITY);
2293         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
2294         assertEquals(USER_LOCKED_PRIORITY
2295                 | USER_LOCKED_SOUND,
2296                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
2297                         .getUserLockedFields());
2298 
2299         NotificationChannel update2 = getChannel();
2300         update2.enableVibration(true);
2301         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true);
2302         assertEquals(USER_LOCKED_PRIORITY
2303                         | USER_LOCKED_SOUND
2304                         | USER_LOCKED_VIBRATION,
2305                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
2306                         .getUserLockedFields());
2307     }
2308 
2309     @Test
testLockFields_vibrationAndLights()2310     public void testLockFields_vibrationAndLights() {
2311         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
2312                 SYSTEM_UID, true);
2313 
2314         final NotificationChannel update1 = getChannel();
2315         update1.setVibrationPattern(new long[]{7945, 46 ,246});
2316         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
2317         assertEquals(USER_LOCKED_VIBRATION,
2318                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
2319                         .getUserLockedFields());
2320 
2321         final NotificationChannel update2 = getChannel();
2322         update2.enableLights(true);
2323         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true);
2324         assertEquals(USER_LOCKED_VIBRATION
2325                         | USER_LOCKED_LIGHTS,
2326                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
2327                         .getUserLockedFields());
2328     }
2329 
2330     @Test
testLockFields_lightsAndImportance()2331     public void testLockFields_lightsAndImportance() {
2332         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
2333                 UID_N_MR1, false);
2334 
2335         final NotificationChannel update1 = getChannel();
2336         update1.setLightColor(Color.GREEN);
2337         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
2338         assertEquals(USER_LOCKED_LIGHTS,
2339                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
2340                         .getUserLockedFields());
2341 
2342         final NotificationChannel update2 = getChannel();
2343         update2.setImportance(IMPORTANCE_DEFAULT);
2344         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true,
2345                 SYSTEM_UID, true);
2346         assertEquals(USER_LOCKED_LIGHTS
2347                         | NotificationChannel.USER_LOCKED_IMPORTANCE,
2348                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
2349                         .getUserLockedFields());
2350     }
2351 
2352     @Test
testLockFields_visibilityAndDndAndBadge()2353     public void testLockFields_visibilityAndDndAndBadge() {
2354         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
2355                 UID_N_MR1, false);
2356         assertEquals(0,
2357                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
2358                         .getUserLockedFields());
2359 
2360         final NotificationChannel update1 = getChannel();
2361         update1.setBypassDnd(true);
2362         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
2363         assertEquals(USER_LOCKED_PRIORITY,
2364                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
2365                         .getUserLockedFields());
2366 
2367         final NotificationChannel update2 = getChannel();
2368         update2.setLockscreenVisibility(VISIBILITY_SECRET);
2369         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true);
2370         assertEquals(USER_LOCKED_PRIORITY
2371                         | USER_LOCKED_VISIBILITY,
2372                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
2373                         .getUserLockedFields());
2374 
2375         final NotificationChannel update3 = getChannel();
2376         update3.setShowBadge(false);
2377         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true, SYSTEM_UID, true);
2378         assertEquals(USER_LOCKED_PRIORITY
2379                         | USER_LOCKED_VISIBILITY
2380                         | USER_LOCKED_SHOW_BADGE,
2381                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update3.getId(), false)
2382                         .getUserLockedFields());
2383     }
2384 
2385     @Test
testLockFields_allowBubble()2386     public void testLockFields_allowBubble() {
2387         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
2388                 UID_N_MR1, false);
2389         assertEquals(0,
2390                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
2391                         .getUserLockedFields());
2392 
2393         final NotificationChannel update = getChannel();
2394         update.setAllowBubbles(true);
2395         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true,
2396                 SYSTEM_UID, true);
2397         assertEquals(USER_LOCKED_ALLOW_BUBBLE,
2398                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
2399                         .getUserLockedFields());
2400     }
2401 
2402     @Test
testDeleteNonExistentChannel()2403     public void testDeleteNonExistentChannel() throws Exception {
2404         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist",
2405                 UID_N_MR1, false);
2406     }
2407 
2408     @Test
testDoubleDeleteChannel()2409     public void testDoubleDeleteChannel() throws Exception {
2410         NotificationChannel channel = getChannel();
2411         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2412                 UID_N_MR1, false);
2413         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(),
2414                 UID_N_MR1, false);
2415         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(),
2416                 UID_N_MR1, false);
2417         assertEquals(2, mLogger.getCalls().size());
2418         assertEquals(
2419                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
2420                 mLogger.get(0).event);
2421         assertEquals(
2422                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_DELETED,
2423                 mLogger.get(1).event);
2424         // No log for the second delete of the same channel.
2425     }
2426 
2427     @Test
testGetDeletedChannel()2428     public void testGetDeletedChannel() throws Exception {
2429         NotificationChannel channel = getChannel();
2430         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
2431         channel.enableLights(true);
2432         channel.setBypassDnd(true);
2433         channel.setLockscreenVisibility(VISIBILITY_SECRET);
2434         channel.enableVibration(true);
2435         channel.setVibrationPattern(new long[]{100, 67, 145, 156});
2436 
2437         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2438                 UID_N_MR1, false);
2439         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(),
2440                 UID_N_MR1, false);
2441 
2442         // Does not return deleted channel
2443         NotificationChannel response =
2444                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
2445         assertNull(response);
2446 
2447         // Returns deleted channel
2448         response = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true);
2449         compareChannels(channel, response);
2450         assertTrue(response.isDeleted());
2451     }
2452 
2453     @Test
testGetDeletedChannels()2454     public void testGetDeletedChannels() throws Exception {
2455         Map<String, NotificationChannel> channelMap = new HashMap<>();
2456         NotificationChannel channel =
2457                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2458         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
2459         channel.enableLights(true);
2460         channel.setBypassDnd(true);
2461         channel.setLockscreenVisibility(VISIBILITY_PRIVATE);
2462         channel.enableVibration(true);
2463         channel.setVibrationPattern(new long[]{100, 67, 145, 156});
2464         channelMap.put(channel.getId(), channel);
2465         NotificationChannel channel2 =
2466                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
2467         channelMap.put(channel2.getId(), channel2);
2468         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2469                 UID_N_MR1, false);
2470         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false,
2471                 UID_N_MR1, false);
2472 
2473         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(),
2474                 UID_N_MR1, false);
2475 
2476         // Returns only non-deleted channels
2477         List<NotificationChannel> channels =
2478                 mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true).getList();
2479         // Default channel + non-deleted channel + system defaults
2480         assertEquals(2, channels.size());
2481         for (NotificationChannel nc : channels) {
2482             if (channel2.getId().equals(nc.getId())) {
2483                 compareChannels(channel2, nc);
2484             }
2485         }
2486 
2487         // Returns deleted channels too
2488         channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true, true).getList();
2489         // Includes system channel(s)
2490         assertEquals(3, channels.size());
2491         for (NotificationChannel nc : channels) {
2492             if (channel2.getId().equals(nc.getId())) {
2493                 compareChannels(channelMap.get(nc.getId()), nc);
2494             }
2495         }
2496     }
2497 
2498     @Test
testGetDeletedChannelCount()2499     public void testGetDeletedChannelCount() throws Exception {
2500         NotificationChannel channel =
2501                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2502         NotificationChannel channel2 =
2503                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
2504         NotificationChannel channel3 =
2505                 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH);
2506         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2507                 UID_N_MR1, false);
2508         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false,
2509                 UID_N_MR1, false);
2510         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
2511                 UID_N_MR1, false);
2512 
2513         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(),
2514                 UID_N_MR1, false);
2515         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(),
2516                 UID_N_MR1, false);
2517 
2518         assertEquals(2, mHelper.getDeletedChannelCount(PKG_N_MR1, UID_N_MR1));
2519         assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID_O));
2520     }
2521 
2522     @Test
testGetBlockedChannelCount()2523     public void testGetBlockedChannelCount() throws Exception {
2524         NotificationChannel channel =
2525                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2526         NotificationChannel channel2 =
2527                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE);
2528         NotificationChannel channel3 =
2529                 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE);
2530         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
2531                 UID_N_MR1, false);
2532         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false,
2533                 UID_N_MR1, false);
2534         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
2535                 UID_N_MR1, false);
2536 
2537         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(),
2538                 UID_N_MR1, false);
2539 
2540         assertEquals(1, mHelper.getBlockedChannelCount(PKG_N_MR1, UID_N_MR1));
2541         assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID_O));
2542     }
2543 
2544     @Test
testGetChannelsBypassingDndCount_noChannelsBypassing()2545     public void testGetChannelsBypassingDndCount_noChannelsBypassing() throws Exception {
2546         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2547                 UID_N_MR1).getList().size());
2548     }
2549 
2550     @Test
testGetChannelsBypassingDnd_noChannelsForUidBypassing()2551     public void testGetChannelsBypassingDnd_noChannelsForUidBypassing()
2552             throws Exception {
2553         int uid = 222;
2554         NotificationChannel channel = new NotificationChannel("id", "name",
2555                 NotificationManager.IMPORTANCE_MAX);
2556         channel.setBypassDnd(true);
2557         mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true,
2558                 111, false);
2559 
2560         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2561                 uid).getList().size());
2562     }
2563 
2564     @Test
testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked()2565     public void testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked() {
2566         int uid = UID_N_MR1;
2567         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2568         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2569                 NotificationManager.IMPORTANCE_MAX);
2570         channel1.setBypassDnd(true);
2571         channel1.setGroup(ncg.getId());
2572         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg,  /* fromTargetApp */ true,
2573                 uid, false);
2574         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true,
2575                 uid, false);
2576 
2577         assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2578                 uid).getList().size());
2579 
2580         // disable group
2581         ncg.setBlocked(true);
2582         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg,  /* fromTargetApp */ false,
2583                 SYSTEM_UID, true);
2584         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2585                 uid).getList().size());
2586     }
2587 
2588     @Test
testGetChannelsBypassingDndCount_multipleChannelsBypassing()2589     public void testGetChannelsBypassingDndCount_multipleChannelsBypassing() {
2590         int uid = UID_N_MR1;
2591         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2592                 NotificationManager.IMPORTANCE_MAX);
2593         NotificationChannel channel2 = new NotificationChannel("id2", "name2",
2594                 NotificationManager.IMPORTANCE_MAX);
2595         NotificationChannel channel3 = new NotificationChannel("id3", "name3",
2596                 NotificationManager.IMPORTANCE_MAX);
2597         channel1.setBypassDnd(true);
2598         channel2.setBypassDnd(true);
2599         channel3.setBypassDnd(true);
2600         // has DND access, so can set bypassDnd attribute
2601         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true,
2602                 uid, false);
2603         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
2604                 uid, false);
2605         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel3, true, true,
2606                 uid, false);
2607         assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2608                 uid).getList().size());
2609 
2610         // setBypassDnd false for some channels
2611         channel1.setBypassDnd(false);
2612         channel2.setBypassDnd(false);
2613         assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2614                 uid).getList().size());
2615 
2616         // setBypassDnd false for rest of the channels
2617         channel3.setBypassDnd(false);
2618         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2619                 uid).getList().size());
2620     }
2621 
2622     @Test
getPackagesBypassingDnd_noChannelsBypassing()2623     public void getPackagesBypassingDnd_noChannelsBypassing() throws Exception {
2624         assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty();
2625     }
2626 
2627     @Test
getPackagesBypassingDnd_oneChannelBypassing_deleted()2628     public void getPackagesBypassingDnd_oneChannelBypassing_deleted() {
2629         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2630                 NotificationManager.IMPORTANCE_MAX);
2631         channel1.setBypassDnd(true);
2632         channel1.setDeleted(true);
2633         // has DND access, so can set bypassDnd attribute
2634         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
2635                 /*has DND access*/ true, UID_N_MR1, false);
2636 
2637         assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty();
2638     }
2639 
2640     @Test
getPackagesBypassingDnd_multipleUsers()2641     public void getPackagesBypassingDnd_multipleUsers() {
2642         int uidUser1 = UserHandle.getUid(1, UID_P);
2643         NotificationChannel channelUser1Bypass = new NotificationChannel("id11", "name1",
2644                 NotificationManager.IMPORTANCE_MAX);
2645         channelUser1Bypass.setBypassDnd(true);
2646         NotificationChannel channelUser1NoBypass = new NotificationChannel("id12", "name2",
2647                 NotificationManager.IMPORTANCE_MAX);
2648         channelUser1NoBypass.setBypassDnd(false);
2649 
2650         int uidUser2 = UserHandle.getUid(2, UID_P);
2651         NotificationChannel channelUser2Bypass = new NotificationChannel("id21", "name1",
2652                 NotificationManager.IMPORTANCE_MAX);
2653         channelUser2Bypass.setBypassDnd(true);
2654 
2655         mHelper.createNotificationChannel(PKG_P, uidUser1, channelUser1Bypass, true,
2656                 /* hasDndAccess= */ true, uidUser1, false);
2657         mHelper.createNotificationChannel(PKG_P, uidUser1, channelUser1NoBypass, true,
2658                 /* hasDndAccess= */ true, uidUser1, false);
2659         mHelper.createNotificationChannel(PKG_P, uidUser2, channelUser2Bypass, true,
2660                 /* hasDndAccess= */ true, uidUser2, false);
2661 
2662         assertThat(mHelper.getPackagesBypassingDnd(0)).isEmpty();
2663         assertThat(mHelper.getPackagesBypassingDnd(1))
2664                 .containsExactly(new ZenBypassingApp(PKG_P, false));
2665         assertThat(mHelper.getPackagesBypassingDnd(2))
2666                 .containsExactly(new ZenBypassingApp(PKG_P, true));
2667     }
2668 
2669     @Test
getPackagesBypassingDnd_oneChannelBypassing_groupBlocked()2670     public void getPackagesBypassingDnd_oneChannelBypassing_groupBlocked() {
2671         int uid = UID_N_MR1;
2672         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2673         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2674                 NotificationManager.IMPORTANCE_MAX);
2675         channel1.setBypassDnd(true);
2676         channel1.setGroup(ncg.getId());
2677         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg,  /* fromTargetApp */ true,
2678                 uid, false);
2679         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true,
2680                 uid, false);
2681         ncg.setBlocked(true);
2682 
2683         assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(uid))).isEmpty();
2684     }
2685 
2686     @Test
getPackagesBypassingDnd_multipleApps()2687     public void getPackagesBypassingDnd_multipleApps() {
2688         List<ZenBypassingApp> expected = ImmutableList.of(
2689                 new ZenBypassingApp(PKG_O, true), new ZenBypassingApp(PKG_P, false));
2690 
2691         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2692                 NotificationManager.IMPORTANCE_MAX);
2693         NotificationChannel channel2 = new NotificationChannel("id2", "name2",
2694                 NotificationManager.IMPORTANCE_MAX);
2695         NotificationChannel channel3 = new NotificationChannel("id3", "name3",
2696                 NotificationManager.IMPORTANCE_MAX);
2697         NotificationChannel channel4 = new NotificationChannel("id4", "name3",
2698                 NotificationManager.IMPORTANCE_MAX);
2699         channel1.setBypassDnd(false);
2700         channel2.setBypassDnd(true);
2701         channel3.setBypassDnd(true);
2702         channel4.setBypassDnd(false);
2703         // has DND access, so can set bypassDnd attribute
2704         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
2705                 /*has DND access*/ true, UID_N_MR1, false);
2706         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, true,
2707                 UID_O, false);
2708         mHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
2709                 UID_P, false);
2710         mHelper.createNotificationChannel(PKG_P, UID_P, channel4, true, true,
2711                 UID_P, false);
2712 
2713         assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_O)))
2714                 .containsExactlyElementsIn(expected);
2715     }
2716 
2717     @Test
testCreateAndDeleteCanChannelsBypassDnd_localSettings()2718     public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() {
2719         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2720         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2721 
2722         // create notification channel that can't bypass dnd
2723         // expected result: areChannelsBypassingDnd = false
2724         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2725         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2726         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
2727                 uid, false);
2728         assertFalse(mHelper.areChannelsBypassingDnd());
2729         if (android.app.Flags.modesUi()) {
2730             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
2731         } else {
2732             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
2733                     anyInt());
2734         }
2735         resetZenModeHelper();
2736 
2737         // create notification channel that can bypass dnd
2738         // expected result: areChannelsBypassingDnd = true
2739         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2740         channel2.setBypassDnd(true);
2741         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
2742                 uid, false);
2743         assertTrue(mHelper.areChannelsBypassingDnd());
2744         if (android.app.Flags.modesUi()) {
2745             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2746                     eq(true));
2747         } else {
2748             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2749                     any(), anyInt(), anyInt());
2750         }
2751         resetZenModeHelper();
2752 
2753         // delete channels
2754         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false);
2755         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
2756         if (android.app.Flags.modesUi()) {
2757             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
2758         } else {
2759             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
2760                     anyInt());
2761         }
2762         resetZenModeHelper();
2763 
2764         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false);
2765         assertFalse(mHelper.areChannelsBypassingDnd());
2766         if (android.app.Flags.modesUi()) {
2767             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2768                     eq(false));
2769         } else {
2770             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2771                     any(), anyInt(), anyInt());
2772         }
2773         resetZenModeHelper();
2774     }
2775 
2776     @Test
testCreateAndUpdateChannelsBypassingDnd_permissionHelper()2777     public void testCreateAndUpdateChannelsBypassingDnd_permissionHelper() {
2778         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2779         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2780 
2781         // create notification channel that can't bypass dnd
2782         // expected result: areChannelsBypassingDnd = false
2783         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2784         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2785         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
2786                 uid, false);
2787         assertFalse(mHelper.areChannelsBypassingDnd());
2788         if (android.app.Flags.modesUi()) {
2789             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
2790         } else {
2791             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
2792                     anyInt());
2793         }
2794         resetZenModeHelper();
2795 
2796         // Recreate a channel & now the app has dnd access granted and can set the bypass dnd field
2797         NotificationChannel update = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2798         update.setBypassDnd(true);
2799         mHelper.createNotificationChannel(PKG_N_MR1, uid, update, true, true,
2800                 uid, false);
2801 
2802         assertTrue(mHelper.areChannelsBypassingDnd());
2803         if (android.app.Flags.modesUi()) {
2804             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2805                     eq(true));
2806         } else {
2807             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2808                     any(), anyInt(), anyInt());
2809         }
2810         resetZenModeHelper();
2811     }
2812 
2813     @Test
testCreateAndDeleteCanChannelsBypassDnd_permissionHelper()2814     public void testCreateAndDeleteCanChannelsBypassDnd_permissionHelper() {
2815         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2816         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2817 
2818         // create notification channel that can't bypass dnd
2819         // expected result: areChannelsBypassingDnd = false
2820         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2821         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2822         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
2823                 uid, false);
2824         assertFalse(mHelper.areChannelsBypassingDnd());
2825         if (android.app.Flags.modesUi()) {
2826             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
2827         } else {
2828             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
2829                     anyInt());
2830         }
2831         resetZenModeHelper();
2832 
2833         // create notification channel that can bypass dnd, using local app level settings
2834         // expected result: areChannelsBypassingDnd = true
2835         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2836         channel2.setBypassDnd(true);
2837         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
2838                 uid, false);
2839         assertTrue(mHelper.areChannelsBypassingDnd());
2840         if (android.app.Flags.modesUi()) {
2841             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2842                     eq(true));
2843         } else {
2844             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2845                     any(), anyInt(), anyInt());
2846         }
2847         resetZenModeHelper();
2848 
2849         // delete channels
2850         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false);
2851         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
2852         if (android.app.Flags.modesUi()) {
2853             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
2854         } else {
2855             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
2856                     anyInt());
2857         }
2858         resetZenModeHelper();
2859 
2860         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false);
2861         assertFalse(mHelper.areChannelsBypassingDnd());
2862         if (android.app.Flags.modesUi()) {
2863             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2864                     eq(false));
2865         } else {
2866             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2867                     any(), anyInt(), anyInt());
2868         }
2869         resetZenModeHelper();
2870     }
2871 
2872     @Test
testBlockedGroupDoesNotBypassDnd()2873     public void testBlockedGroupDoesNotBypassDnd() {
2874         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2875         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2876 
2877         // start in a 'allowed to bypass dnd state'
2878         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2879                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2880         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
2881         mHelper.syncChannelsBypassingDnd();
2882 
2883         // create notification channel that can bypass dnd, but app is blocked
2884         // expected result: areChannelsBypassingDnd = false
2885         NotificationChannelGroup group = new NotificationChannelGroup("group", "group");
2886         group.setBlocked(true);
2887         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, group, false,
2888                 SYSTEM_UID, true);
2889         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2890         channel2.setGroup("group");
2891         channel2.setBypassDnd(true);
2892         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
2893                 uid, false);
2894         assertFalse(mHelper.areChannelsBypassingDnd());
2895         if (android.app.Flags.modesUi()) {
2896             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2897                     eq(false));
2898         } else {
2899             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2900                     any(), anyInt(), anyInt());
2901         }
2902         resetZenModeHelper();
2903     }
2904 
2905     @Test
testBlockedAppsDoNotBypassDnd_localSettings()2906     public void testBlockedAppsDoNotBypassDnd_localSettings() {
2907         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2908         when(mPermissionHelper.hasPermission(uid)).thenReturn(false);
2909 
2910         // start in a 'allowed to bypass dnd state'
2911         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2912                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2913         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
2914         mHelper.syncChannelsBypassingDnd();
2915 
2916         // create notification channel that can bypass dnd, but app is blocked
2917         // expected result: areChannelsBypassingDnd = false
2918         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2919         channel2.setBypassDnd(true);
2920         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
2921                 uid, false);
2922         assertFalse(mHelper.areChannelsBypassingDnd());
2923         if (android.app.Flags.modesUi()) {
2924             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2925                     eq(false));
2926         } else {
2927             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2928                     any(), anyInt(), anyInt());
2929         }
2930         resetZenModeHelper();
2931     }
2932 
2933     @Test
testBlockedAppsDoNotBypassDnd_permissionHelper()2934     public void testBlockedAppsDoNotBypassDnd_permissionHelper() {
2935         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2936         when(mPermissionHelper.hasPermission(uid)).thenReturn(false);
2937 
2938         // start in a 'allowed to bypass dnd state'
2939         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2940                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2941         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
2942         mHelper.syncChannelsBypassingDnd();
2943 
2944         // create notification channel that can bypass dnd, but app is blocked
2945         // expected result: areChannelsBypassingDnd = false
2946         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2947         channel2.setBypassDnd(true);
2948         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
2949                 uid, false);
2950         assertFalse(mHelper.areChannelsBypassingDnd());
2951         if (android.app.Flags.modesUi()) {
2952             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2953                     eq(false));
2954         } else {
2955             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2956                     any(), anyInt(), anyInt());
2957         }
2958         resetZenModeHelper();
2959     }
2960 
2961     @Test
testUpdateCanChannelsBypassDnd()2962     public void testUpdateCanChannelsBypassDnd() {
2963         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2964         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2965 
2966         // create notification channel that can't bypass dnd
2967         // expected result: areChannelsBypassingDnd = false
2968         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2969         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2970         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
2971                 uid, false);
2972         assertFalse(mHelper.areChannelsBypassingDnd());
2973         if (android.app.Flags.modesUi()) {
2974             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
2975         } else {
2976             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
2977                     anyInt());
2978         }
2979         resetZenModeHelper();
2980 
2981         // update channel so it CAN bypass dnd:
2982         // expected result: areChannelsBypassingDnd = true
2983         channel.setBypassDnd(true);
2984         mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true);
2985         assertTrue(mHelper.areChannelsBypassingDnd());
2986         if (android.app.Flags.modesUi()) {
2987             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
2988                     eq(true));
2989         } else {
2990             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
2991                     any(), anyInt(), anyInt());
2992         }
2993         resetZenModeHelper();
2994 
2995         // update channel so it can't bypass dnd:
2996         // expected result: areChannelsBypassingDnd = false
2997         channel.setBypassDnd(false);
2998         mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true);
2999         assertFalse(mHelper.areChannelsBypassingDnd());
3000         if (android.app.Flags.modesUi()) {
3001             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
3002                     eq(false));
3003         } else {
3004             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
3005                     any(), anyInt(), anyInt());
3006         }
3007         resetZenModeHelper();
3008     }
3009 
3010     @Test
testSetupNewZenModeHelper_canBypass()3011     public void testSetupNewZenModeHelper_canBypass() {
3012         // start notification policy off with mAreChannelsBypassingDnd = true, but
3013         // RankingHelper should change to false
3014         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
3015                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
3016         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
3017         mHelper.syncChannelsBypassingDnd();
3018         assertFalse(mHelper.areChannelsBypassingDnd());
3019         if (android.app.Flags.modesUi()) {
3020             verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
3021                     eq(false));
3022         } else {
3023             verify(mMockZenModeHelper, times(1)).setNotificationPolicy(eq(UserHandle.CURRENT),
3024                     any(), anyInt(), anyInt());
3025         }
3026         resetZenModeHelper();
3027     }
3028 
3029     @Test
testSetupNewZenModeHelper_cannotBypass()3030     public void testSetupNewZenModeHelper_cannotBypass() {
3031         // start notification policy off with mAreChannelsBypassingDnd = false
3032         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
3033         when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
3034         assertFalse(mHelper.areChannelsBypassingDnd());
3035         if (android.app.Flags.modesUi()) {
3036             verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
3037         } else {
3038             verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), any(), anyInt(),
3039                     anyInt());
3040         }
3041         resetZenModeHelper();
3042     }
3043 
3044     @Test
syncChannelsBypassingDnd_includesProfilesOfCurrentUser()3045     public void syncChannelsBypassingDnd_includesProfilesOfCurrentUser() throws Exception {
3046         when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0, 10}));
3047         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true);
3048         ApplicationInfo appInfo = new ApplicationInfo();
3049         appInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
3050         when(mPm.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn(appInfo);
3051 
3052         NotificationChannel withBypass = new NotificationChannel("1", "with", IMPORTANCE_DEFAULT);
3053         withBypass.setBypassDnd(true);
3054         NotificationChannel withoutBypass = new NotificationChannel("2", "without",
3055                 IMPORTANCE_DEFAULT);
3056         withoutBypass.setBypassDnd(false);
3057         mHelper.createNotificationChannel("com.example", UserHandle.getUid(0, 444), withoutBypass,
3058                 false, false, Process.SYSTEM_UID, true);
3059         mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass,
3060                 false, false, Process.SYSTEM_UID, true);
3061 
3062         mHelper.syncChannelsBypassingDnd();
3063 
3064         assertThat(mHelper.areChannelsBypassingDnd()).isTrue();
3065     }
3066 
3067     @Test
syncChannelsBypassingDnd_excludesOtherUsers()3068     public void syncChannelsBypassingDnd_excludesOtherUsers() throws Exception {
3069         when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0}));
3070         when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true);
3071         ApplicationInfo appInfo = new ApplicationInfo();
3072         appInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
3073         when(mPm.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn(appInfo);
3074 
3075         NotificationChannel withBypass = new NotificationChannel("1", "with", IMPORTANCE_DEFAULT);
3076         withBypass.setBypassDnd(true);
3077         NotificationChannel withoutBypass = new NotificationChannel("2", "without",
3078                 IMPORTANCE_DEFAULT);
3079         withoutBypass.setBypassDnd(false);
3080         mHelper.createNotificationChannel("com.example", UserHandle.getUid(0, 444), withoutBypass,
3081                 false, false, Process.SYSTEM_UID, true);
3082         mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass,
3083                 false, false, Process.SYSTEM_UID, true);
3084 
3085         mHelper.syncChannelsBypassingDnd();
3086 
3087         assertThat(mHelper.areChannelsBypassingDnd()).isFalse();
3088     }
3089 
3090     @Test
testOnlyHasDefaultChannel()3091     public void testOnlyHasDefaultChannel() throws Exception {
3092         assertTrue(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
3093         assertFalse(mHelper.onlyHasDefaultChannel(PKG_O, UID_O));
3094 
3095         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
3096                 UID_N_MR1, false);
3097         assertFalse(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
3098     }
3099 
3100     @Test
3101     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testOnlyHasDefaultChannel_bundleExists()3102     public void testOnlyHasDefaultChannel_bundleExists() throws Exception {
3103         mHelper.createReservedChannel(PKG_N_MR1, UID_N_MR1, TYPE_NEWS);
3104         assertTrue(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
3105         assertFalse(mHelper.onlyHasDefaultChannel(PKG_O, UID_O));
3106 
3107         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false,
3108                 UID_N_MR1, false);
3109         assertFalse(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
3110     }
3111 
3112     @Test
testCreateDeletedChannel()3113     public void testCreateDeletedChannel() throws Exception {
3114         long[] vibration = new long[]{100, 67, 145, 156};
3115         NotificationChannel channel =
3116                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
3117         channel.setVibrationPattern(vibration);
3118 
3119         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
3120                 UID_N_MR1, false);
3121         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(),
3122                 UID_N_MR1, false);
3123 
3124         NotificationChannel newChannel = new NotificationChannel(
3125                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
3126         newChannel.setVibrationPattern(new long[]{100});
3127 
3128         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false,
3129                 UID_N_MR1, false);
3130 
3131         // No long deleted, using old settings
3132         compareChannels(channel,
3133                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
3134     }
3135 
3136     @Test
testCreateChannel_defaultChannelId()3137     public void testCreateChannel_defaultChannelId() throws Exception {
3138         try {
3139             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel(
3140                     NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false,
3141                     UID_N_MR1, false);
3142             fail("Allowed to create default channel");
3143         } catch (IllegalArgumentException e) {
3144             // pass
3145         }
3146     }
3147 
3148     @Test
testCreateChannel_alreadyExists()3149     public void testCreateChannel_alreadyExists() throws Exception {
3150         long[] vibration = new long[]{100, 67, 145, 156};
3151         NotificationChannel channel =
3152                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
3153         channel.setVibrationPattern(vibration);
3154 
3155         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
3156                 UID_N_MR1, false));
3157 
3158         NotificationChannel newChannel = new NotificationChannel(
3159                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
3160         newChannel.setVibrationPattern(new long[]{100});
3161         newChannel.setAllowBubbles(!channel.canBubble());
3162         newChannel.setLightColor(Color.BLUE);
3163         newChannel.setSound(Uri.EMPTY, null);
3164         newChannel.setShowBadge(!channel.canShowBadge());
3165 
3166         assertFalse(mHelper.createNotificationChannel(
3167                 PKG_N_MR1, UID_N_MR1, newChannel, true, false,
3168                 UID_N_MR1, false));
3169 
3170         // Old settings not overridden
3171         compareChannels(channel,
3172                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
3173 
3174         assertEquals(1, mLogger.getCalls().size());
3175         assertEquals(
3176                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
3177                 mLogger.get(0).event);
3178     }
3179 
3180     @Test
testCreateChannel_noOverrideSound()3181     public void testCreateChannel_noOverrideSound() throws Exception {
3182         Uri sound = new Uri.Builder().scheme("test").build();
3183         final NotificationChannel channel = new NotificationChannel("id2", "name2",
3184                  NotificationManager.IMPORTANCE_DEFAULT);
3185         channel.setSound(sound, mAudioAttributes);
3186         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
3187                 UID_N_MR1, false);
3188         assertEquals(sound, mHelper.getNotificationChannel(
3189                 PKG_N_MR1, UID_N_MR1, channel.getId(), false).getSound());
3190     }
3191 
3192     @Test
3193     @EnableFlags(FLAG_NOTIFICATION_VERIFY_CHANNEL_SOUND_URI)
testCreateChannel_noSoundUriPermission_contentSchemeVerified()3194     public void testCreateChannel_noSoundUriPermission_contentSchemeVerified() {
3195         final Uri sound = Uri.parse(SCHEME_CONTENT + "://media/test/sound/uri");
3196 
3197         doThrow(new SecurityException("no access")).when(mUgmInternal)
3198                 .checkGrantUriPermission(eq(UID_N_MR1), any(), eq(sound),
3199                     anyInt(), eq(Process.myUserHandle().getIdentifier()));
3200 
3201         final NotificationChannel channel = new NotificationChannel("id2", "name2",
3202                 NotificationManager.IMPORTANCE_DEFAULT);
3203         channel.setSound(sound, mAudioAttributes);
3204 
3205         assertThrows(SecurityException.class,
3206                 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel,
3207                     true, false, UID_N_MR1, false));
3208         assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true))
3209                 .isNull();
3210     }
3211 
3212     @Test
3213     @EnableFlags(FLAG_NOTIFICATION_VERIFY_CHANNEL_SOUND_URI)
testCreateChannel_noSoundUriPermission_fileSchemaIgnored()3214     public void testCreateChannel_noSoundUriPermission_fileSchemaIgnored() {
3215         final Uri sound = Uri.parse(SCHEME_FILE + "://path/sound");
3216 
3217         doThrow(new SecurityException("no access")).when(mUgmInternal)
3218                 .checkGrantUriPermission(eq(UID_N_MR1), any(), any(),
3219                     anyInt(), eq(Process.myUserHandle().getIdentifier()));
3220 
3221         final NotificationChannel channel = new NotificationChannel("id2", "name2",
3222                 NotificationManager.IMPORTANCE_DEFAULT);
3223         channel.setSound(sound, mAudioAttributes);
3224 
3225         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, UID_N_MR1,
3226                 false);
3227         assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true)
3228                 .getSound()).isEqualTo(sound);
3229     }
3230 
3231     @Test
3232     @EnableFlags(FLAG_NOTIFICATION_VERIFY_CHANNEL_SOUND_URI)
testCreateChannel_noSoundUriPermission_resourceSchemaIgnored()3233     public void testCreateChannel_noSoundUriPermission_resourceSchemaIgnored() {
3234         final Uri sound = Uri.parse(SCHEME_ANDROID_RESOURCE + "://resId/sound");
3235 
3236         doThrow(new SecurityException("no access")).when(mUgmInternal)
3237                 .checkGrantUriPermission(eq(UID_N_MR1), any(), any(),
3238                     anyInt(), eq(Process.myUserHandle().getIdentifier()));
3239 
3240         final NotificationChannel channel = new NotificationChannel("id2", "name2",
3241                 NotificationManager.IMPORTANCE_DEFAULT);
3242         channel.setSound(sound, mAudioAttributes);
3243 
3244         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, UID_N_MR1,
3245                 false);
3246         assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true)
3247                 .getSound()).isEqualTo(sound);
3248     }
3249 
3250     @Test
testPermanentlyDeleteChannels()3251     public void testPermanentlyDeleteChannels() throws Exception {
3252         NotificationChannel channel1 =
3253                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3254         NotificationChannel channel2 =
3255                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
3256 
3257         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3258                 UID_N_MR1, false);
3259         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
3260                 UID_N_MR1, false);
3261 
3262         mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1);
3263 
3264         // Only default channel remains
3265         assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true, true)
3266                 .getList().size());
3267     }
3268 
3269     @Test
testDeleteGroup()3270     public void testDeleteGroup() throws Exception {
3271         NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
3272         NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted");
3273         NotificationChannel nonGroupedNonDeletedChannel =
3274                 new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH);
3275         NotificationChannel groupedButNotDeleted =
3276                 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
3277         groupedButNotDeleted.setGroup("not");
3278         NotificationChannel groupedAndDeleted =
3279                 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
3280         groupedAndDeleted.setGroup("totally");
3281 
3282         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true,
3283                 UID_N_MR1, false);
3284         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true,
3285                 UID_N_MR1, false);
3286         mHelper.createNotificationChannel(
3287                 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false,
3288                 UID_N_MR1, false);
3289         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false,
3290                 UID_N_MR1, false);
3291         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false,
3292                 UID_N_MR1, false);
3293 
3294         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId(),
3295                 UID_N_MR1, false);
3296 
3297         assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1));
3298         assertNotNull(
3299                 mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
3300 
3301         assertNull(mHelper.getNotificationChannel(
3302                 PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
3303         compareChannels(groupedAndDeleted, mHelper.getNotificationChannel(
3304                 PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
3305 
3306         compareChannels(groupedButNotDeleted, mHelper.getNotificationChannel(
3307                 PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
3308         compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
3309                 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel.getId(), false));
3310 
3311         // notDeleted
3312         assertEquals(1, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).size());
3313 
3314         verify(mHandler, never()).requestSort();
3315 
3316         assertEquals(7, mLogger.getCalls().size());
3317         assertEquals(
3318                 NotificationChannelLogger.NotificationChannelEvent
3319                         .NOTIFICATION_CHANNEL_GROUP_DELETED,
3320                 mLogger.get(5).event);  // Next-to-last log is the deletion of the channel group.
3321         assertEquals(
3322                 NotificationChannelLogger.NotificationChannelEvent
3323                         .NOTIFICATION_CHANNEL_DELETED,
3324                 mLogger.get(6).event);  // Final log is the deletion of the channel.
3325     }
3326 
3327     @Test
testGetNotificationChannelGroup()3328     public void testGetNotificationChannelGroup() throws Exception {
3329         NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
3330         NotificationChannel base =
3331                 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
3332         base.setGroup("not");
3333         NotificationChannel convo =
3334                 new NotificationChannel("convo", "belongs to notDeleted", IMPORTANCE_DEFAULT);
3335         convo.setGroup("not");
3336         convo.setConversationId("not deleted", "banana");
3337 
3338         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true,
3339                 UID_N_MR1, false);
3340         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false,
3341                 UID_N_MR1, false);
3342         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false,
3343                 UID_N_MR1, false);
3344         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true,
3345                 UID_N_MR1, false);
3346 
3347         NotificationChannelGroup g
3348                 = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
3349         Parcel parcel = Parcel.obtain();
3350         g.writeToParcel(parcel, 0);
3351         parcel.setDataPosition(0);
3352 
3353         NotificationChannelGroup g2
3354                 = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
3355         Parcel parcel2 = Parcel.obtain();
3356         g2.writeToParcel(parcel2, 0);
3357         parcel2.setDataPosition(0);
3358     }
3359 
3360     @Test
testOnUserRemoved()3361     public void testOnUserRemoved() throws Exception {
3362         int[] user0Uids = {98, 235, 16, 3782};
3363         int[] user1Uids = new int[user0Uids.length];
3364         for (int i = 0; i < user0Uids.length; i++) {
3365             user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i];
3366 
3367             final ApplicationInfo legacy = new ApplicationInfo();
3368             legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
3369             when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt()))
3370                     .thenReturn(legacy);
3371 
3372             // create records with the default channel for all user 0 and user 1 uids
3373             mHelper.canShowBadge(PKG_N_MR1, user0Uids[i]);
3374             mHelper.canShowBadge(PKG_N_MR1, user1Uids[i]);
3375         }
3376 
3377         mHelper.onUserRemoved(1);
3378 
3379         // user 0 records remain
3380         for (int i = 0; i < user0Uids.length; i++) {
3381             assertEquals(1,
3382                     mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false, true)
3383                             .getList().size());
3384         }
3385         // user 1 records are gone
3386         for (int i = 0; i < user1Uids.length; i++) {
3387             assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false, true)
3388                     .getList().size());
3389         }
3390     }
3391 
3392     @Test
testOnPackageChanged_packageRemoval()3393     public void testOnPackageChanged_packageRemoval() throws Exception {
3394         // Deleted
3395         NotificationChannel channel1 =
3396                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3397         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3398                 UID_N_MR1, false);
3399 
3400         assertTrue(mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1},
3401                 new int[]{UID_N_MR1}));
3402 
3403         assertEquals(0, mHelper.getNotificationChannels(
3404                 PKG_N_MR1, UID_N_MR1, true, true).getList().size());
3405 
3406         // Not deleted
3407         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3408                 UID_N_MR1, false);
3409 
3410         assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM,
3411                 new String[]{PKG_N_MR1}, new int[]{UID_N_MR1}));
3412         assertEquals(2,
3413                 mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true)
3414                         .getList().size());
3415     }
3416 
3417     @Test
testOnPackageChanged_packageRemoval_groups()3418     public void testOnPackageChanged_packageRemoval_groups() throws Exception {
3419         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
3420         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
3421                 UID_N_MR1, false);
3422         NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
3423         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
3424                 UID_N_MR1, false);
3425 
3426         mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
3427                 UID_N_MR1});
3428 
3429         assertEquals(0, mHelper.getNotificationChannelGroups(
3430                 PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList().size());
3431     }
3432 
3433     @Test
testOnPackageChange_downgradeTargetSdk()3434     public void testOnPackageChange_downgradeTargetSdk() throws Exception {
3435         // create channel as api 26
3436         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
3437                 UID_N_MR1, false);
3438 
3439         // install new app version targeting 25
3440         final ApplicationInfo legacy = new ApplicationInfo();
3441         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
3442         when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(legacy);
3443         mHelper.onPackagesChanged(
3444                 false, USER_SYSTEM, new String[]{PKG_O}, new int[]{UID_O});
3445 
3446         // make sure the default channel was readded
3447         //assertEquals(2, mHelper.getNotificationChannels(PKG_O, UID_O, false).getList().size());
3448         assertNotNull(mHelper.getNotificationChannel(
3449                 PKG_O, UID_O, NotificationChannel.DEFAULT_CHANNEL_ID, false));
3450     }
3451 
3452     @Test
testClearData()3453     public void testClearData() {
3454         ArraySet<Pair<String, Integer>> pkgPair = new ArraySet<>();
3455         pkgPair.add(new Pair<>(PKG_O, UID_O));
3456         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
3457                 UID_O, false);
3458         mHelper.createNotificationChannelGroup(
3459                 PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true,
3460                 UID_O, false);
3461         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkgPair);
3462         mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1);
3463         mHelper.setBubblesAllowed(PKG_O, UID_O, DEFAULT_BUBBLE_PREFERENCE);
3464         mHelper.setShowBadge(PKG_O, UID_O, false);
3465         mHelper.setAppImportanceLocked(PKG_O, UID_O);
3466 
3467         mHelper.clearData(PKG_O, UID_O);
3468 
3469         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), DEFAULT_BUBBLE_PREFERENCE);
3470         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
3471         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3472         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
3473         assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size());
3474         assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size());
3475 
3476         NotificationChannel channel = getChannel();
3477         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false,
3478                 UID_O, false);
3479 
3480         assertTrue(channel.isImportanceLockedByCriticalDeviceFunction());
3481     }
3482 
3483     @Test
testRecordDefaults()3484     public void testRecordDefaults() throws Exception {
3485         assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
3486         assertEquals(1,
3487                 mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true)
3488                         .getList().size());
3489     }
3490 
3491     @Test
testCreateGroup()3492     public void testCreateGroup() {
3493         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
3494         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
3495                 UID_N_MR1, false);
3496         assertEquals(ncg,
3497                 mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
3498         verify(mHandler, never()).requestSort();
3499         assertEquals(1, mLogger.getCalls().size());
3500         assertEquals(
3501                 NotificationChannelLogger.NotificationChannelEvent
3502                         .NOTIFICATION_CHANNEL_GROUP_CREATED,
3503                 mLogger.get(0).event);
3504     }
3505 
3506     @Test
testCannotCreateChannel_badGroup()3507     public void testCannotCreateChannel_badGroup() {
3508         NotificationChannel channel1 =
3509                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3510         channel1.setGroup("garbage");
3511         try {
3512             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3513                     UID_N_MR1, false);
3514             fail("Created a channel with a bad group");
3515         } catch (IllegalArgumentException e) {
3516         }
3517         assertEquals(0, mLogger.getCalls().size());
3518     }
3519 
3520     @Test
testCannotCreateChannel_goodGroup()3521     public void testCannotCreateChannel_goodGroup() {
3522         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
3523         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
3524                 UID_N_MR1, false);
3525         NotificationChannel channel1 =
3526                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3527         channel1.setGroup(ncg.getId());
3528         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3529                 UID_N_MR1, false);
3530 
3531         assertEquals(ncg.getId(), mHelper.getNotificationChannel(
3532                 PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
3533     }
3534 
3535     @Test
testGetChannelGroups()3536     public void testGetChannelGroups() {
3537         NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
3538         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true,
3539                 UID_N_MR1, false);
3540         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
3541         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
3542                 UID_N_MR1, false);
3543         NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
3544         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true,
3545                 UID_N_MR1, false);
3546 
3547         NotificationChannel channel1 =
3548                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3549         channel1.setGroup(ncg.getId());
3550         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3551                 UID_N_MR1, false);
3552         NotificationChannel channel1a =
3553                 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
3554         channel1a.setGroup(ncg.getId());
3555         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1a, true, false,
3556                 UID_N_MR1, false);
3557 
3558         NotificationChannel channel2 =
3559                 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
3560         channel2.setGroup(ncg2.getId());
3561         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false,
3562                 UID_N_MR1, false);
3563 
3564         NotificationChannel channel3 =
3565                 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
3566         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
3567                 UID_N_MR1, false);
3568 
3569         List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
3570                 PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList();
3571         assertEquals(3, actual.size());
3572         for (NotificationChannelGroup group : actual) {
3573             if (group.getId() == null) {
3574                 assertEquals(2, group.getChannels().size());
3575                 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
3576                         || channel3.getId().equals(group.getChannels().get(1).getId()));
3577             } else if (group.getId().equals(ncg.getId())) {
3578                 assertEquals(2, group.getChannels().size());
3579                 if (group.getChannels().get(0).getId().equals(channel1.getId())) {
3580                     assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId()));
3581                 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) {
3582                     assertTrue(group.getChannels().get(1).getId().equals(channel1.getId()));
3583                 } else {
3584                     fail("expected channel not found");
3585                 }
3586             } else if (group.getId().equals(ncg2.getId())) {
3587                 assertEquals(1, group.getChannels().size());
3588                 assertEquals(channel2.getId(), group.getChannels().get(0).getId());
3589             }
3590         }
3591     }
3592 
3593     @Test
testGetChannelGroups_noSideEffects()3594     public void testGetChannelGroups_noSideEffects() {
3595         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
3596         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
3597                 UID_N_MR1, false);
3598 
3599         NotificationChannel channel1 =
3600                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3601         channel1.setGroup(ncg.getId());
3602         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3603                 UID_N_MR1, false);
3604         mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false, true, null)
3605                 .getList();
3606 
3607         channel1.setImportance(IMPORTANCE_LOW);
3608         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
3609                 UID_N_MR1, false);
3610 
3611         List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
3612                 PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList();
3613 
3614         assertEquals(2, actual.size());
3615         for (NotificationChannelGroup group : actual) {
3616             if (Objects.equals(group.getId(), ncg.getId())) {
3617                 assertEquals(1, group.getChannels().size());
3618             }
3619         }
3620     }
3621 
3622     @Test
testGetChannelGroups_includeEmptyGroups()3623     public void testGetChannelGroups_includeEmptyGroups() {
3624         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
3625         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true,
3626                 UID_N_MR1, false);
3627         NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2");
3628         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true,
3629                 UID_N_MR1, false);
3630 
3631         NotificationChannel channel1 =
3632                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3633         channel1.setGroup(ncg.getId());
3634         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
3635                 UID_N_MR1, false);
3636 
3637         List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
3638                 PKG_N_MR1, UID_N_MR1, false, false, true, true, null).getList();
3639 
3640         assertEquals(2, actual.size());
3641         for (NotificationChannelGroup group : actual) {
3642             if (Objects.equals(group.getId(), ncg.getId())) {
3643                 assertEquals(1, group.getChannels().size());
3644             }
3645             if (Objects.equals(group.getId(), ncgEmpty.getId())) {
3646                 assertEquals(0, group.getChannels().size());
3647             }
3648         }
3649     }
3650 
3651     @Test
testCreateChannel_updateName()3652     public void testCreateChannel_updateName() {
3653         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
3654         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false,
3655                 UID_N_MR1, false));
3656         NotificationChannel actual =
3657                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
3658         assertEquals("hello", actual.getName());
3659 
3660         nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
3661         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false,
3662                 UID_N_MR1, false));
3663 
3664         actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
3665         assertEquals("goodbye", actual.getName());
3666         assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
3667 
3668         verify(mHandler, times(1)).requestSort();
3669     }
3670 
3671     @Test
testCreateChannel_addToGroup()3672     public void testCreateChannel_addToGroup() {
3673         NotificationChannelGroup group = new NotificationChannelGroup("group", "group");
3674         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true,
3675                 UID_N_MR1, false);
3676         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
3677         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false,
3678                 UID_N_MR1, false));
3679         NotificationChannel actual =
3680                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
3681         assertNull(actual.getGroup());
3682 
3683         nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
3684         nc.setGroup(group.getId());
3685         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false,
3686                 UID_N_MR1, false));
3687 
3688         actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
3689         assertNotNull(actual.getGroup());
3690         assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
3691 
3692         verify(mHandler, times(1)).requestSort();
3693         assertEquals(3, mLogger.getCalls().size());
3694         assertEquals(
3695                 NotificationChannelLogger.NotificationChannelEvent
3696                         .NOTIFICATION_CHANNEL_GROUP_CREATED,
3697                 mLogger.get(0).event);
3698         assertEquals(
3699                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
3700                 mLogger.get(1).event);
3701         assertEquals(
3702                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED,
3703                 mLogger.get(2).event);
3704     }
3705 
3706     @Test
testDumpChannelsJson()3707     public void testDumpChannelsJson() throws Exception {
3708         final ApplicationInfo upgrade = new ApplicationInfo();
3709         upgrade.targetSdkVersion = Build.VERSION_CODES.O;
3710         try {
3711             when(mPm.getApplicationInfoAsUser(
3712                     anyString(), anyInt(), anyInt())).thenReturn(upgrade);
3713         } catch (PackageManager.NameNotFoundException e) {
3714         }
3715         ArrayMap<String, Integer> expectedChannels = new ArrayMap<>();
3716         int numPackages = ThreadLocalRandom.current().nextInt(1, 5);
3717         for (int i = 0; i < numPackages; i++) {
3718             String pkgName = "pkg" + i;
3719             int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
3720             for (int j = 0; j < numChannels; j++) {
3721                 mHelper.createNotificationChannel(pkgName, UID_N_MR1,
3722                         new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false,
3723                         UID_N_MR1, false);
3724             }
3725             expectedChannels.put(pkgName, numChannels);
3726         }
3727 
3728         // delete the first channel of the first package
3729         String pkg = expectedChannels.keyAt(0);
3730         mHelper.deleteNotificationChannel("pkg" + 0, UID_N_MR1, "0",
3731                 UID_N_MR1, false);
3732         // dump should not include deleted channels
3733         int count = expectedChannels.get(pkg);
3734         expectedChannels.put(pkg, count - 1);
3735 
3736         JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter());
3737         assertEquals(numPackages, actual.length());
3738         for (int i = 0; i < numPackages; i++) {
3739             JSONObject object = actual.getJSONObject(i);
3740             assertTrue(expectedChannels.containsKey(object.get("packageName")));
3741             assertEquals(expectedChannels.get(object.get("packageName")).intValue(),
3742                     object.getInt("channelCount"));
3743         }
3744     }
3745 
3746     @Test
testDumpJson_postPermissionMigration()3747     public void testDumpJson_postPermissionMigration() throws Exception {
3748         // when getting a json dump, we want to verify that:
3749         //   - all notification importance info should come from the permission, even if the data
3750         //     isn't there yet but is present in package preferences
3751         //   - if there are permissions granted or denied from packages PreferencesHelper doesn't
3752         //     know about, those should still be included
3753 
3754         // package permissions map to be passed in
3755         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
3756         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs
3757         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); // not in local prefs
3758         appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); // in local prefs
3759         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs
3760 
3761         NotificationChannel channel1 =
3762                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3763         NotificationChannel channel2 =
3764                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
3765         NotificationChannel channel3 = new NotificationChannel("id3", "name3", IMPORTANCE_HIGH);
3766 
3767         mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false,
3768                 UID_P, false);
3769         mHelper.createNotificationChannel(PKG_P, UID_P, channel2, false, false,
3770                 UID_P, false);
3771         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false,
3772                 UID_N_MR1, false);
3773         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false,
3774                 UID_N_MR1, false);
3775 
3776         // in the json array, all of the individual package preferences are simply elements in the
3777         // values array. this set is to collect expected outputs for each of our packages.
3778         // the key/value pairs are: (userId, package name) -> expected importance
3779         ArrayMap<Pair<Integer, String>, String> expected = new ArrayMap<>();
3780 
3781         // packages that only exist via the app permissions; should be present
3782         expected.put(new Pair<>(UserHandle.getUserId(1), "first"), "DEFAULT");
3783         expected.put(new Pair<>(UserHandle.getUserId(3), "third"), "NONE");
3784 
3785         // packages that exist in both app permissions & local preferences
3786         expected.put(new Pair<>(UserHandle.getUserId(UID_P), PKG_P), "DEFAULT");
3787         expected.put(new Pair<>(UserHandle.getUserId(UID_O), PKG_O), "NONE");
3788 
3789         // package that only exists in local preferences; expect no importance output
3790         expected.put(new Pair<>(UserHandle.getUserId(UID_N_MR1), PKG_N_MR1), null);
3791 
3792         JSONArray actual = (JSONArray) mHelper.dumpJson(
3793                 new NotificationManagerService.DumpFilter(), appPermissions)
3794                 .get("PackagePreferencess");
3795         assertThat(actual.length()).isEqualTo(expected.size());
3796         for (int i = 0; i < actual.length(); i++) {
3797             JSONObject pkgInfo = actual.getJSONObject(i);
3798             Pair<Integer, String> pkgKey =
3799                     new Pair<>(pkgInfo.getInt("userId"), pkgInfo.getString("packageName"));
3800             assertTrue(expected.containsKey(pkgKey));
3801             if (pkgInfo.has("importance")) {
3802                 assertThat(pkgInfo.getString("importance")).isEqualTo(expected.get(pkgKey));
3803             } else {
3804                 assertThat(expected.get(pkgKey)).isNull();
3805             }
3806         }
3807     }
3808 
3809     @Test
testDumpJson_givenNullInput_postMigration()3810     public void testDumpJson_givenNullInput_postMigration() throws Exception {
3811         // simple test just to make sure nothing dies if we pass in null input even post migration
3812         // for some reason, even though in practice this should not be how one calls this method
3813 
3814         // some packages exist
3815         mHelper.canShowBadge(PKG_O, UID_O);
3816         mHelper.canShowBadge(PKG_P, UID_P);
3817 
3818         JSONArray actual = (JSONArray) mHelper.dumpJson(
3819                 new NotificationManagerService.DumpFilter(), null)
3820                 .get("PackagePreferencess");
3821 
3822         // there should still be info for the packages
3823         assertThat(actual.length()).isEqualTo(2);
3824 
3825         // but they should not have importance info because the migration is enabled and it got
3826         // no info
3827         for (int i = 0; i < actual.length(); i++) {
3828             assertFalse(actual.getJSONObject(i).has("importance"));
3829         }
3830     }
3831 
3832     @Test
testDumpBansJson_postPermissionMigration()3833     public void testDumpBansJson_postPermissionMigration() throws Exception {
3834         // confirm that the package bans that are in the output include all packages that
3835         // have their permission set to false, and not based on PackagePreferences importance
3836 
3837         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
3838         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs
3839         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); // not in local prefs
3840         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs
3841 
3842         mHelper.canShowBadge(PKG_O, UID_O);
3843 
3844         // expected output
3845         ArraySet<Pair<Integer, String>> expected = new ArraySet<>();
3846         expected.add(new Pair<>(UserHandle.getUserId(3), "third"));
3847         expected.add(new Pair<>(UserHandle.getUserId(UID_O), PKG_O));
3848 
3849         // make sure that's the only thing in the package ban output
3850         JSONArray actual = mHelper.dumpBansJson(
3851                 new NotificationManagerService.DumpFilter(), appPermissions);
3852         assertThat(actual.length()).isEqualTo(expected.size());
3853 
3854         for (int i = 0; i < actual.length(); i++) {
3855             JSONObject ban = actual.getJSONObject(i);
3856             assertTrue(expected.contains(
3857                     new Pair<>(ban.getInt("userId"), ban.getString("packageName"))));
3858         }
3859     }
3860 
3861     @Test
testDumpBansJson_givenNullInput()3862     public void testDumpBansJson_givenNullInput() throws Exception {
3863         // no one should do this, but...
3864 
3865         JSONArray actual = mHelper.dumpBansJson(
3866                 new NotificationManagerService.DumpFilter(), null);
3867         assertThat(actual.length()).isEqualTo(0);
3868     }
3869 
3870     @Test
testDumpString_postPermissionMigration()3871     public void testDumpString_postPermissionMigration() {
3872         // confirm that the string resulting from dumpImpl contains only importances from permission
3873 
3874         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
3875         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs
3876         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, true)); // not in local prefs
3877         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs
3878 
3879         // local package preferences
3880         mHelper.canShowBadge(PKG_O, UID_O);
3881         mHelper.canShowBadge(PKG_P, UID_P);
3882 
3883         // get dump output as a string so we can inspect the contents later
3884         StringWriter sw = new StringWriter();
3885         PrintWriter pw = new PrintWriter(sw);
3886         mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), appPermissions);
3887         pw.flush();
3888         String actual = sw.toString();
3889 
3890         // expected (substring) output for each preference via permissions
3891         ArrayList<String> expected = new ArrayList<>();
3892         expected.add("first (1) importance=DEFAULT userSet=false");
3893         expected.add("third (3) importance=NONE userSet=true");
3894         expected.add(PKG_O + " (" + UID_O + ") importance=NONE userSet=false");
3895         expected.add(PKG_P + " (" + UID_P + ")");
3896 
3897         // make sure we don't have package preference info
3898         ArrayList<String> notExpected = new ArrayList<>();
3899         notExpected.add(PKG_O + " (" + UID_O + ") importance=HIGH");
3900         notExpected.add(PKG_P + " (" + UID_P + ") importance=");  // no importance for PKG_P
3901 
3902         for (String exp : expected) {
3903             assertTrue(actual.contains(exp));
3904         }
3905 
3906         for (String notExp : notExpected) {
3907             assertFalse(actual.contains(notExp));
3908         }
3909     }
3910 
3911     @Test
testDumpString_givenNullInput()3912     public void testDumpString_givenNullInput() {
3913         // test that this doesn't choke on null input
3914 
3915         // local package preferences
3916         mHelper.canShowBadge(PKG_O, UID_O);
3917         mHelper.canShowBadge(PKG_P, UID_P);
3918 
3919         // get dump output
3920         StringWriter sw = new StringWriter();
3921         PrintWriter pw = new PrintWriter(sw);
3922         mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), null);
3923         pw.flush();
3924         String actual = sw.toString();
3925 
3926         // nobody gets any importance
3927         assertFalse(actual.contains("importance="));
3928     }
3929 
3930     @Test
testDumpProto_postPermissionMigration()3931     public void testDumpProto_postPermissionMigration() throws Exception {
3932         // test that dumping to proto gets the importances from the right place
3933 
3934         // permissions -- these should take precedence
3935         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
3936         appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs
3937         appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); // not in local prefs
3938         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs
3939 
3940         // local package preferences
3941         mHelper.canShowBadge(PKG_O, UID_O);
3942         mHelper.canShowBadge(PKG_P, UID_P);
3943 
3944         // expected output: all the packages, but only the ones provided via appPermissions
3945         // should have importance set (aka not PKG_P)
3946         // map format: (uid, package name) -> importance (int)
3947         ArrayMap<Pair<Integer, String>, Integer> expected = new ArrayMap<>();
3948         expected.put(new Pair<>(1, "first"), IMPORTANCE_DEFAULT);
3949         expected.put(new Pair<>(3, "third"), IMPORTANCE_NONE);
3950         expected.put(new Pair<>(UID_O, PKG_O), IMPORTANCE_NONE);
3951 
3952         // unfortunately, due to how nano protos work, there's no distinction between unset
3953         // fields and default-value fields, so we have no choice here but to check for a value of 0.
3954         // at least we can make sure the local importance for PKG_P in this test is not 0 (NONE).
3955         expected.put(new Pair<>(UID_P, PKG_P), 0);
3956 
3957         // get the proto output and inspect its contents
3958         ProtoOutputStream proto = new ProtoOutputStream();
3959         mHelper.dump(proto, new NotificationManagerService.DumpFilter(), appPermissions);
3960 
3961         RankingHelperProto actual = RankingHelperProto.parseFrom(proto.getBytes());
3962         assertThat(actual.records.length).isEqualTo(expected.size());
3963         for (int i = 0; i < actual.records.length; i++) {
3964             RankingHelperProto.RecordProto record = actual.records[i];
3965             Pair<Integer, String> pkgKey = new Pair<>(record.uid, record.package_);
3966             assertTrue(expected.containsKey(pkgKey));
3967             assertThat(record.importance).isEqualTo(expected.get(pkgKey));
3968         }
3969     }
3970 
3971     @Test
testBadgingOverrideTrue()3972     public void testBadgingOverrideTrue() throws Exception {
3973         Secure.putIntForUser(getContext().getContentResolver(),
3974                 Secure.NOTIFICATION_BADGING, 1,
3975                 USER.getIdentifier());
3976         mHelper.updateBadgingEnabled(); // would be called by settings observer
3977         assertTrue(mHelper.badgingEnabled(USER));
3978     }
3979 
3980     @Test
testBadgingOverrideFalse()3981     public void testBadgingOverrideFalse() throws Exception {
3982         Secure.putIntForUser(getContext().getContentResolver(),
3983                 Secure.NOTIFICATION_BADGING, 0,
3984                 USER.getIdentifier());
3985         mHelper.updateBadgingEnabled(); // would be called by settings observer
3986         assertFalse(mHelper.badgingEnabled(USER));
3987     }
3988 
3989     @Test
testBadgingForUserAll()3990     public void testBadgingForUserAll() throws Exception {
3991         try {
3992             mHelper.badgingEnabled(UserHandle.ALL);
3993         } catch (Exception e) {
3994             fail("just don't throw");
3995         }
3996     }
3997 
3998     @Test
testBadgingOverrideUserIsolation()3999     public void testBadgingOverrideUserIsolation() throws Exception {
4000         Secure.putIntForUser(getContext().getContentResolver(),
4001                 Secure.NOTIFICATION_BADGING, 0,
4002                 USER.getIdentifier());
4003         Secure.putIntForUser(getContext().getContentResolver(),
4004                 Secure.NOTIFICATION_BADGING, 1,
4005                 USER2.getIdentifier());
4006         mHelper.updateBadgingEnabled(); // would be called by settings observer
4007         assertFalse(mHelper.badgingEnabled(USER));
4008         assertTrue(mHelper.badgingEnabled(USER2));
4009     }
4010 
4011     @Test
testBubblesOverrideTrue()4012     public void testBubblesOverrideTrue() {
4013         Secure.putIntForUser(getContext().getContentResolver(),
4014                 Secure.NOTIFICATION_BUBBLES, 1,
4015                 USER.getIdentifier());
4016         mHelper.updateBubblesEnabled(); // would be called by settings observer
4017         assertTrue(mHelper.bubblesEnabled(USER));
4018     }
4019 
4020     @Test
testBubblesOverrideFalse()4021     public void testBubblesOverrideFalse() {
4022         Secure.putIntForUser(getContext().getContentResolver(),
4023                 Secure.NOTIFICATION_BUBBLES, 0,
4024                 USER.getIdentifier());
4025         mHelper.updateBubblesEnabled(); // would be called by settings observer
4026         assertFalse(mHelper.bubblesEnabled(USER));
4027     }
4028 
4029     @Test
testBubblesOverrideUserIsolation()4030     public void testBubblesOverrideUserIsolation() throws Exception {
4031         Secure.putIntForUser(getContext().getContentResolver(),
4032                 Secure.NOTIFICATION_BUBBLES, 0,
4033                 USER.getIdentifier());
4034         Secure.putIntForUser(getContext().getContentResolver(),
4035                 Secure.NOTIFICATION_BUBBLES, 1,
4036                 USER2.getIdentifier());
4037         mHelper.updateBubblesEnabled(); // would be called by settings observer
4038         assertFalse(mHelper.bubblesEnabled(USER));
4039         assertTrue(mHelper.bubblesEnabled(USER2));
4040     }
4041 
4042     @Test
testShowQSMediaOverrideTrue()4043     public void testShowQSMediaOverrideTrue() {
4044         Global.putInt(getContext().getContentResolver(),
4045                 Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1);
4046         mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer
4047         assertTrue(mHelper.isMediaNotificationFilteringEnabled());
4048     }
4049 
4050     @Test
testShowQSMediaOverrideFalse()4051     public void testShowQSMediaOverrideFalse() {
4052         Global.putInt(getContext().getContentResolver(),
4053                 Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0);
4054         mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer
4055         assertFalse(mHelper.isMediaNotificationFilteringEnabled());
4056     }
4057 
4058     @Test
testOnLocaleChanged_updatesDefaultChannels()4059     public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
4060         String newLabel = "bananas!";
4061         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
4062                 UID_N_MR1,
4063                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
4064         assertFalse(newLabel.equals(defaultChannel.getName()));
4065 
4066         Resources res = mock(Resources.class);
4067         when(mContext.getResources()).thenReturn(res);
4068         when(res.getString(com.android.internal.R.string.default_notification_channel_label))
4069                 .thenReturn(newLabel);
4070 
4071         mHelper.onLocaleChanged(mContext, USER.getIdentifier());
4072 
4073         assertEquals(newLabel, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
4074                 NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
4075     }
4076 
4077     @Test
testIsGroupBlocked_noGroup()4078     public void testIsGroupBlocked_noGroup() throws Exception {
4079         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, null));
4080 
4081         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, "non existent group"));
4082     }
4083 
4084     @Test
testIsGroupBlocked_notBlocked()4085     public void testIsGroupBlocked_notBlocked() throws Exception {
4086         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
4087         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true,
4088                 UID_N_MR1, false);
4089 
4090         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
4091     }
4092 
4093     @Test
testIsGroupBlocked_blocked()4094     public void testIsGroupBlocked_blocked() throws Exception {
4095         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
4096         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true,
4097                 UID_N_MR1, false);
4098         group.setBlocked(true);
4099         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, false,
4100                 UID_N_MR1, false);
4101 
4102         assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
4103     }
4104 
4105     @Test
testIsGroupBlocked_appCannotCreateAsBlocked()4106     public void testIsGroupBlocked_appCannotCreateAsBlocked() throws Exception {
4107         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
4108         group.setBlocked(true);
4109         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true,
4110                 UID_N_MR1, false);
4111         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
4112 
4113         NotificationChannelGroup group3 = group.clone();
4114         group3.setBlocked(false);
4115         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true,
4116                 UID_N_MR1, false);
4117         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
4118     }
4119 
4120     @Test
testIsGroup_appCannotResetBlock()4121     public void testIsGroup_appCannotResetBlock() throws Exception {
4122         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
4123         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true,
4124                 UID_N_MR1, false);
4125         NotificationChannelGroup group2 = group.clone();
4126         group2.setBlocked(true);
4127         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group2, false,
4128                 UID_N_MR1, false);
4129         assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
4130 
4131         NotificationChannelGroup group3 = group.clone();
4132         group3.setBlocked(false);
4133         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true,
4134                 UID_N_MR1, false);
4135         assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
4136     }
4137 
4138     @Test
testGetNotificationChannelGroupWithChannels()4139     public void testGetNotificationChannelGroupWithChannels() throws Exception {
4140         NotificationChannelGroup group = new NotificationChannelGroup("group", "group");
4141         NotificationChannelGroup other = new NotificationChannelGroup("something else", "name");
4142         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true,
4143                 UID_N_MR1, false);
4144         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true,
4145                 UID_N_MR1, false);
4146 
4147         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
4148         a.setGroup(group.getId());
4149         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
4150         b.setGroup(other.getId());
4151         NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
4152         c.setGroup(group.getId());
4153         NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT);
4154 
4155         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, a, true, false,
4156                 UID_N_MR1, false);
4157         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, true, false,
4158                 UID_N_MR1, false);
4159         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, c, true, false,
4160                 UID_N_MR1, false);
4161         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, d, true, false,
4162                 UID_N_MR1, false);
4163         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, c.getId(),
4164                 UID_N_MR1, false);
4165 
4166         NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels(
4167                 PKG_N_MR1, UID_N_MR1, group.getId(), true);
4168         assertEquals(2, retrieved.getChannels().size());
4169         compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
4170         compareChannels(c, findChannel(retrieved.getChannels(), c.getId()));
4171 
4172         retrieved = mHelper.getNotificationChannelGroupWithChannels(
4173                 PKG_N_MR1, UID_N_MR1, group.getId(), false);
4174         assertEquals(1, retrieved.getChannels().size());
4175         compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
4176     }
4177 
4178     @Test
testAndroidPkgCannotBypassDnd_creation()4179     public void testAndroidPkgCannotBypassDnd_creation() {
4180         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4181         test.setBypassDnd(true);
4182 
4183         mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false,
4184                 SYSTEM_UID, true);
4185 
4186         assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
4187                 .canBypassDnd());
4188     }
4189 
4190     @Test
testDndPkgCanBypassDnd_creation()4191     public void testDndPkgCanBypassDnd_creation() {
4192         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4193         test.setBypassDnd(true);
4194 
4195         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true,
4196                 UID_N_MR1, false);
4197 
4198         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd());
4199     }
4200 
4201     @Test
testNormalPkgCannotBypassDnd_creation()4202     public void testNormalPkgCannotBypassDnd_creation() {
4203         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4204         test.setBypassDnd(true);
4205 
4206         mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false,
4207                 UID_N_MR1, false);
4208 
4209         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd());
4210     }
4211 
4212     @Test
testAndroidPkgCannotBypassDnd_update()4213     public void testAndroidPkgCannotBypassDnd_update() throws Exception {
4214         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4215         mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false,
4216                 SYSTEM_UID, true);
4217 
4218         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4219         update.setBypassDnd(true);
4220         assertFalse(mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false,
4221                 SYSTEM_UID, true));
4222 
4223         assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
4224                 .canBypassDnd());
4225     }
4226 
4227     @Test
testDndPkgCanBypassDnd_update()4228     public void testDndPkgCanBypassDnd_update() throws Exception {
4229         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4230         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true,
4231                 UID_N_MR1, false);
4232 
4233         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4234         update.setBypassDnd(true);
4235         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, true,
4236                 UID_N_MR1, false));
4237 
4238         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd());
4239     }
4240 
4241     @Test
testNormalPkgCannotBypassDnd_update()4242     public void testNormalPkgCannotBypassDnd_update() {
4243         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4244         mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false,
4245                 UID_N_MR1, false);
4246         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
4247         update.setBypassDnd(true);
4248         mHelper.createNotificationChannel(PKG_N_MR1, 1000, update, true, false,
4249                 UID_N_MR1, false);
4250         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd());
4251     }
4252 
4253     @Test
testXml_statusBarIcons_default()4254     public void testXml_statusBarIcons_default() throws Exception {
4255         String preQXml = "<ranking version=\"1\">\n"
4256                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
4257                 + "<channel id=\"something\" name=\"name\" importance=\"2\" "
4258                 + "show_badge=\"true\" />\n"
4259                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" "
4260                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
4261                 + "</package>\n"
4262                 + "</ranking>\n";
4263 
4264         loadByteArrayXml(preQXml.getBytes(), true, USER_SYSTEM);
4265 
4266         assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
4267                 mXmlHelper.shouldHideSilentStatusIcons());
4268     }
4269 
4270     @Test
testXml_statusBarIcons()4271     public void testXml_statusBarIcons() throws Exception {
4272         mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
4273 
4274         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_SYSTEM);
4275         loadStreamXml(baos, false, UserHandle.USER_ALL);
4276 
4277         assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
4278                 mXmlHelper.shouldHideSilentStatusIcons());
4279     }
4280 
4281     @Test
testXml_statusBarIcons_restore()4282     public void testXml_statusBarIcons_restore() throws Exception {
4283         mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
4284 
4285         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_SYSTEM);
4286         loadStreamXml(baos, true, USER_SYSTEM);
4287 
4288         assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
4289                 mXmlHelper.shouldHideSilentStatusIcons());
4290     }
4291 
4292     @Test
testXml_statusBarIcons_restoreSecondary()4293     public void testXml_statusBarIcons_restoreSecondary() throws Exception {
4294         mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
4295 
4296         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4297         loadStreamXml(baos, true, USER_ALL);
4298 
4299         assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
4300                 mXmlHelper.shouldHideSilentStatusIcons());
4301     }
4302 
4303     @Test
testSetNotificationDelegate()4304     public void testSetNotificationDelegate() {
4305         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4306         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
4307     }
4308 
4309     @Test
testRevokeNotificationDelegate()4310     public void testRevokeNotificationDelegate() {
4311         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4312         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
4313 
4314         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
4315     }
4316 
4317     @Test
testRevokeNotificationDelegate_noDelegateExistsNoCrash()4318     public void testRevokeNotificationDelegate_noDelegateExistsNoCrash() {
4319         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
4320 
4321         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
4322     }
4323 
4324     @Test
testIsDelegateAllowed_noSource()4325     public void testIsDelegateAllowed_noSource() {
4326         assertFalse(mHelper.isDelegateAllowed("does not exist", -1, "whatever", 0));
4327     }
4328 
4329     @Test
testIsDelegateAllowed_noDelegate()4330     public void testIsDelegateAllowed_noDelegate() {
4331         mHelper.canShowBadge(PKG_O, UID_O);
4332 
4333         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0));
4334     }
4335 
4336     @Test
testIsDelegateAllowed_delegateDisabledByApp()4337     public void testIsDelegateAllowed_delegateDisabledByApp() {
4338         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4339         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
4340 
4341         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
4342     }
4343 
4344     @Test
testIsDelegateAllowed_wrongDelegate()4345     public void testIsDelegateAllowed_wrongDelegate() {
4346         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4347         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
4348 
4349         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "banana", 27));
4350     }
4351 
4352     @Test
testIsDelegateAllowed()4353     public void testIsDelegateAllowed() {
4354         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4355 
4356         assertTrue(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
4357     }
4358 
4359     @Test
testDelegateXml_noDelegate()4360     public void testDelegateXml_noDelegate() throws Exception {
4361         mHelper.canShowBadge(PKG_O, UID_O);
4362 
4363         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4364         loadStreamXml(baos, false, UserHandle.USER_ALL);
4365 
4366         assertNull(mXmlHelper.getNotificationDelegate(PKG_O, UID_O));
4367     }
4368 
4369     @Test
testDelegateXml_delegate()4370     public void testDelegateXml_delegate() throws Exception {
4371         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4372 
4373         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4374         loadStreamXml(baos, false, UserHandle.USER_ALL);
4375 
4376         assertEquals("other", mXmlHelper.getNotificationDelegate(PKG_O, UID_O));
4377     }
4378 
4379     @Test
testDelegateXml_disabledDelegate()4380     public void testDelegateXml_disabledDelegate() throws Exception {
4381         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4382         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
4383 
4384         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4385         loadStreamXml(baos, false, UserHandle.USER_ALL);
4386 
4387         assertNull(mXmlHelper.getNotificationDelegate(PKG_O, UID_O));
4388 
4389         mXmlHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
4390         assertEquals("other", mXmlHelper.getNotificationDelegate(PKG_O, UID_O));
4391     }
4392 
4393     @Test
testBubblePreference_defaults()4394     public void testBubblePreference_defaults() throws Exception {
4395         assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
4396 
4397         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4398         loadStreamXml(baos, false, UserHandle.USER_ALL);
4399 
4400         assertEquals(BUBBLE_PREFERENCE_NONE, mXmlHelper.getBubblePreference(PKG_O, UID_O));
4401         assertEquals(0, mXmlHelper.getAppLockedFields(PKG_O, UID_O));
4402     }
4403 
4404     @Test
testBubblePreference_upgradeWithSAWPermission()4405     public void testBubblePreference_upgradeWithSAWPermission() throws Exception {
4406         when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
4407                 anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED);
4408 
4409         final String xml = "<ranking version=\"1\">\n"
4410                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n"
4411                 + "<channel id=\"someId\" name=\"hi\""
4412                 + " importance=\"3\"/>"
4413                 + "</package>"
4414                 + "</ranking>";
4415         TypedXmlPullParser parser = Xml.newFastPullParser();
4416         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4417                 null);
4418         parser.nextTag();
4419         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4420 
4421         assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
4422         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
4423     }
4424 
4425     @Test
testBubblePreference_upgradeWithSAWThenUserOverride()4426     public void testBubblePreference_upgradeWithSAWThenUserOverride() throws Exception {
4427         when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
4428                 anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED);
4429 
4430         final String xml = "<ranking version=\"1\">\n"
4431                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n"
4432                 + "<channel id=\"someId\" name=\"hi\""
4433                 + " importance=\"3\"/>"
4434                 + "</package>"
4435                 + "</ranking>";
4436         TypedXmlPullParser parser = Xml.newFastPullParser();
4437         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4438                 null);
4439         parser.nextTag();
4440         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4441 
4442         assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
4443         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
4444 
4445         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED);
4446         assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
4447         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
4448                 mHelper.getAppLockedFields(PKG_O, UID_O));
4449 
4450         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4451         loadStreamXml(baos, false, UserHandle.USER_ALL);
4452 
4453         assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
4454         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
4455                 mXmlHelper.getAppLockedFields(PKG_O, UID_O));
4456     }
4457 
4458     @Test
testBubblePrefence_noSAWCheckForUnknownUid()4459     public void testBubblePrefence_noSAWCheckForUnknownUid() throws Exception {
4460         final String xml = "<ranking version=\"1\">\n"
4461                 + "<package name=\"" + PKG_O + "\" uid=\"" + UNKNOWN_UID + "\">\n"
4462                 + "<channel id=\"someId\" name=\"hi\""
4463                 + " importance=\"3\"/>"
4464                 + "</package>"
4465                 + "</ranking>";
4466         TypedXmlPullParser parser = Xml.newFastPullParser();
4467         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4468                 null);
4469         parser.nextTag();
4470         mXmlHelper.readXml(parser, false, UserHandle.USER_ALL);
4471 
4472         assertEquals(DEFAULT_BUBBLE_PREFERENCE, mHelper.getBubblePreference(PKG_O, UID_O));
4473         assertEquals(0, mXmlHelper.getAppLockedFields(PKG_O, UID_O));
4474         verify(mAppOpsManager, never()).noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
4475                 anyString(), eq(null), anyString());
4476     }
4477 
4478     @Test
testBubblePreference_xml()4479     public void testBubblePreference_xml() throws Exception {
4480         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
4481         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
4482         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
4483                 mHelper.getAppLockedFields(PKG_O, UID_O));
4484 
4485         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4486         loadStreamXml(baos, false, UserHandle.USER_ALL);
4487 
4488         assertEquals(mXmlHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
4489         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
4490                 mXmlHelper.getAppLockedFields(PKG_O, UID_O));
4491     }
4492 
4493     @Test
testReadXml_existingPackage_bubblePrefsRestored()4494     public void testReadXml_existingPackage_bubblePrefsRestored() throws Exception {
4495         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL);
4496         assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
4497 
4498         mXmlHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
4499         assertEquals(BUBBLE_PREFERENCE_NONE, mXmlHelper.getBubblePreference(PKG_O, UID_O));
4500 
4501         ByteArrayOutputStream stream = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
4502         loadStreamXml(stream, true, UserHandle.USER_ALL);
4503 
4504         assertEquals(BUBBLE_PREFERENCE_ALL, mXmlHelper.getBubblePreference(PKG_O, UID_O));
4505     }
4506 
4507     @Test
testUpdateNotificationChannel_fixedPermission()4508     public void testUpdateNotificationChannel_fixedPermission() {
4509         List<UserInfo> users = ImmutableList.of(new UserInfo(UserHandle.USER_SYSTEM, "user0", 0));
4510         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
4511         PackageInfo pm = new PackageInfo();
4512         pm.packageName = PKG_O;
4513         pm.applicationInfo = new ApplicationInfo();
4514         pm.applicationInfo.uid = UID_O;
4515         List<PackageInfo> packages = ImmutableList.of(pm);
4516         when(mPm.getInstalledPackagesAsUser(eq(0), anyInt())).thenReturn(packages);
4517         mHelper.updateFixedImportance(users);
4518 
4519         assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
4520 
4521         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4522         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false,
4523                 UID_O, false);
4524 
4525         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
4526         update.setAllowBubbles(false);
4527 
4528         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true,
4529                 UID_O, false);
4530 
4531         assertEquals(IMPORTANCE_HIGH,
4532                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4533         assertEquals(false,
4534                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
4535     }
4536 
4537     @Test
testUpdateNotificationChannel_defaultApp()4538     public void testUpdateNotificationChannel_defaultApp() {
4539         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4540         toAdd.add(new Pair<>(PKG_O, UID_O));
4541         mHelper.updateDefaultApps(0, null, toAdd);
4542         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4543         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4544 
4545         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
4546         update.setAllowBubbles(false);
4547 
4548         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false);
4549 
4550         assertEquals(IMPORTANCE_HIGH,
4551                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4552         assertEquals(false,
4553                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
4554     }
4555 
4556     @Test
testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt()4557     public void testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt() {
4558         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
4559 
4560         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_NONE);
4561         mHelper.createNotificationChannel(PKG_O, UID_O, a, false, false, UID_O, false);
4562 
4563         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4564         update.setAllowBubbles(false);
4565 
4566         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false);
4567 
4568         assertEquals(IMPORTANCE_HIGH,
4569                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4570         assertEquals(false,
4571                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
4572     }
4573 
4574     @Test
testUpdateNotificationChannel_fixedPermission_butAppAllowsIt()4575     public void testUpdateNotificationChannel_fixedPermission_butAppAllowsIt() {
4576         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
4577 
4578         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4579         a.setBlockable(true);
4580         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4581 
4582         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
4583         update.setAllowBubbles(false);
4584 
4585         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false);
4586 
4587         assertEquals(IMPORTANCE_NONE,
4588                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4589         assertEquals(false,
4590                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
4591     }
4592 
4593     @Test
testUpdateNotificationChannel_notFixedPermission()4594     public void testUpdateNotificationChannel_notFixedPermission() {
4595         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false);
4596 
4597         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4598         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4599 
4600         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
4601         update.setAllowBubbles(false);
4602 
4603         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false);
4604 
4605         assertEquals(IMPORTANCE_NONE,
4606                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4607         assertEquals(false,
4608                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
4609     }
4610 
4611     @Test
testUpdateFixedImportance_multiUser()4612     public void testUpdateFixedImportance_multiUser() {
4613         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4614         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4615         NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
4616         // different uids, same package
4617         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4618         mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false,
4619                 SYSTEM_UID, true);
4620         mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true,
4621                 UserHandle.PER_USER_RANGE + 1, false);
4622 
4623         UserInfo user = new UserInfo();
4624         user.id = 0;
4625         List<UserInfo> users = ImmutableList.of(user);
4626         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
4627         PackageInfo pm = new PackageInfo();
4628         pm.packageName = PKG_O;
4629         pm.applicationInfo = new ApplicationInfo();
4630         pm.applicationInfo.uid = UID_O;
4631         List<PackageInfo> packages = ImmutableList.of(pm);
4632         when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages);
4633         mHelper.updateFixedImportance(users);
4634 
4635         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4636                 .isImportanceLockedByCriticalDeviceFunction());
4637         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
4638                 .isImportanceLockedByCriticalDeviceFunction());
4639         assertFalse(mHelper.getNotificationChannel(
4640                         PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
4641                 .isImportanceLockedByCriticalDeviceFunction());
4642     }
4643 
4644     @Test
testUpdateFixedImportance_channelDoesNotExistYet()4645     public void testUpdateFixedImportance_channelDoesNotExistYet() {
4646         UserInfo user = new UserInfo();
4647         user.id = 0;
4648         List<UserInfo> users = ImmutableList.of(user);
4649         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
4650         PackageInfo pm = new PackageInfo();
4651         pm.packageName = PKG_O;
4652         pm.applicationInfo = new ApplicationInfo();
4653         pm.applicationInfo.uid = UID_O;
4654         List<PackageInfo> packages = ImmutableList.of(pm);
4655         when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages);
4656         mHelper.updateFixedImportance(users);
4657 
4658         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4659         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4660 
4661         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4662                 .isImportanceLockedByCriticalDeviceFunction());
4663     }
4664 
4665     @Test
testUpdateDefaultApps_add_multiUser()4666     public void testUpdateDefaultApps_add_multiUser() {
4667         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4668         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4669         NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
4670         // different uids, same package
4671         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4672         mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, UID_O, false);
4673         mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true,
4674                 UID_O, false);
4675 
4676         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4677         toAdd.add(new Pair<>(PKG_O, UID_O));
4678         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4679 
4680         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4681                 .isImportanceLockedByCriticalDeviceFunction());
4682         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
4683                 .isImportanceLockedByCriticalDeviceFunction());
4684         assertFalse(mHelper.getNotificationChannel(
4685                 PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
4686                 .isImportanceLockedByCriticalDeviceFunction());
4687     }
4688 
4689     @Test
testUpdateDefaultApps_add_onlyGivenPkg()4690     public void testUpdateDefaultApps_add_onlyGivenPkg() {
4691         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4692         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4693         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4694         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false, UID_O, false);
4695 
4696         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4697         toAdd.add(new Pair<>(PKG_O, UID_O));
4698         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4699 
4700         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4701                 .isImportanceLockedByCriticalDeviceFunction());
4702         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
4703                 .isImportanceLockedByCriticalDeviceFunction());
4704     }
4705 
4706     @Test
testUpdateDefaultApps_remove()4707     public void testUpdateDefaultApps_remove() {
4708         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4709         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4710         // different uids, same package
4711         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4712         mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, SYSTEM_UID, true);
4713 
4714         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4715         toAdd.add(new Pair<>(PKG_O, UID_O));
4716         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4717 
4718         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4719                 .isImportanceLockedByCriticalDeviceFunction());
4720         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
4721                 .isImportanceLockedByCriticalDeviceFunction());
4722 
4723         ArraySet<String> toRemove = new ArraySet<>();
4724         toRemove.add(PKG_O);
4725         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, null);
4726 
4727         assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4728                 .isImportanceLockedByCriticalDeviceFunction());
4729         assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
4730                 .isImportanceLockedByCriticalDeviceFunction());
4731     }
4732 
4733     @Test
testUpdateDefaultApps_addAndRemove()4734     public void testUpdateDefaultApps_addAndRemove() {
4735         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4736         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4737         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false,
4738                 UID_O, false);
4739         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false,
4740                 UID_N_MR1, false);
4741 
4742         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4743         toAdd.add(new Pair<>(PKG_O, UID_O));
4744         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4745 
4746 
4747         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4748                 .isImportanceLockedByCriticalDeviceFunction());
4749         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
4750                 .isImportanceLockedByCriticalDeviceFunction());
4751 
4752         // now the default is PKG_N_MR1
4753         ArraySet<String> toRemove = new ArraySet<>();
4754         toRemove.add(PKG_O);
4755         toAdd = new ArraySet<>();
4756         toAdd.add(new Pair<>(PKG_N_MR1, UID_N_MR1));
4757         mHelper.updateDefaultApps(USER.getIdentifier(), toRemove, toAdd);
4758 
4759         assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4760                 .isImportanceLockedByCriticalDeviceFunction());
4761         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
4762                 .isImportanceLockedByCriticalDeviceFunction());
4763     }
4764 
4765     @Test
testUpdateDefaultApps_appDoesNotExist_noCrash()4766     public void testUpdateDefaultApps_appDoesNotExist_noCrash() {
4767         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4768         toAdd.add(new Pair<>(PKG_O, UID_O));
4769         ArraySet<String> toRemove = new ArraySet<>();
4770         toRemove.add(PKG_N_MR1);
4771         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, toAdd);
4772     }
4773 
4774     @Test
testUpdateDefaultApps_channelDoesNotExistYet()4775     public void testUpdateDefaultApps_channelDoesNotExistYet() {
4776         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4777         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4778         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4779 
4780         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4781         toAdd.add(new Pair<>(PKG_O, UID_O));
4782         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4783 
4784         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4785                 .isImportanceLockedByCriticalDeviceFunction());
4786 
4787         mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false, UID_O, false);
4788         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
4789                 .isImportanceLockedByCriticalDeviceFunction());
4790     }
4791 
4792     @Test
testUpdateNotificationChannel_defaultAppLockedImportance()4793     public void testUpdateNotificationChannel_defaultAppLockedImportance() {
4794         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4795         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4796         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4797         toAdd.add(new Pair<>(PKG_O, UID_O));
4798         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4799 
4800         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
4801         update.setAllowBubbles(false);
4802 
4803         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, SYSTEM_UID, true);
4804         assertEquals(IMPORTANCE_HIGH,
4805                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4806         assertEquals(false,
4807                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
4808 
4809         mHelper.updateNotificationChannel(PKG_O, UID_O, update, false, UID_O, false);
4810         assertEquals(IMPORTANCE_HIGH,
4811                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4812 
4813         NotificationChannel updateImportanceLow = new NotificationChannel("a", "a",
4814                 IMPORTANCE_LOW);
4815         mHelper.updateNotificationChannel(PKG_O, UID_O, updateImportanceLow, true,
4816                 SYSTEM_UID, true);
4817         assertEquals(IMPORTANCE_LOW,
4818                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
4819     }
4820 
4821     @Test
testDefaultApp_appHasNoSettingsYet()4822     public void testDefaultApp_appHasNoSettingsYet() {
4823         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4824         toAdd.add(new Pair<>(PKG_O, UID_O));
4825         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4826 
4827         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4828         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4829 
4830         assertTrue(a.isImportanceLockedByCriticalDeviceFunction());
4831     }
4832 
4833     @Test
testUpdateFixedImportance_thenDefaultAppsRemoves()4834     public void testUpdateFixedImportance_thenDefaultAppsRemoves() {
4835         UserInfo user = new UserInfo();
4836         user.id = 0;
4837         List<UserInfo> users = ImmutableList.of(user);
4838         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
4839         PackageInfo pm = new PackageInfo();
4840         pm.packageName = PKG_O;
4841         pm.applicationInfo = new ApplicationInfo();
4842         pm.applicationInfo.uid = UID_O;
4843         List<PackageInfo> packages = ImmutableList.of(pm);
4844         when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages);
4845         mHelper.updateFixedImportance(users);
4846 
4847         ArraySet<String> toRemove = new ArraySet<>();
4848         toRemove.add(PKG_O);
4849         mHelper.updateDefaultApps(0, toRemove, null);
4850 
4851         assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
4852 
4853         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4854         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4855 
4856         // Still locked by permission if not role
4857         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4858                 .isImportanceLockedByCriticalDeviceFunction());
4859     }
4860 
4861     @Test
testUpdateDefaultApps_thenNotFixedPermission()4862     public void testUpdateDefaultApps_thenNotFixedPermission() {
4863         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4864         toAdd.add(new Pair<>(PKG_O, UID_O));
4865         mHelper.updateDefaultApps(0, null, toAdd);
4866 
4867         UserInfo user = new UserInfo();
4868         user.id = 0;
4869         List<UserInfo> users = ImmutableList.of(user);
4870         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false);
4871         PackageInfo pm = new PackageInfo();
4872         pm.packageName = PKG_O;
4873         pm.applicationInfo = new ApplicationInfo();
4874         pm.applicationInfo.uid = UID_O;
4875         List<PackageInfo> packages = ImmutableList.of(pm);
4876         when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages);
4877         mHelper.updateFixedImportance(users);
4878 
4879         assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
4880 
4881         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
4882         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false);
4883 
4884         // Still locked by role if not permission
4885         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
4886                 .isImportanceLockedByCriticalDeviceFunction());
4887     }
4888 
4889     @Test
testChannelXml_backupDefaultApp()4890     public void testChannelXml_backupDefaultApp() throws Exception {
4891         NotificationChannel channel1 =
4892                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
4893 
4894         mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false, UID_O, false);
4895 
4896         // clear data
4897         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, true,
4898                 USER_SYSTEM, channel1.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
4899         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_O}, new int[]{
4900                 UID_O});
4901 
4902         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
4903         toAdd.add(new Pair<>(PKG_O, UID_O));
4904         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
4905 
4906         TypedXmlPullParser parser = Xml.newFastPullParser();
4907         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
4908                 null);
4909         parser.nextTag();
4910         mHelper.readXml(parser, true, USER_SYSTEM);
4911 
4912         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, channel1.getId(), false)
4913                 .isImportanceLockedByCriticalDeviceFunction());
4914     }
4915 
4916     @Test
testSetBubblesAllowed_none()4917     public void testSetBubblesAllowed_none() {
4918         // Change it to non-default first
4919         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL);
4920         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL);
4921         verify(mHandler, times(1)).requestSort();
4922         reset(mHandler);
4923         // Now test
4924         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
4925         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
4926         verify(mHandler, times(1)).requestSort();
4927     }
4928 
4929     @Test
testSetBubblesAllowed_all()4930     public void testSetBubblesAllowed_all() {
4931         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL);
4932         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL);
4933         verify(mHandler, times(1)).requestSort();
4934     }
4935 
4936     @Test
testSetBubblesAllowed_selected()4937     public void testSetBubblesAllowed_selected() {
4938         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED);
4939         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_SELECTED);
4940         verify(mHandler, times(1)).requestSort();
4941     }
4942 
4943     @Test
testTooManyChannels()4944     public void testTooManyChannels() {
4945         int numToCreate = NOTIFICATION_CHANNEL_COUNT_LIMIT;
4946         for (int i = 0; i < numToCreate; i++) {
4947             NotificationChannel channel = new NotificationChannel(String.valueOf(i),
4948                     String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
4949             mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false);
4950         }
4951         try {
4952             NotificationChannel channel = new NotificationChannel(
4953                     String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT),
4954                     String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT),
4955                     NotificationManager.IMPORTANCE_HIGH);
4956             mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false);
4957             fail("Allowed to create too many notification channels");
4958         } catch (IllegalStateException e) {
4959             // great
4960         }
4961     }
4962 
4963     @Test
testTooManyChannels_xml()4964     public void testTooManyChannels_xml() throws Exception {
4965         int numToCreate = NOTIFICATION_CHANNEL_COUNT_LIMIT;
4966         String extraChannel = "EXTRA";
4967         String extraChannel1 = "EXTRA1";
4968 
4969         // create first... many... directly so we don't need a big xml blob in this test
4970         for (int i = 0; i < numToCreate; i++) {
4971             NotificationChannel channel = new NotificationChannel(String.valueOf(i),
4972                     String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
4973             mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false);
4974         }
4975 
4976         final String xml = "<ranking version=\"1\">\n"
4977                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4978                 + "<channel id=\"" + extraChannel + "\" name=\"hi\" importance=\"3\"/>"
4979                 + "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>"
4980                 + "</package>"
4981                 + "</ranking>";
4982         TypedXmlPullParser parser = Xml.newFastPullParser();
4983         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4984                 null);
4985         parser.nextTag();
4986         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4987 
4988         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true));
4989         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true));
4990     }
4991 
4992     @Test
testTooManyGroups_fromTargetApp()4993     public void testTooManyGroups_fromTargetApp() {
4994         testTooManyGroups(/* fromTargetApp= */ true);
4995     }
4996 
4997     @Test
testTooManyGroups_fromListener()4998     public void testTooManyGroups_fromListener() {
4999         testTooManyGroups(/* fromTargetApp= */ false);
5000     }
5001 
testTooManyGroups(boolean fromTargetApp)5002     private void testTooManyGroups(boolean fromTargetApp) {
5003         for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
5004             NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
5005                     String.valueOf(i));
5006             mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp,
5007                     UID_O, false);
5008         }
5009         try {
5010             NotificationChannelGroup group = new NotificationChannelGroup(
5011                     String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT),
5012                     String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT));
5013             mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp,
5014                     UID_O, false);
5015             fail("Allowed to create too many notification channel groups");
5016         } catch (IllegalStateException e) {
5017             // great
5018         }
5019     }
5020 
5021     @Test
testTooManyGroups_xml()5022     public void testTooManyGroups_xml() throws Exception {
5023         String extraGroup = "EXTRA";
5024         String extraGroup1 = "EXTRA1";
5025 
5026         // create first... many... directly so we don't need a big xml blob in this test
5027         for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
5028             NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
5029                     String.valueOf(i));
5030             mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true,
5031                     UID_O, false);
5032         }
5033 
5034         final String xml = "<ranking version=\"1\">\n"
5035                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
5036                 + "<channelGroup id=\"" + extraGroup + "\" name=\"hi\"/>"
5037                 + "<channelGroup id=\"" + extraGroup1 + "\" name=\"hi2\"/>"
5038                 + "</package>"
5039                 + "</ranking>";
5040         TypedXmlPullParser parser = Xml.newFastPullParser();
5041         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
5042                 null);
5043         parser.nextTag();
5044         mHelper.readXml(parser, false, UserHandle.USER_ALL);
5045 
5046         assertNull(mHelper.getNotificationChannelGroup(extraGroup, PKG_O, UID_O));
5047         assertNull(mHelper.getNotificationChannelGroup(extraGroup1, PKG_O, UID_O));
5048     }
5049 
5050     @Test
testRestoreMultiUser()5051     public void testRestoreMultiUser() throws Exception {
5052         String pkg = "restore_pkg";
5053         String channelId = "channelId";
5054         int user0Importance = 3;
5055         int user10Importance = 4;
5056         when(mPm.getPackageUidAsUser(eq(pkg), anyInt())).thenReturn(UserHandle.USER_NULL);
5057 
5058         // both users have the same package, but different notification settings
5059         final String xmlUser0 = "<ranking version=\"1\">\n"
5060                 + "<package name=\"" + pkg + "\" >\n"
5061                 + "<channel id=\"" + channelId + "\" name=\"hi\""
5062                 + " importance=\"" + user0Importance + "\"/>"
5063                 + "</package>"
5064                 + "</ranking>";
5065         final String xmlUser10 = "<ranking version=\"1\">\n"
5066                 + "<package name=\"" + pkg + "\" >\n"
5067                 + "<channel id=\"" + channelId + "\" name=\"hi\""
5068                 + " importance=\"" + user10Importance + "\"/>"
5069                 + "</package>"
5070                 + "</ranking>";
5071 
5072         // trigger a restore for both users
5073         TypedXmlPullParser parser = Xml.newFastPullParser();
5074         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
5075                 null);
5076         parser.nextTag();
5077         mHelper.readXml(parser, true, 0);
5078         parser = Xml.newFastPullParser();
5079         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
5080                 null);
5081         parser.nextTag();
5082         mHelper.readXml(parser, true, 10);
5083 
5084         // "install" package on both users
5085         String[] pkgList = new String[] {pkg};
5086         int[] uidList0 = new int[] {UserHandle.PER_USER_RANGE};
5087         int[] uidList10 = new int[] {UserHandle.PER_USER_RANGE + 1};
5088         when(mPm.getPackageUidAsUser(pkg, 0)).thenReturn(uidList0[0]);
5089         when(mPm.getPackageUidAsUser(pkg, 10)).thenReturn(uidList10[0]);
5090         ApplicationInfo info = new ApplicationInfo();
5091         info.targetSdkVersion = Build.VERSION_CODES.Q;
5092         when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(info);
5093 
5094         mHelper.onPackagesChanged(false, 0, pkgList, uidList0);
5095         mHelper.onPackagesChanged(false, 10, pkgList, uidList10);
5096 
5097         assertEquals(user0Importance,
5098                 mHelper.getNotificationChannel(pkg, uidList0[0], channelId, false).getImportance());
5099         assertEquals(user10Importance, mHelper.getNotificationChannel(
5100                 pkg, uidList10[0], channelId, false).getImportance());
5101     }
5102 
5103     @Test
testGetConversationNotificationChannel()5104     public void testGetConversationNotificationChannel() {
5105         String conversationId = "friend";
5106 
5107         NotificationChannel parent =
5108                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
5109         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false,
5110                 UID_O, false);
5111 
5112         NotificationChannel friend = new NotificationChannel(String.format(
5113                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId),
5114                 "messages", IMPORTANCE_DEFAULT);
5115         friend.setConversationId(parent.getId(), conversationId);
5116         mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false,
5117                 UID_O, false);
5118 
5119         compareChannelsParentChild(parent, mHelper.getConversationNotificationChannel(
5120                 PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId);
5121     }
5122 
5123     @Test
testGetNotificationChannel_conversationProvidedByNotCustomizedYet()5124     public void testGetNotificationChannel_conversationProvidedByNotCustomizedYet() {
5125         String conversationId = "friend";
5126 
5127         NotificationChannel parent =
5128                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
5129         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false,
5130                 UID_O, false);
5131 
5132         compareChannels(parent, mHelper.getConversationNotificationChannel(
5133                 PKG_O, UID_O, parent.getId(), conversationId, true, false));
5134     }
5135 
5136     @Test
testConversationNotificationChannelsRequireParents()5137     public void testConversationNotificationChannelsRequireParents() {
5138         String parentId = "does not exist";
5139         String conversationId = "friend";
5140 
5141         NotificationChannel friend = new NotificationChannel(String.format(
5142                 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId),
5143                 "messages", IMPORTANCE_DEFAULT);
5144         friend.setConversationId(parentId, conversationId);
5145 
5146         try {
5147             mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false,
5148                     UID_O, false);
5149             fail("allowed creation of conversation channel without a parent");
5150         } catch (IllegalArgumentException e) {
5151             // good
5152         }
5153     }
5154 
5155     @Test
testPlaceholderConversationId_shortcutRequired()5156     public void testPlaceholderConversationId_shortcutRequired() throws Exception {
5157         final String xml = "<ranking version=\"1\">\n"
5158                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
5159                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
5160                 + "</package>"
5161                 + "</ranking>";
5162         TypedXmlPullParser parser = Xml.newFastPullParser();
5163         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
5164                 null);
5165         parser.nextTag();
5166         mHelper.readXml(parser, false, UserHandle.USER_ALL);
5167 
5168         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
5169     }
5170 
5171     @Test
testNormalConversationId_shortcutRequired()5172     public void testNormalConversationId_shortcutRequired() throws Exception {
5173         final String xml = "<ranking version=\"1\">\n"
5174                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
5175                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"other\"/>"
5176                 + "</package>"
5177                 + "</ranking>";
5178         TypedXmlPullParser parser = Xml.newFastPullParser();
5179         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
5180                 null);
5181         parser.nextTag();
5182         mHelper.readXml(parser, false, UserHandle.USER_ALL);
5183 
5184         assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
5185     }
5186 
5187     @Test
testNoConversationId_shortcutRequired()5188     public void testNoConversationId_shortcutRequired() throws Exception {
5189         final String xml = "<ranking version=\"1\">\n"
5190                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
5191                 + "<channel id=\"id\" name=\"hi\" importance=\"3\"/>"
5192                 + "</package>"
5193                 + "</ranking>";
5194         TypedXmlPullParser parser = Xml.newFastPullParser();
5195         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
5196                 null);
5197         parser.nextTag();
5198         mHelper.readXml(parser, false, UserHandle.USER_ALL);
5199 
5200         assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
5201     }
5202 
5203     @Test
testDeleted_noTime()5204     public void testDeleted_noTime() throws Exception {
5205         final String xml = "<ranking version=\"1\">\n"
5206                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
5207                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\"/>"
5208                 + "</package>"
5209                 + "</ranking>";
5210         TypedXmlPullParser parser = Xml.newFastPullParser();
5211         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
5212                 null);
5213         parser.nextTag();
5214         mHelper.readXml(parser, false, UserHandle.USER_ALL);
5215 
5216         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
5217     }
5218 
5219     @Test
testDeleted_twice()5220     public void testDeleted_twice() throws Exception {
5221         mHelper.createNotificationChannel(
5222                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
5223                 UID_P, false);
5224 
5225         assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id",
5226                 UID_P, false));
5227         assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id",
5228                 UID_P, false));
5229     }
5230 
5231     @Test
testDeleted_recentTime()5232     public void testDeleted_recentTime() throws Exception {
5233         mHelper.createNotificationChannel(
5234                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
5235                 UID_P, false);
5236         mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", UID_P, false);
5237         NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
5238         assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
5239         assertTrue(nc1.isDeleted());
5240 
5241         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_P, UID_P, false,
5242                 USER_SYSTEM, "id", NotificationChannel.DEFAULT_CHANNEL_ID);
5243 
5244         TypedXmlPullParser parser = Xml.newFastPullParser();
5245         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
5246                 null);
5247         parser.nextTag();
5248         mHelper.readXml(parser, true, USER_SYSTEM);
5249 
5250         NotificationChannel nc = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
5251         assertTrue(DateUtils.isToday(nc.getDeletedTimeMs()));
5252         assertTrue(nc.isDeleted());
5253     }
5254 
5255     @Test
testUnDelete_time()5256     public void testUnDelete_time() throws Exception {
5257         mHelper.createNotificationChannel(
5258                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
5259                 UID_P, false);
5260         mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", UID_P, false);
5261         NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
5262         assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
5263         assertTrue(nc1.isDeleted());
5264 
5265         mHelper.createNotificationChannel(
5266                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
5267                 UID_P, false);
5268         nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
5269         assertEquals(-1, nc1.getDeletedTimeMs());
5270         assertFalse(nc1.isDeleted());
5271     }
5272 
5273     @Test
testDeleted_longTime()5274     public void testDeleted_longTime() throws Exception {
5275         long time = System.currentTimeMillis() - (DateUtils.DAY_IN_MILLIS * 30);
5276 
5277         final String xml = "<ranking version=\"1\">\n"
5278                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
5279                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\" del_time=\""
5280                 + time + "\"/>"
5281                 + "</package>"
5282                 + "</ranking>";
5283         TypedXmlPullParser parser = Xml.newFastPullParser();
5284         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
5285                 null);
5286         parser.nextTag();
5287         mHelper.readXml(parser, false, UserHandle.USER_ALL);
5288 
5289         NotificationChannel nc = mHelper.getNotificationChannel(PKG_O, UID_O, "id", true);
5290         assertNull(nc);
5291     }
5292 
5293     @Test
testGetConversations_all()5294     public void testGetConversations_all() {
5295         String convoId = "convo";
5296         NotificationChannel messages =
5297                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5298         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false,
5299                 UID_O, false);
5300         NotificationChannel calls =
5301                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
5302         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false,
5303                 UID_O, false);
5304         NotificationChannel p =
5305                 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
5306         mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false,
5307                 UID_P, false);
5308 
5309         NotificationChannel channel =
5310                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
5311         channel.setConversationId(messages.getId(), convoId);
5312         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false,
5313                 UID_O, false);
5314 
5315         NotificationChannel diffConvo =
5316                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
5317         diffConvo.setConversationId(p.getId(), "different convo");
5318         mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false,
5319                 UID_O, false);
5320 
5321         NotificationChannel channel2 =
5322                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
5323         channel2.setConversationId(calls.getId(), convoId);
5324         channel2.setImportantConversation(true);
5325         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false,
5326                 SYSTEM_UID, true);
5327 
5328         List<ConversationChannelWrapper> convos =
5329                 mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
5330 
5331         assertEquals(3, convos.size());
5332         assertTrue(conversationWrapperContainsChannel(convos, channel));
5333         assertTrue(conversationWrapperContainsChannel(convos, diffConvo));
5334         assertTrue(conversationWrapperContainsChannel(convos, channel2));
5335     }
5336 
5337     @Test
testGetConversations_multiUser()5338     public void testGetConversations_multiUser() {
5339         String convoId = "convo";
5340         NotificationChannel messages =
5341                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5342         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false,
5343                 UID_O, false);
5344 
5345         NotificationChannel messagesUser10 =
5346                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5347         mHelper.createNotificationChannel(
5348                 PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false,
5349                 UID_O + UserHandle.PER_USER_RANGE, false);
5350 
5351         NotificationChannel messagesFromB =
5352                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
5353         messagesFromB.setConversationId(messages.getId(), "different convo");
5354         mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false, UID_O, false);
5355 
5356         NotificationChannel messagesFromBUser10 =
5357                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
5358         messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo");
5359         mHelper.createNotificationChannel(
5360                 PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false,
5361                 UID_O + UserHandle.PER_USER_RANGE, false);
5362 
5363 
5364         List<ConversationChannelWrapper> convos =
5365                 mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
5366 
5367         assertEquals(1, convos.size());
5368         assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
5369 
5370         convos =
5371                 mHelper.getConversations(IntArray.wrap(new int[] {0, UserHandle.getUserId(UID_O + UserHandle.PER_USER_RANGE)}), false);
5372 
5373         assertEquals(2, convos.size());
5374         assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
5375         assertTrue(conversationWrapperContainsChannel(convos, messagesFromBUser10));
5376     }
5377 
5378     @Test
testGetConversations_notDemoted()5379     public void testGetConversations_notDemoted() {
5380         String convoId = "convo";
5381         NotificationChannel messages =
5382                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5383         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false);
5384         NotificationChannel calls =
5385                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
5386         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false);
5387         NotificationChannel p =
5388                 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
5389         mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, UID_O, false);
5390 
5391         NotificationChannel channel =
5392                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
5393         channel.setConversationId(messages.getId(), convoId);
5394         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5395 
5396         NotificationChannel diffConvo =
5397                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
5398         diffConvo.setConversationId(p.getId(), "different convo");
5399         diffConvo.setDemoted(true);
5400         mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false, UID_P, false);
5401 
5402         NotificationChannel channel2 =
5403                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
5404         channel2.setConversationId(calls.getId(), convoId);
5405         channel2.setImportantConversation(true);
5406         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false,
5407                 SYSTEM_UID, true);
5408 
5409         List<ConversationChannelWrapper> convos =
5410                 mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
5411 
5412         assertEquals(2, convos.size());
5413         assertTrue(conversationWrapperContainsChannel(convos, channel));
5414         assertFalse(conversationWrapperContainsChannel(convos, diffConvo));
5415         assertTrue(conversationWrapperContainsChannel(convos, channel2));
5416     }
5417 
5418     @Test
testGetConversations_onlyImportant()5419     public void testGetConversations_onlyImportant() {
5420         String convoId = "convo";
5421         NotificationChannel messages =
5422                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5423         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false);
5424         NotificationChannel calls =
5425                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
5426         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false);
5427         NotificationChannel p =
5428                 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
5429         mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, UID_P, false);
5430 
5431         NotificationChannel channel =
5432                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
5433         channel.setConversationId(messages.getId(), convoId);
5434         channel.setImportantConversation(true);
5435         mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, UID_O, false);
5436 
5437         NotificationChannel diffConvo =
5438                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
5439         diffConvo.setConversationId(p.getId(), "different convo");
5440         diffConvo.setImportantConversation(true);
5441         mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, false, false,
5442                 SYSTEM_UID, true);
5443 
5444         NotificationChannel channel2 =
5445                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
5446         channel2.setConversationId(calls.getId(), convoId);
5447         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false);
5448 
5449         List<ConversationChannelWrapper> convos =
5450                 mHelper.getConversations(IntArray.wrap(new int[] {0}), true);
5451 
5452         assertEquals(2, convos.size());
5453         assertTrue(conversationWrapperContainsChannel(convos, channel));
5454         assertTrue(conversationWrapperContainsChannel(convos, diffConvo));
5455         assertFalse(conversationWrapperContainsChannel(convos, channel2));
5456     }
5457 
5458     @Test
testGetConversations_parentDeleted()5459     public void testGetConversations_parentDeleted() {
5460         String convoId = "convo";
5461         NotificationChannel messages =
5462                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5463         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false);
5464 
5465         NotificationChannel channel =
5466                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
5467         channel.setConversationId(messages.getId(), convoId);
5468         channel.setImportantConversation(true);
5469         mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false,
5470                 SYSTEM_UID, true);
5471 
5472         mHelper.permanentlyDeleteNotificationChannel(PKG_O, UID_O, "messages");
5473 
5474         List<ConversationChannelWrapper> convos =
5475                 mHelper.getConversations(IntArray.wrap(new int[] {0}), true);
5476 
5477         assertEquals(1, convos.size());
5478         assertTrue(conversationWrapperContainsChannel(convos, channel));
5479     }
5480 
conversationWrapperContainsChannel(List<ConversationChannelWrapper> list, NotificationChannel expected)5481     private boolean conversationWrapperContainsChannel(List<ConversationChannelWrapper> list,
5482             NotificationChannel expected) {
5483         for (ConversationChannelWrapper ccw : list) {
5484             if (ccw.getNotificationChannel().equals(expected)) {
5485                 return true;
5486             }
5487         }
5488 
5489         return false;
5490     }
5491 
5492     @Test
testGetConversations_invalidPkg()5493     public void testGetConversations_invalidPkg() {
5494         assertThat(mHelper.getConversations("bad", 1)).isEmpty();
5495     }
5496 
5497     @Test
testGetConversations_noConversations()5498     public void testGetConversations_noConversations() {
5499         NotificationChannel channel =
5500                 new NotificationChannel("not_convo", "not_convo", IMPORTANCE_DEFAULT);
5501         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5502 
5503         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
5504     }
5505 
5506     @Test
testGetConversations_noDisabledGroups()5507     public void testGetConversations_noDisabledGroups() {
5508         NotificationChannelGroup group = new NotificationChannelGroup("a", "a");
5509         group.setBlocked(true);
5510         mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false, SYSTEM_UID, true);
5511         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
5512         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
5513 
5514         NotificationChannel channel =
5515                 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
5516         channel.setConversationId("parent", "convo");
5517         channel.setGroup(group.getId());
5518         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5519 
5520         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
5521     }
5522 
5523     @Test
testGetConversations_noDeleted()5524     public void testGetConversations_noDeleted() {
5525         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
5526         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
5527         NotificationChannel channel =
5528                 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
5529         channel.setConversationId("parent", "convo");
5530         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5531         mHelper.deleteNotificationChannel(PKG_O, UID_O, channel.getId(), UID_O, false);
5532 
5533         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
5534     }
5535 
5536     @Test
testGetConversations_noDemoted()5537     public void testGetConversations_noDemoted() {
5538         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
5539         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
5540         NotificationChannel channel =
5541                 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
5542         channel.setConversationId("parent", "convo");
5543         channel.setDemoted(true);
5544         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5545 
5546         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
5547     }
5548 
5549     @Test
testGetConversations()5550     public void testGetConversations() {
5551         NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name");
5552         mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true, UID_O, false);
5553 
5554         NotificationChannel messages =
5555                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5556         messages.setGroup(group.getId());
5557         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false);
5558         NotificationChannel calls =
5559                 new NotificationChannel("calls", "Calls", IMPORTANCE_HIGH);
5560         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false);
5561 
5562         NotificationChannel channel =
5563                 new NotificationChannel("A person", "A lovely person", IMPORTANCE_DEFAULT);
5564         channel.setGroup(group.getId());
5565         channel.setConversationId(messages.getId(), channel.getName().toString());
5566         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5567 
5568         NotificationChannel channel2 =
5569                 new NotificationChannel("B person", "B fabulous person", IMPORTANCE_DEFAULT);
5570         channel2.setConversationId(calls.getId(), channel2.getName().toString());
5571         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false);
5572 
5573         Map<String, NotificationChannel> expected = new HashMap<>();
5574         expected.put(channel.getId(), channel);
5575         expected.put(channel2.getId(), channel2);
5576 
5577         Map<String, CharSequence> expectedGroup = new HashMap<>();
5578         expectedGroup.put(channel.getId(), group.getName());
5579         expectedGroup.put(channel2.getId(), null);
5580 
5581         Map<String, CharSequence> expectedParentLabel= new HashMap<>();
5582         expectedParentLabel.put(channel.getId(), messages.getName());
5583         expectedParentLabel.put(channel2.getId(), calls.getName());
5584 
5585         ArrayList<ConversationChannelWrapper> convos = mHelper.getConversations(PKG_O, UID_O);
5586         assertThat(convos).hasSize(2);
5587 
5588         for (ConversationChannelWrapper convo : convos) {
5589             assertThat(convo.getNotificationChannel())
5590                     .isEqualTo(expected.get(convo.getNotificationChannel().getId()));
5591             assertThat(convo.getParentChannelLabel())
5592                     .isEqualTo(expectedParentLabel.get(convo.getNotificationChannel().getId()));
5593             assertThat(convo.getGroupLabel())
5594                     .isEqualTo(expectedGroup.get(convo.getNotificationChannel().getId()));
5595         }
5596     }
5597 
5598     @Test
testDeleteConversations()5599     public void testDeleteConversations() {
5600         String convoId = "convo";
5601         String convoIdC = "convoC";
5602         NotificationChannel messages =
5603                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5604         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false);
5605         NotificationChannel calls =
5606                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
5607         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false);
5608 
5609         NotificationChannel channel =
5610                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
5611         channel.setConversationId(messages.getId(), convoId);
5612         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5613 
5614         NotificationChannel noMatch =
5615                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
5616         noMatch.setConversationId(messages.getId(), "different convo");
5617         mHelper.createNotificationChannel(PKG_O, UID_O, noMatch, true, false, UID_O, false);
5618 
5619         NotificationChannel channel2 =
5620                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
5621         channel2.setConversationId(calls.getId(), convoId);
5622         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false);
5623 
5624         NotificationChannel channel3 =
5625                 new NotificationChannel("C person msgs", "msgs from C", IMPORTANCE_DEFAULT);
5626         channel3.setConversationId(messages.getId(), convoIdC);
5627         mHelper.createNotificationChannel(PKG_O, UID_O, channel3, true, false, UID_O, false);
5628 
5629         assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false));
5630         assertEquals(channel2,
5631                 mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false));
5632         List<String> deleted = mHelper.deleteConversations(PKG_O, UID_O, Set.of(convoId, convoIdC),
5633                 UID_O, false);
5634         assertEquals(3, deleted.size());
5635 
5636         assertEquals(messages,
5637                 mHelper.getNotificationChannel(PKG_O, UID_O, messages.getId(), false));
5638         assertEquals(noMatch,
5639                 mHelper.getNotificationChannel(PKG_O, UID_O, noMatch.getId(), false));
5640 
5641         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false));
5642         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false));
5643         assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), true));
5644         assertEquals(channel2,
5645                 mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), true));
5646 
5647         assertEquals(9, mLogger.getCalls().size());
5648         assertEquals(
5649                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
5650                 mLogger.get(0).event);  // Channel messages
5651         assertEquals(
5652                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
5653                 mLogger.get(1).event);  // Channel calls
5654         assertEquals(
5655                 NotificationChannelLogger.NotificationChannelEvent
5656                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
5657                 mLogger.get(2).event);  // Channel channel - Conversation A person msgs
5658         assertEquals(
5659                 NotificationChannelLogger.NotificationChannelEvent
5660                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
5661                 mLogger.get(3).event);  // Channel noMatch - Conversation B person msgs
5662         assertEquals(
5663                 NotificationChannelLogger.NotificationChannelEvent
5664                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
5665                 mLogger.get(4).event);  // Channel channel2 - Conversation A person calls
5666         assertEquals(
5667                 NotificationChannelLogger.NotificationChannelEvent
5668                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
5669                 mLogger.get(5).event);  // Channel channel3 - Conversation C person msgs
5670         assertEquals(
5671                 NotificationChannelLogger.NotificationChannelEvent
5672                         .NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
5673                 mLogger.get(6).event);  // Delete Channel channel - Conversation A person msgs
5674         assertEquals(
5675                 NotificationChannelLogger.NotificationChannelEvent
5676                         .NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
5677                 mLogger.get(7).event);  // Delete Channel channel2 - Conversation A person calls
5678         assertEquals(
5679                 NotificationChannelLogger.NotificationChannelEvent
5680                         .NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
5681                 mLogger.get(8).event);  // Delete Channel channel3 - Conversation C person msgs
5682     }
5683 
5684     @Test
testUpdateConversationParent_updatesConversations()5685     public void testUpdateConversationParent_updatesConversations() {
5686         SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
5687                 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
5688 
5689         NotificationChannel parent =
5690                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5691         mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
5692                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5693         NotificationChannel convoA = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
5694         convoA.setConversationId(parent.getId(), "A");
5695         mHelper.createNotificationChannel(PKG_O, UID_O, convoA, /* fromTargetApp= */ true,
5696                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5697         NotificationChannel convoB = new NotificationChannel("B", "With B", IMPORTANCE_DEFAULT);
5698         convoB.setConversationId(parent.getId(), "B");
5699         mHelper.createNotificationChannel(PKG_O, UID_O, convoB, /* fromTargetApp= */ true,
5700                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5701         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "messages", /* includeDeleted= */
5702                 false).shouldVibrate()).isFalse();
5703         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A",
5704                 /* includeDeleted= */ false).shouldVibrate()).isFalse();
5705         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "B",
5706                 /* includeDeleted= */ false).shouldVibrate()).isFalse();
5707         mLogger.clear();
5708 
5709         NotificationChannel parentUpdate = cloneChannel(parent);
5710         parentUpdate.enableVibration(true);
5711         mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, UID_O,
5712                 /* fromSystemOrSystemUi= */ true);
5713 
5714         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "messages",
5715                 /* includeDeleted= */ false).shouldVibrate()).isTrue();
5716         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A",
5717                 /* includeDeleted= */ false).shouldVibrate()).isTrue();
5718         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "B",
5719                 /* includeDeleted= */ false).shouldVibrate()).isTrue();
5720 
5721         // Verify that the changes to parent and children were logged.
5722         assertThat(mLogger.getCalls()).containsExactly(
5723                         new NotificationChannelLoggerFake.CallRecord(
5724                                 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "messages"),
5725                         new NotificationChannelLoggerFake.CallRecord(
5726                                 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "A"),
5727                         new NotificationChannelLoggerFake.CallRecord(
5728                                 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "B"))
5729                 .inOrder();
5730     }
5731 
5732     @Test
testUpdateConversationParent_updatesUnlockedFields()5733     public void testUpdateConversationParent_updatesUnlockedFields() {
5734         SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
5735                 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
5736 
5737         NotificationChannel parent =
5738                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5739         mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
5740                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5741         NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
5742         convo.setConversationId(parent.getId(), "A");
5743         mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
5744                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5745         NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5746                 convo.getId(), /* includeDeleted= */ false);
5747         assertThat(originalChild.canBypassDnd()).isFalse();
5748         assertThat(originalChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE);
5749         assertThat(originalChild.getImportance()).isEqualTo(IMPORTANCE_DEFAULT);
5750         assertThat(originalChild.shouldShowLights()).isFalse();
5751         assertThat(originalChild.getSound()).isEqualTo(DEFAULT_SOUND_URI);
5752         assertThat(originalChild.shouldVibrate()).isFalse();
5753         assertThat(originalChild.canShowBadge()).isTrue();
5754         assertThat(originalChild.getAllowBubbles()).isEqualTo(DEFAULT_ALLOW_BUBBLE);
5755 
5756         NotificationChannel parentUpdate = cloneChannel(parent);
5757         parentUpdate.setBypassDnd(true);
5758         parentUpdate.setLockscreenVisibility(VISIBILITY_SECRET);
5759         parentUpdate.setImportance(IMPORTANCE_HIGH);
5760         parentUpdate.enableLights(true);
5761         parentUpdate.setSound(SOUND_URI, mAudioAttributes);
5762         parentUpdate.enableVibration(true);
5763         parentUpdate.setShowBadge(false);
5764         parentUpdate.setAllowBubbles(true);
5765         mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
5766                 UID_O, /* fromSystemOrSystemUi= */ true);
5767 
5768         NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5769                 "A", /* includeDeleted= */ false);
5770         assertThat(updatedChild.canBypassDnd()).isTrue();
5771         assertThat(updatedChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_SECRET);
5772         assertThat(updatedChild.getImportance()).isEqualTo(IMPORTANCE_HIGH);
5773         assertThat(updatedChild.shouldShowLights()).isTrue();
5774         assertThat(updatedChild.getSound()).isEqualTo(SOUND_URI);
5775         assertThat(updatedChild.shouldVibrate()).isTrue();
5776         assertThat(updatedChild.canShowBadge()).isFalse();
5777         assertThat(updatedChild.getAllowBubbles()).isEqualTo(ALLOW_BUBBLE_ON);
5778     }
5779 
5780     @Test
testUpdateConversationParent_doesNotUpdateLockedFields()5781     public void testUpdateConversationParent_doesNotUpdateLockedFields() {
5782         SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
5783                 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
5784         NotificationChannel parent =
5785                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5786         mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
5787                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5788         NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
5789         convo.setConversationId(parent.getId(), "A");
5790         mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
5791                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5792         // Directly update the child to lock every field.
5793         // Normally this would be the result of one or more "fromUser" updates with modified fields.
5794         convo.lockFields(
5795                 USER_LOCKED_PRIORITY | USER_LOCKED_VISIBILITY | USER_LOCKED_IMPORTANCE
5796                         | USER_LOCKED_LIGHTS | USER_LOCKED_VIBRATION | USER_LOCKED_SOUND
5797                         | USER_LOCKED_SHOW_BADGE | USER_LOCKED_ALLOW_BUBBLE);
5798         mLogger.clear();
5799 
5800         NotificationChannel parentUpdate = cloneChannel(parent);
5801         parentUpdate.setBypassDnd(true);
5802         parentUpdate.setLockscreenVisibility(VISIBILITY_SECRET);
5803         parentUpdate.setImportance(IMPORTANCE_HIGH);
5804         parentUpdate.enableLights(true);
5805         parentUpdate.setSound(SOUND_URI, mAudioAttributes);
5806         parentUpdate.enableVibration(true);
5807         parentUpdate.setShowBadge(false);
5808         parentUpdate.setAllowBubbles(true);
5809         mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
5810                 UID_O, /* fromSystemOrSystemUi= */ true);
5811 
5812         NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5813                 "A", /* includeDeleted= */ false);
5814         assertThat(updatedChild.canBypassDnd()).isFalse();
5815         assertThat(updatedChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE);
5816         assertThat(updatedChild.getImportance()).isEqualTo(IMPORTANCE_DEFAULT);
5817         assertThat(updatedChild.shouldShowLights()).isFalse();
5818         assertThat(updatedChild.getSound()).isEqualTo(DEFAULT_SOUND_URI);
5819         assertThat(updatedChild.shouldVibrate()).isFalse();
5820         assertThat(updatedChild.canShowBadge()).isTrue();
5821         assertThat(updatedChild.getAllowBubbles()).isEqualTo(DEFAULT_ALLOW_BUBBLE);
5822 
5823         // Verify that only the changes to the parent were logged.
5824         assertThat(mLogger.getCalls()).containsExactly(
5825                         new NotificationChannelLoggerFake.CallRecord(
5826                                 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "messages"));
5827     }
5828 
5829     @Test
testUpdateConversationParent_updatesDemotedConversation()5830     public void testUpdateConversationParent_updatesDemotedConversation() {
5831         SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
5832                 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
5833         NotificationChannel parent =
5834                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5835         mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
5836                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5837         NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
5838         convo.setConversationId(parent.getId(), "A");
5839         convo.setDemoted(true);
5840         mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
5841                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5842         NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5843                 convo.getId(), /* includeDeleted= */ false);
5844         assertThat(originalChild.shouldVibrate()).isFalse();
5845 
5846         NotificationChannel parentUpdate = cloneChannel(parent);
5847         parentUpdate.enableVibration(true);
5848         mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
5849                 UID_O, /* fromSystemOrSystemUi= */ true);
5850 
5851         NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5852                 "A", /* includeDeleted= */ false);
5853         assertThat(updatedChild.shouldVibrate()).isTrue();
5854     }
5855 
5856     @Test
testUpdateConversationParent_updatesDeletedConversation()5857     public void testUpdateConversationParent_updatesDeletedConversation() {
5858         SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
5859                 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
5860         NotificationChannel parent =
5861                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5862         mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
5863                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5864         NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
5865         convo.setConversationId(parent.getId(), "A");
5866         mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
5867                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5868         mHelper.deleteNotificationChannel(PKG_O, UID_O, "A", UID_O,
5869                 /* fromSystemOrSystemUi= */ false);
5870         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A",
5871                 /* includeDeleted= */ false)).isNull();
5872 
5873         NotificationChannel parentUpdate = cloneChannel(parent);
5874         parentUpdate.enableVibration(true);
5875         mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
5876                 UID_O, /* fromSystemOrSystemUi= */ true);
5877 
5878         NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5879                 "A", /* includeDeleted= */ true);
5880         assertThat(updatedChild.shouldVibrate()).isTrue();
5881     }
5882 
5883     @Test
testUpdateConversationParent_flagOff_doesNotUpdateConversations()5884     public void testUpdateConversationParent_flagOff_doesNotUpdateConversations() {
5885         SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
5886                 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, false);
5887         NotificationChannel parent =
5888                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
5889         mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
5890                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5891         NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
5892         convo.setConversationId(parent.getId(), "A");
5893         mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
5894                 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
5895         NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5896                 convo.getId(), /* includeDeleted= */ false);
5897         assertThat(originalChild.shouldVibrate()).isFalse();
5898 
5899         NotificationChannel parentUpdate = cloneChannel(parent);
5900         parentUpdate.enableVibration(true);
5901         mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
5902                 UID_O, /* fromSystemOrSystemUi= */ true);
5903 
5904         NotificationChannel untouchedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
5905                 "A", /* includeDeleted= */ false);
5906         assertThat(untouchedChild.shouldVibrate()).isFalse();
5907     }
5908 
5909     @Test
testInvalidMessageSent()5910     public void testInvalidMessageSent() {
5911         // create package preferences
5912         mHelper.canShowBadge(PKG_P, UID_P);
5913 
5914         // check default value
5915         assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P));
5916 
5917         // change it
5918         mHelper.setInvalidMessageSent(PKG_P, UID_P);
5919         assertTrue(mHelper.isInInvalidMsgState(PKG_P, UID_P));
5920         assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P));
5921     }
5922 
5923     @Test
testValidMessageSent()5924     public void testValidMessageSent() {
5925         // create package preferences
5926         mHelper.canShowBadge(PKG_P, UID_P);
5927 
5928         // get into the bad state
5929         mHelper.setInvalidMessageSent(PKG_P, UID_P);
5930 
5931         // and then fix it
5932         mHelper.setValidMessageSent(PKG_P, UID_P);
5933 
5934         assertTrue(mHelper.hasSentValidMsg(PKG_P, UID_P));
5935         assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P));
5936     }
5937 
5938     @Test
testUserDemotedInvalidMsgApp()5939     public void testUserDemotedInvalidMsgApp() {
5940         // create package preferences
5941         mHelper.canShowBadge(PKG_P, UID_P);
5942 
5943         // demotion means nothing before msg notif sent
5944         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
5945         assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
5946 
5947         // it's valid when incomplete msgs have been sent
5948         mHelper.setInvalidMessageSent(PKG_P, UID_P);
5949         assertTrue(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
5950 
5951         // and is invalid once complete msgs are sent
5952         mHelper.setValidMessageSent(PKG_P, UID_P);
5953         assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
5954     }
5955 
5956     @Test
testValidBubbleSent()5957     public void testValidBubbleSent() {
5958         // create package preferences
5959         mHelper.canShowBadge(PKG_P, UID_P);
5960         // false by default
5961         assertFalse(mHelper.hasSentValidBubble(PKG_P, UID_P));
5962 
5963         // set something valid was sent
5964         mHelper.setValidBubbleSent(PKG_P, UID_P);
5965         assertTrue(mHelper.hasSentValidBubble(PKG_P, UID_P));
5966     }
5967 
5968     @Test
testPullPackageChannelPreferencesStats()5969     public void testPullPackageChannelPreferencesStats() throws InvalidProtocolBufferException {
5970         String channelId = "parent";
5971         String name = "messages";
5972         NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
5973         mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false, UID_O, false);
5974         NotificationChannel channel =
5975                 new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT);
5976         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
5977         NotificationChannel fodderB = new NotificationChannel("b", "b", IMPORTANCE_HIGH);
5978         mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false, UID_O, false);
5979 
5980         ArrayList<StatsEvent> events = new ArrayList<>();
5981         mHelper.pullPackageChannelPreferencesStats(events);
5982 
5983         assertEquals("expected number of events", 3, events.size());
5984         for (StatsEvent ev : events) {
5985             // all of these events should be of PackageNotificationChannelPreferences type,
5986             // and therefore we expect the atom to have this field.
5987             AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
5988             assertTrue(atom.hasPackageNotificationChannelPreferences());
5989             PackageNotificationChannelPreferences p =
5990                     atom.getPackageNotificationChannelPreferences();
5991 
5992             // uid is shared across all channels; conversation & deleted are not set in any of
5993             // these channels; beyond that check individual channel properties
5994             assertEquals("uid", UID_O, p.getUid());
5995             assertFalse("is conversation", p.getIsConversation());
5996             assertFalse("is deleted", p.getIsDeleted());
5997 
5998             String eventChannelId = p.getChannelId();
5999             if (eventChannelId.equals(channelId)) {
6000                 assertEquals("channel name", name, p.getChannelName());
6001                 assertEquals("importance", IMPORTANCE_DEFAULT, p.getImportance());
6002                 assertFalse("is conversation", p.getIsConversation());
6003             } else if (eventChannelId.equals("a")) {
6004                 assertEquals("channel name", "a", p.getChannelName());
6005                 assertEquals("importance", IMPORTANCE_LOW, p.getImportance());
6006             } else if (eventChannelId.equals("b")){ // b
6007                 assertEquals("channel name", "b", p.getChannelName());
6008                 assertEquals("importance", IMPORTANCE_HIGH, p.getImportance());
6009             }
6010         }
6011     }
6012 
6013     @Test
testPullPackageChannelPreferencesStats_one_to_one()6014     public void testPullPackageChannelPreferencesStats_one_to_one()
6015             throws InvalidProtocolBufferException {
6016         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
6017         mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false);
6018         NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW);
6019         mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false);
6020         NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH);
6021         mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false, UID_O, false);
6022 
6023         List<String> channels = new LinkedList<>(Arrays.asList("a", "b", "c"));
6024 
6025         ArrayList<StatsEvent> events = new ArrayList<>();
6026         mHelper.pullPackageChannelPreferencesStats(events);
6027 
6028         assertEquals("total events", 3, events.size());
6029         for (StatsEvent ev : events) {
6030             AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
6031             assertTrue(atom.hasPackageNotificationChannelPreferences());
6032             PackageNotificationChannelPreferences p =
6033                     atom.getPackageNotificationChannelPreferences();
6034             String id = p.getChannelId();
6035             assertTrue("missing channel in the output", channels.contains(id));
6036             channels.remove(id);
6037         }
6038         assertTrue("unexpected channel in output", channels.isEmpty());
6039     }
6040 
6041     @Test
testPullPackageChannelPreferencesStats_conversation()6042     public void testPullPackageChannelPreferencesStats_conversation()
6043             throws InvalidProtocolBufferException {
6044         String conversationId = "friend";
6045 
6046         NotificationChannel parent =
6047                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
6048         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
6049 
6050         String channelId = String.format(
6051                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId);
6052         String name = "conversation";
6053         NotificationChannel friend = new NotificationChannel(channelId,
6054                 name, IMPORTANCE_DEFAULT);
6055         friend.setConversationId(parent.getId(), conversationId);
6056         mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, UID_O, false);
6057 
6058         ArrayList<StatsEvent> events = new ArrayList<>();
6059         mHelper.pullPackageChannelPreferencesStats(events);
6060 
6061         // In this case, we want to check the properties of the conversation channel (not parent)
6062         assertEquals("total events", 2, events.size());
6063         for (StatsEvent ev : events) {
6064             AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
6065             assertTrue(atom.hasPackageNotificationChannelPreferences());
6066             PackageNotificationChannelPreferences p =
6067                     atom.getPackageNotificationChannelPreferences();
6068 
6069             if (channelId.equals(p.getChannelId())) {
6070                 assertTrue("isConversation should be true", p.getIsConversation());
6071                 assertFalse("not demoted", p.getIsDemotedConversation());
6072                 assertFalse("not important", p.getIsImportantConversation());
6073             }
6074         }
6075     }
6076 
6077     @Test
testPullPackageChannelPreferencesStats_conversation_demoted()6078     public void testPullPackageChannelPreferencesStats_conversation_demoted()
6079             throws InvalidProtocolBufferException {
6080         NotificationChannel parent =
6081                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
6082         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
6083         String channelId = String.format(
6084                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend");
6085         NotificationChannel friend = new NotificationChannel(channelId,
6086                 "conversation", IMPORTANCE_DEFAULT);
6087         friend.setConversationId(parent.getId(), "friend");
6088         friend.setDemoted(true);
6089         mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, UID_O, false);
6090 
6091         ArrayList<StatsEvent> events = new ArrayList<>();
6092         mHelper.pullPackageChannelPreferencesStats(events);
6093 
6094         assertEquals("total events", 2, events.size());
6095         for (StatsEvent ev : events) {
6096             AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
6097             assertTrue(atom.hasPackageNotificationChannelPreferences());
6098             PackageNotificationChannelPreferences p =
6099                     atom.getPackageNotificationChannelPreferences();
6100             if (channelId.equals(p.getChannelId())) {
6101                 assertTrue("isConversation should be true", p.getIsConversation());
6102                 assertTrue("is demoted", p.getIsDemotedConversation());
6103                 assertFalse("not important", p.getIsImportantConversation());
6104             }
6105         }
6106     }
6107 
6108     @Test
testPullPackageChannelPreferencesStats_conversation_priority()6109     public void testPullPackageChannelPreferencesStats_conversation_priority()
6110             throws InvalidProtocolBufferException {
6111         NotificationChannel parent =
6112                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
6113         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
6114         String channelId = String.format(
6115                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend");
6116         NotificationChannel friend = new NotificationChannel(channelId,
6117                 "conversation", IMPORTANCE_DEFAULT);
6118         friend.setConversationId(parent.getId(), "friend");
6119         friend.setImportantConversation(true);
6120         mHelper.createNotificationChannel(PKG_O, UID_O, friend, false, false, SYSTEM_UID, true);
6121 
6122         ArrayList<StatsEvent> events = new ArrayList<>();
6123         mHelper.pullPackageChannelPreferencesStats(events);
6124 
6125         assertEquals("total events", 2, events.size());
6126         for (StatsEvent ev : events) {
6127             AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
6128             assertTrue(atom.hasPackageNotificationChannelPreferences());
6129             PackageNotificationChannelPreferences p =
6130                     atom.getPackageNotificationChannelPreferences();
6131             if (channelId.equals(p.getChannelId())) {
6132                 assertTrue("isConversation should be true", p.getIsConversation());
6133                 assertFalse("not demoted", p.getIsDemotedConversation());
6134                 assertTrue("is important", p.getIsImportantConversation());
6135             }
6136         }
6137     }
6138 
6139     @Test
testPullPackagePreferencesStats_postPermissionMigration()6140     public void testPullPackagePreferencesStats_postPermissionMigration()
6141             throws InvalidProtocolBufferException {
6142         // make sure there's at least one channel for each package we want to test
6143         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
6144         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false,
6145                 UID_N_MR1, false);
6146         NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
6147         mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false);
6148         NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
6149         mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false, UID_P, false);
6150 
6151         // build a collection of app permissions that should be passed in and used
6152         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
6153         appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
6154         appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, true)); // in local prefs
6155 
6156         // local preferences
6157         mHelper.canShowBadge(PKG_O, UID_O);
6158         mHelper.canShowBadge(PKG_P, UID_P);
6159 
6160         // expected output. format: uid -> importance, as only uid (and not package name)
6161         // is in PackageNotificationPreferences
6162         ArrayMap<Integer, Pair<Integer, Boolean>> expected = new ArrayMap<>();
6163         expected.put(UID_N_MR1, new Pair<>(IMPORTANCE_DEFAULT, false));
6164         expected.put(UID_O, new Pair<>(IMPORTANCE_NONE, true));         // banned by permissions
6165         expected.put(UID_P, new Pair<>(IMPORTANCE_UNSPECIFIED, false)); // default: unspecified
6166 
6167         ArrayList<StatsEvent> events = new ArrayList<>();
6168         mHelper.pullPackagePreferencesStats(events, appPermissions);
6169 
6170         assertEquals("total number of packages", 3, events.size());
6171         for (StatsEvent ev : events) {
6172             AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
6173             assertTrue(atom.hasPackageNotificationPreferences());
6174             PackageNotificationPreferences p = atom.getPackageNotificationPreferences();
6175             int uid = p.getUid();
6176 
6177             // if it's one of the expected ids, then make sure the importance matches
6178             assertTrue(expected.containsKey(uid));
6179             assertThat(expected.get(uid).first).isEqualTo(p.getImportance());
6180             assertThat(expected.get(uid).second).isEqualTo(p.getUserSetImportance());
6181         }
6182     }
6183 
6184     @Test
testUnlockNotificationChannelImportance()6185     public void testUnlockNotificationChannelImportance() {
6186         NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
6187         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
6188         channel.lockFields(USER_LOCKED_IMPORTANCE);
6189         assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
6190 
6191         mHelper.unlockNotificationChannelImportance(PKG_O, UID_O, channel.getId());
6192         assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
6193 
6194     }
6195 
6196     @Test
testUnlockAllNotificationChannels()6197     public void testUnlockAllNotificationChannels() {
6198         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
6199         mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false);
6200         NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
6201         mHelper.createNotificationChannel(PKG_P, UID_P, channelB, true, false, UID_P, false);
6202         NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH);
6203         mHelper.createNotificationChannel(PKG_P, UID_O, channelC, false, false, UID_O, false);
6204 
6205         channelA.lockFields(USER_LOCKED_IMPORTANCE);
6206         channelB.lockFields(USER_LOCKED_IMPORTANCE);
6207         channelC.lockFields(USER_LOCKED_IMPORTANCE);
6208 
6209         assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
6210         assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
6211         assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
6212 
6213         mHelper.unlockAllNotificationChannels();
6214         assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
6215         assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
6216         assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
6217     }
6218 
6219     @Test
createNotificationChannel_updateDifferent_requestsSort()6220     public void createNotificationChannel_updateDifferent_requestsSort() {
6221         NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT);
6222         mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false);
6223         clearInvocations(mHandler);
6224 
6225         NotificationChannel updated = new NotificationChannel("id", "Wow", IMPORTANCE_DEFAULT);
6226         mHelper.createNotificationChannel(PKG_P, 0, updated, true, false, 0, false);
6227 
6228         verify(mHandler).requestSort();
6229     }
6230 
6231     @Test
createNotificationChannel_updateSame_doesNotRequestSort()6232     public void createNotificationChannel_updateSame_doesNotRequestSort() {
6233         NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT);
6234         mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false);
6235         clearInvocations(mHandler);
6236 
6237         NotificationChannel same = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT);
6238         mHelper.createNotificationChannel(PKG_P, 0, same, true, false, 0, false);
6239 
6240         verifyZeroInteractions(mHandler);
6241     }
6242 
6243     @Test
updateNotificationChannel_different_requestsSort()6244     public void updateNotificationChannel_different_requestsSort() {
6245         NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT);
6246         mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false);
6247         clearInvocations(mHandler);
6248 
6249         NotificationChannel updated = new NotificationChannel("id", "Wow", IMPORTANCE_DEFAULT);
6250         mHelper.updateNotificationChannel(PKG_P, 0, updated, false, 0, false);
6251 
6252         verify(mHandler).requestSort();
6253     }
6254 
6255     @Test
updateNotificationChannel_same_doesNotRequestSort()6256     public void updateNotificationChannel_same_doesNotRequestSort() {
6257         NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT);
6258         mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false);
6259         clearInvocations(mHandler);
6260         // Note: Creating a NotificationChannel identical to the original is not equals(), because
6261         // of mOriginalImportance. So we create a "true copy" instead.
6262         NotificationChannel same = cloneChannel(original);
6263 
6264         mHelper.updateNotificationChannel(PKG_P, 0, same, false, 0, false);
6265 
6266         verifyZeroInteractions(mHandler);
6267     }
6268 
6269     @Test
setShowBadge_update_requestsSort()6270     public void setShowBadge_update_requestsSort() {
6271         mHelper.setShowBadge(PKG_P, 0, false);
6272 
6273         verify(mHandler).requestSort();
6274     }
6275 
6276     @Test
setShowBadge_same_doesNotRequestSort()6277     public void setShowBadge_same_doesNotRequestSort() {
6278         mHelper.setShowBadge(PKG_P, 0, true); // true == DEFAULT_SHOW_BADGE
6279 
6280         verifyZeroInteractions(mHandler);
6281     }
6282 
6283     @Test
testGetFsiState_appDidNotRequest_enumNotRequested()6284     public void testGetFsiState_appDidNotRequest_enumNotRequested() {
6285         final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
6286                 /* requestedFsiPermission */ false);
6287 
6288         assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED, fsiState);
6289     }
6290 
6291     @Test
testGetFsiState_permissionGranted_enumGranted()6292     public void testGetFsiState_permissionGranted_enumGranted() {
6293         when(mPermissionManager.checkPermissionForPreflight(any(), any()))
6294                 .thenReturn(PermissionManager.PERMISSION_GRANTED);
6295 
6296         final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
6297                 /* requestedFsiPermission= */ true);
6298 
6299         assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED, fsiState);
6300     }
6301 
6302     @Test
testGetFsiState_permissionSoftDenied_enumDenied()6303     public void testGetFsiState_permissionSoftDenied_enumDenied() {
6304         when(mPermissionManager.checkPermissionForPreflight(any(), any()))
6305                 .thenReturn(PermissionManager.PERMISSION_SOFT_DENIED);
6306 
6307         final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
6308                 /* requestedFsiPermission = */ true);
6309 
6310         assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED, fsiState);
6311     }
6312 
6313     @Test
testGetFsiState_permissionHardDenied_enumDenied()6314     public void testGetFsiState_permissionHardDenied_enumDenied() {
6315         when(mPermissionManager.checkPermissionForPreflight(any(), any()))
6316                 .thenReturn(PermissionManager.PERMISSION_HARD_DENIED);
6317 
6318         final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
6319                 /* requestedFsiPermission = */ true);
6320 
6321         assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED, fsiState);
6322     }
6323 
6324     @Test
testIsFsiPermissionUserSet_appDidNotRequest_false()6325     public void testIsFsiPermissionUserSet_appDidNotRequest_false() {
6326         final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
6327                 /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED,
6328                 /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET);
6329 
6330         assertFalse(isUserSet);
6331     }
6332 
6333     @Test
testIsFsiPermissionUserSet_userSet_true()6334     public void testIsFsiPermissionUserSet_userSet_true() {
6335         final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
6336                 /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED,
6337                 /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET);
6338 
6339         assertTrue(isUserSet);
6340     }
6341 
6342     @Test
testIsFsiPermissionUserSet_notUserSet_false()6343     public void testIsFsiPermissionUserSet_notUserSet_false() {
6344         final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
6345                 /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED,
6346                 /* currentPermissionFlags= */ ~PackageManager.FLAG_PERMISSION_USER_SET);
6347 
6348         assertFalse(isUserSet);
6349     }
6350 
6351     @Test
testGetNotificationChannelGroups_withChannelFilter_includeBlocked()6352     public void testGetNotificationChannelGroups_withChannelFilter_includeBlocked() {
6353         NotificationChannel channel =
6354                 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
6355         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
6356                 UID_N_MR1, false);
6357         // modifying same object, don't need to call updateNotificationChannel
6358         channel.setImportance(IMPORTANCE_NONE);
6359 
6360         NotificationChannel channel2 =
6361                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
6362         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false,
6363                 UID_N_MR1, false);
6364 
6365         NotificationChannel channel3 =
6366                 new NotificationChannel("id3", "name3", NotificationManager.IMPORTANCE_HIGH);
6367         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
6368                 UID_N_MR1, false);
6369 
6370         Set<String> filter = ImmutableSet.of("id3");
6371 
6372         NotificationChannelGroup actual = mHelper.getNotificationChannelGroups(
6373                 PKG_N_MR1, UID_N_MR1, false, true, false, true, filter).getList().get(0);
6374         assertEquals(2, actual.getChannels().size());
6375         assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id3")).count());
6376         assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count());
6377     }
6378 
6379     @Test
testGetNotificationChannelGroups_withChannelFilter_doNotIncludeBlocked()6380     public void testGetNotificationChannelGroups_withChannelFilter_doNotIncludeBlocked() {
6381         NotificationChannel channel =
6382                 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
6383         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false,
6384                 UID_N_MR1, false);
6385         // modifying same object, don't need to call updateNotificationChannel
6386         channel.setImportance(IMPORTANCE_NONE);
6387 
6388         NotificationChannel channel2 =
6389                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
6390         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false,
6391                 UID_N_MR1, false);
6392 
6393         NotificationChannel channel3 =
6394                 new NotificationChannel("id3", "name3", NotificationManager.IMPORTANCE_HIGH);
6395         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
6396                 UID_N_MR1, false);
6397 
6398         Set<String> filter = ImmutableSet.of("id3");
6399 
6400         NotificationChannelGroup actual = mHelper.getNotificationChannelGroups(
6401                 PKG_N_MR1, UID_N_MR1, false, true, false, false, filter).getList().get(0);
6402         assertEquals(1, actual.getChannels().size());
6403         assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id3")).count());
6404         assertEquals(0, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count());
6405     }
6406 
6407     @Test
6408     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testGetNotificationChannels_omitBundleChannels()6409     public void testGetNotificationChannels_omitBundleChannels() {
6410         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_NEWS);
6411 
6412         assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, false).getList()).isEmpty();
6413     }
6414 
6415     @Test
6416     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testNotificationBundles()6417     public void testNotificationBundles() {
6418         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_NEWS);
6419         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, NEWS_ID, false).getImportance())
6420                 .isEqualTo(IMPORTANCE_LOW);
6421         assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size())
6422                 .isEqualTo(1);
6423 
6424         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_SOCIAL_MEDIA);
6425         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, SOCIAL_MEDIA_ID, false).
6426                 getImportance()).isEqualTo(IMPORTANCE_LOW);
6427         assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size())
6428                 .isEqualTo(2);
6429 
6430         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_CONTENT_RECOMMENDATION);
6431         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, RECS_ID, false).getImportance())
6432                 .isEqualTo(IMPORTANCE_LOW);
6433         assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size())
6434                 .isEqualTo(3);
6435 
6436         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_PROMOTION);
6437         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, PROMOTIONS_ID, false)
6438                 .getImportance()).isEqualTo(IMPORTANCE_LOW);
6439         assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size())
6440                 .isEqualTo(4);
6441 
6442         // only the first 4 types are created; no others
6443         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_OTHER);
6444         assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size())
6445                 .isEqualTo(4);
6446     }
6447 
6448     @Test
6449     @DisableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testNotificationBundles_off_deletesData()6450     public void testNotificationBundles_off_deletesData() throws Exception {
6451         String xml = "<ranking version=\"1\">\n"
6452                 + "<package name=\"" + PKG_P + "\" uid=\"" + UID_P + "\">\n"
6453                 + "<channel id=\"android.app.social\" name=\"Social\" importance=\"2\"/>\n"
6454                 + "<channel id=\"android.app.news\" name=\"News\" importance=\"2\"/>\n"
6455                 + "<channel id=\"android.app.recs\" name=\"Recs\" importance=\"2\"/>\n"
6456                 + "<channel id=\"android.app.promotions\" name=\"Promos\" importance=\"2\"/>\n"
6457                 + "<channel id=\"keep.me\" name=\"name\" importance=\"2\" "
6458                 + "show_badge=\"true\" />\n"
6459                 + "</package></ranking>\n";
6460 
6461         loadByteArrayXml(xml.getBytes(), false, USER_SYSTEM);
6462 
6463         // verify 4 reserved channels are created
6464         assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, NEWS_ID, true)).isNull();
6465         assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, PROMOTIONS_ID, true)).isNull();
6466         assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, SOCIAL_MEDIA_ID, true)).isNull();
6467         assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, RECS_ID, true)).isNull();
6468         assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, "keep.me", false)
6469                 .getImportance()).isEqualTo(IMPORTANCE_LOW);
6470     }
6471 
6472     @Test
6473     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testNotificationBundles_appsCannotUpdate()6474     public void testNotificationBundles_appsCannotUpdate() {
6475         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_NEWS);
6476 
6477         NotificationChannel fromApp =
6478                 new NotificationChannel(NEWS_ID, "The best channel", IMPORTANCE_HIGH);
6479         mHelper.createNotificationChannel(PKG_O, UID_O, fromApp, true, false, UID_O, false);
6480 
6481         assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, NEWS_ID, false).getImportance())
6482                 .isEqualTo(IMPORTANCE_LOW);
6483     }
6484 
6485     @Test
6486     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testNotificationBundles_osCanAllowToBypassDnd()6487     public void testNotificationBundles_osCanAllowToBypassDnd() {
6488         mHelper.createReservedChannel(PKG_O, UID_O, TYPE_NEWS);
6489 
6490         NotificationChannel fromApp =
6491                 new NotificationChannel(NEWS_ID, "The best channel", IMPORTANCE_HIGH);
6492         mHelper.createNotificationChannel(PKG_O, UID_O, fromApp, true, false, UID_O, false);
6493     }
6494 
6495     @Test
6496     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
testUnDeleteBundleChannelsOnLoadIfNotUserChange()6497     public void testUnDeleteBundleChannelsOnLoadIfNotUserChange() throws Exception {
6498         // the public create/update methods should prevent this, so take advantage of the fact that
6499         // the object is in the same process
6500         mHelper.createReservedChannel(PKG_N_MR1, UID_N_MR1, TYPE_SOCIAL_MEDIA).setDeleted(true);
6501 
6502         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
6503                 UserHandle.USER_ALL, SOCIAL_MEDIA_ID);
6504 
6505         loadStreamXml(baos, false, UserHandle.USER_ALL);
6506 
6507         assertThat(mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, SOCIAL_MEDIA_ID, true)
6508                 .isDeleted()).isFalse();
6509     }
6510 
6511     @Test
testRestoredWithoutUid_threadSafety()6512     public void testRestoredWithoutUid_threadSafety() throws Exception {
6513         when(mPm.getPackageUidAsUser(anyString(), anyInt())).thenReturn(UNKNOWN_UID);
6514         when(mPm.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())).thenThrow(
6515                 new PackageManager.NameNotFoundException());
6516         when(mClock.millis()).thenReturn(System.currentTimeMillis());
6517         testThreadSafety(() -> {
6518             String id = "id";
6519             String xml = "<ranking version=\"1\">\n"
6520                     + "<package name=\"" + Thread.currentThread()+ "\" show_badge=\"true\">\n"
6521                     + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
6522                     + "show_badge=\"true\" />\n"
6523                     + "</package>\n"
6524                     + "<package name=\"" + PKG_P + "\" show_badge=\"true\">\n"
6525                     + "</package>\n"
6526                     + "</ranking>\n";
6527 
6528             try {
6529                 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
6530             } catch (Exception e) {
6531                 throw new RuntimeException(e);
6532             }
6533 
6534             // trigger a removal from the list
6535             mXmlHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_P},
6536                     new int[]{UNKNOWN_UID});
6537         }, 20, 50);
6538     }
6539 
6540     @Test
6541     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
6542     @DisableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
testNoAppHasPermissionToPromoteByDefault()6543     public void testNoAppHasPermissionToPromoteByDefault() {
6544         mHelper.setShowBadge(PKG_P, UID_P, true);
6545         assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isFalse();
6546     }
6547 
6548     @Test
6549     @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING,
6550             android.app.Flags.FLAG_UI_RICH_ONGOING})
testAllAppsHavePermissionToPromoteByDefault()6551     public void testAllAppsHavePermissionToPromoteByDefault() {
6552         mHelper.setShowBadge(PKG_P, UID_P, true);
6553         assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isTrue();
6554     }
6555 
6556     @Test
6557     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
testSetCanBePromoted()6558     public void testSetCanBePromoted() {
6559         mHelper.setCanBePromoted(PKG_P, UID_P, true, true);
6560         assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isTrue();
6561 
6562         mHelper.setCanBePromoted(PKG_P, UID_P, false, true);
6563         assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isFalse();
6564         verify(mHandler, never()).requestSort();
6565     }
6566 
6567     @Test
6568     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
testSetCanBePromoted_allowlistNotOverrideUser()6569     public void testSetCanBePromoted_allowlistNotOverrideUser() {
6570         mHelper.setCanBePromoted(PKG_P, UID_P, true, true);
6571         assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isTrue();
6572 
6573         mHelper.setCanBePromoted(PKG_P, UID_P, false, false);
6574         assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isTrue();
6575     }
6576 }
6577