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