• 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.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
22 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
23 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
24 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
25 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
26 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
27 import static android.app.NotificationManager.IMPORTANCE_HIGH;
28 import static android.app.NotificationManager.IMPORTANCE_LOW;
29 import static android.app.NotificationManager.IMPORTANCE_MAX;
30 import static android.app.NotificationManager.IMPORTANCE_NONE;
31 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
32 import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION;
33 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
34 import static android.os.UserHandle.USER_SYSTEM;
35 import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
36 
37 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
38 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
39 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER;
40 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER;
41 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IMPORTANCE_FIELD_NUMBER;
42 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_CONVERSATION_FIELD_NUMBER;
43 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DELETED_FIELD_NUMBER;
44 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DEMOTED_CONVERSATION_FIELD_NUMBER;
45 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_IMPORTANT_CONVERSATION_FIELD_NUMBER;
46 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.UID_FIELD_NUMBER;
47 import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
48 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
49 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT;
50 import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
51 
52 import static com.google.common.truth.Truth.assertThat;
53 
54 import static junit.framework.Assert.assertNull;
55 import static junit.framework.Assert.fail;
56 
57 import static org.junit.Assert.assertEquals;
58 import static org.junit.Assert.assertFalse;
59 import static org.junit.Assert.assertNotNull;
60 import static org.junit.Assert.assertTrue;
61 import static org.mockito.ArgumentMatchers.any;
62 import static org.mockito.ArgumentMatchers.anyInt;
63 import static org.mockito.ArgumentMatchers.anyString;
64 import static org.mockito.ArgumentMatchers.eq;
65 import static org.mockito.Mockito.doAnswer;
66 import static org.mockito.Mockito.doReturn;
67 import static org.mockito.Mockito.mock;
68 import static org.mockito.Mockito.never;
69 import static org.mockito.Mockito.reset;
70 import static org.mockito.Mockito.times;
71 import static org.mockito.Mockito.verify;
72 import static org.mockito.Mockito.when;
73 
74 import android.app.AppOpsManager;
75 import android.app.Notification;
76 import android.app.NotificationChannel;
77 import android.app.NotificationChannelGroup;
78 import android.app.NotificationManager;
79 import android.content.AttributionSource;
80 import android.content.ContentProvider;
81 import android.content.ContentResolver;
82 import android.content.Context;
83 import android.content.IContentProvider;
84 import android.content.pm.ApplicationInfo;
85 import android.content.pm.PackageInfo;
86 import android.content.pm.PackageManager;
87 import android.content.pm.Signature;
88 import android.content.pm.UserInfo;
89 import android.content.res.Resources;
90 import android.graphics.Color;
91 import android.media.AudioAttributes;
92 import android.net.Uri;
93 import android.os.AsyncTask;
94 import android.os.Build;
95 import android.os.Bundle;
96 import android.os.RemoteCallback;
97 import android.os.RemoteException;
98 import android.os.UserHandle;
99 import android.os.UserManager;
100 import android.provider.Settings;
101 import android.provider.Settings.Global;
102 import android.provider.Settings.Secure;
103 import android.service.notification.ConversationChannelWrapper;
104 import android.service.notification.nano.RankingHelperProto;
105 import android.test.suitebuilder.annotation.SmallTest;
106 import android.testing.TestableContentResolver;
107 import android.text.format.DateUtils;
108 import android.util.ArrayMap;
109 import android.util.ArraySet;
110 import android.util.IntArray;
111 import android.util.Pair;
112 import android.util.StatsEvent;
113 import android.util.TypedXmlPullParser;
114 import android.util.TypedXmlSerializer;
115 import android.util.Xml;
116 import android.util.proto.ProtoOutputStream;
117 
118 import androidx.test.InstrumentationRegistry;
119 import androidx.test.runner.AndroidJUnit4;
120 
121 import com.android.os.AtomsProto.PackageNotificationPreferences;
122 import com.android.server.UiServiceTestCase;
123 import com.android.server.notification.PermissionHelper.PackagePermission;
124 
125 import com.google.common.collect.ImmutableList;
126 
127 import org.json.JSONArray;
128 import org.json.JSONObject;
129 import org.junit.Before;
130 import org.junit.Test;
131 import org.junit.runner.RunWith;
132 import org.mockito.Mock;
133 import org.mockito.MockitoAnnotations;
134 
135 import java.io.BufferedInputStream;
136 import java.io.BufferedOutputStream;
137 import java.io.ByteArrayInputStream;
138 import java.io.ByteArrayOutputStream;
139 import java.io.PrintWriter;
140 import java.io.StringWriter;
141 import java.util.ArrayList;
142 import java.util.Arrays;
143 import java.util.HashMap;
144 import java.util.LinkedList;
145 import java.util.List;
146 import java.util.Map;
147 import java.util.Objects;
148 import java.util.Set;
149 import java.util.concurrent.ThreadLocalRandom;
150 
151 @SmallTest
152 @RunWith(AndroidJUnit4.class)
153 public class PreferencesHelperTest extends UiServiceTestCase {
154     private static final int UID_N_MR1 = 0;
155     private static final int UID_HEADLESS = 1000000;
156     private static final UserHandle USER = UserHandle.of(0);
157     private static final int UID_O = 1111;
158     private static final int UID_P = 2222;
159     private static final String SYSTEM_PKG = "android";
160     private static final int SYSTEM_UID = 1000;
161     private static final UserHandle USER2 = UserHandle.of(10);
162     private static final String TEST_CHANNEL_ID = "test_channel_id";
163     private static final String TEST_AUTHORITY = "test";
164     private static final Uri SOUND_URI =
165             Uri.parse("content://" + TEST_AUTHORITY + "/internal/audio/media/10");
166     private static final Uri CANONICAL_SOUND_URI =
167             Uri.parse("content://" + TEST_AUTHORITY
168                     + "/internal/audio/media/10?title=Test&canonical=1");
169 
170     @Mock PermissionHelper mPermissionHelper;
171     @Mock RankingHandler mHandler;
172     @Mock PackageManager mPm;
173     IContentProvider mTestIContentProvider;
174     @Mock Context mContext;
175     @Mock ZenModeHelper mMockZenModeHelper;
176     @Mock AppOpsManager mAppOpsManager;
177 
178     private NotificationManager.Policy mTestNotificationPolicy;
179 
180     private PreferencesHelper mHelper;
181     private AudioAttributes mAudioAttributes;
182     private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
183     private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
184 
185     @Before
setUp()186     public void setUp() throws Exception {
187         MockitoAnnotations.initMocks(this);
188 
189         final ApplicationInfo legacy = new ApplicationInfo();
190         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
191         final ApplicationInfo upgrade = new ApplicationInfo();
192         upgrade.targetSdkVersion = Build.VERSION_CODES.O;
193         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
194         when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(upgrade);
195         when(mPm.getApplicationInfoAsUser(eq(PKG_P), anyInt(), anyInt())).thenReturn(upgrade);
196         when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade);
197         when(mPm.getPackageUidAsUser(eq(PKG_N_MR1), anyInt())).thenReturn(UID_N_MR1);
198         when(mPm.getPackageUidAsUser(eq(PKG_O), anyInt())).thenReturn(UID_O);
199         when(mPm.getPackageUidAsUser(eq(PKG_P), anyInt())).thenReturn(UID_P);
200         when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID);
201         PackageInfo info = mock(PackageInfo.class);
202         info.signatures = new Signature[] {mock(Signature.class)};
203         when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info);
204         when(mPm.getPackageInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt()))
205                 .thenReturn(mock(PackageInfo.class));
206         when(mContext.getResources()).thenReturn(
207                 InstrumentationRegistry.getContext().getResources());
208         when(mContext.getContentResolver()).thenReturn(
209                 InstrumentationRegistry.getContext().getContentResolver());
210         when(mContext.getPackageManager()).thenReturn(mPm);
211         when(mContext.getApplicationInfo()).thenReturn(legacy);
212         // most tests assume badging is enabled
213         TestableContentResolver contentResolver = getContext().getContentResolver();
214         contentResolver.setFallbackToExisting(false);
215         Secure.putIntForUser(contentResolver,
216                 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1));
217         Secure.putIntForUser(contentResolver, Secure.NOTIFICATION_BUBBLES, 1,
218                 UserHandle.getUserId(UID_N_MR1));
219 
220         ContentProvider testContentProvider = mock(ContentProvider.class);
221         mTestIContentProvider = mock(IContentProvider.class, invocation -> {
222             throw new UnsupportedOperationException("unimplemented mock method");
223         });
224         doAnswer(invocation -> {
225             AttributionSource attributionSource = invocation.getArgument(0);
226             Uri uri = invocation.getArgument(1);
227             RemoteCallback cb = invocation.getArgument(2);
228             IContentProvider mock = (IContentProvider) (invocation.getMock());
229             AsyncTask.SERIAL_EXECUTOR.execute(() -> {
230                 final Bundle bundle = new Bundle();
231                 try {
232                     bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
233                             mock.canonicalize(attributionSource, uri));
234                 } catch (RemoteException e) { /* consume */ }
235                 cb.sendResult(bundle);
236             });
237             return null;
238         }).when(mTestIContentProvider).canonicalizeAsync(any(), any(), any());
239         doAnswer(invocation -> {
240             AttributionSource attributionSource = invocation.getArgument(0);
241             Uri uri = invocation.getArgument(1);
242             RemoteCallback cb = invocation.getArgument(2);
243             IContentProvider mock = (IContentProvider) (invocation.getMock());
244             AsyncTask.SERIAL_EXECUTOR.execute(() -> {
245                 final Bundle bundle = new Bundle();
246                 try {
247                     bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
248                             mock.uncanonicalize(attributionSource, uri));
249                 } catch (RemoteException e) { /* consume */ }
250                 cb.sendResult(bundle);
251             });
252             return null;
253         }).when(mTestIContentProvider).uncanonicalizeAsync(any(), any(), any());
254         doAnswer(invocation -> {
255             Uri uri = invocation.getArgument(0);
256             RemoteCallback cb = invocation.getArgument(1);
257             IContentProvider mock = (IContentProvider) (invocation.getMock());
258             AsyncTask.SERIAL_EXECUTOR.execute(() -> {
259                 final Bundle bundle = new Bundle();
260                 try {
261                     bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, mock.getType(uri));
262                 } catch (RemoteException e) { /* consume */ }
263                 cb.sendResult(bundle);
264             });
265             return null;
266         }).when(mTestIContentProvider).getTypeAsync(any(), any());
267 
268         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
269         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
270 
271         doReturn(CANONICAL_SOUND_URI)
272                 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
273         doReturn(CANONICAL_SOUND_URI)
274                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
275         doReturn(SOUND_URI)
276                 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
277 
278         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
279                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
280         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
281         when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(),
282                 anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT);
283 
284         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
285         appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));
286         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(true, false));
287         appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
288 
289         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
290                 .thenReturn(appPermissions);
291 
292         mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
293 
294         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
295                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
296         resetZenModeHelper();
297 
298         mAudioAttributes = new AudioAttributes.Builder()
299                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
300                 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
301                 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
302                 .build();
303 
304         // make sure that the settings for review notification permissions are unset to begin with
305         Settings.Global.putInt(mContext.getContentResolver(),
306                 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
307                 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN);
308     }
309 
writeXmlAndPurge( String pkg, int uid, boolean forBackup, int userId, String... channelIds)310     private ByteArrayOutputStream writeXmlAndPurge(
311             String pkg, int uid, boolean forBackup, int userId, String... channelIds)
312             throws Exception {
313         TypedXmlSerializer serializer = Xml.newFastSerializer();
314         ByteArrayOutputStream baos = new ByteArrayOutputStream();
315         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
316         serializer.startDocument(null, true);
317         mHelper.writeXml(serializer, forBackup, userId);
318         serializer.endDocument();
319         serializer.flush();
320         for (String channelId : channelIds) {
321             mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
322         }
323         return baos;
324     }
325 
loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId)326     private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId)
327             throws Exception {
328         loadByteArrayXml(stream.toByteArray(), forRestore, userId);
329     }
330 
loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)331     private void loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)
332             throws Exception {
333         TypedXmlPullParser parser = Xml.newFastPullParser();
334         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null);
335         parser.nextTag();
336         mHelper.readXml(parser, forRestore, userId);
337     }
338 
compareChannels(NotificationChannel expected, NotificationChannel actual)339     private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
340         assertEquals(expected.getId(), actual.getId());
341         assertEquals(expected.getName(), actual.getName());
342         assertEquals(expected.getDescription(), actual.getDescription());
343         assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
344         assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
345         assertEquals(expected.getImportance(), actual.getImportance());
346         assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
347         assertEquals(expected.getSound(), actual.getSound());
348         assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
349         assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
350         assertEquals(expected.getGroup(), actual.getGroup());
351         assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes());
352         assertEquals(expected.getLightColor(), actual.getLightColor());
353         assertEquals(expected.getParentChannelId(), actual.getParentChannelId());
354         assertEquals(expected.getConversationId(), actual.getConversationId());
355         assertEquals(expected.isDemoted(), actual.isDemoted());
356     }
357 
compareChannelsParentChild(NotificationChannel parent, NotificationChannel actual, String conversationId)358     private void compareChannelsParentChild(NotificationChannel parent,
359             NotificationChannel actual, String conversationId) {
360         assertEquals(parent.getName(), actual.getName());
361         assertEquals(parent.getDescription(), actual.getDescription());
362         assertEquals(parent.shouldVibrate(), actual.shouldVibrate());
363         assertEquals(parent.shouldShowLights(), actual.shouldShowLights());
364         assertEquals(parent.getImportance(), actual.getImportance());
365         assertEquals(parent.getLockscreenVisibility(), actual.getLockscreenVisibility());
366         assertEquals(parent.getSound(), actual.getSound());
367         assertEquals(parent.canBypassDnd(), actual.canBypassDnd());
368         assertTrue(Arrays.equals(parent.getVibrationPattern(), actual.getVibrationPattern()));
369         assertEquals(parent.getGroup(), actual.getGroup());
370         assertEquals(parent.getAudioAttributes(), actual.getAudioAttributes());
371         assertEquals(parent.getLightColor(), actual.getLightColor());
372         assertEquals(parent.getId(), actual.getParentChannelId());
373         assertEquals(conversationId, actual.getConversationId());
374     }
375 
compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual)376     private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
377         assertEquals(expected.getId(), actual.getId());
378         assertEquals(expected.getName(), actual.getName());
379         assertEquals(expected.getDescription(), actual.getDescription());
380         assertEquals(expected.isBlocked(), actual.isBlocked());
381     }
382 
getChannel()383     private NotificationChannel getChannel() {
384         return new NotificationChannel("id", "name", IMPORTANCE_LOW);
385     }
386 
findChannel(List<NotificationChannel> channels, String id)387     private NotificationChannel findChannel(List<NotificationChannel> channels, String id) {
388         for (NotificationChannel channel : channels) {
389             if (channel.getId().equals(id)) {
390                 return channel;
391             }
392         }
393         return null;
394     }
395 
resetZenModeHelper()396     private void resetZenModeHelper() {
397         reset(mMockZenModeHelper);
398         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
399     }
400 
setUpPackageWithUid(String packageName, int uid)401     private void setUpPackageWithUid(String packageName, int uid) throws Exception {
402         when(mPm.getApplicationInfoAsUser(eq(packageName), anyInt(), anyInt()))
403                 .thenReturn(new ApplicationInfo());
404         when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
405     }
406 
407     @Test
testWriteXml_onlyBackupsTargetUser()408     public void testWriteXml_onlyBackupsTargetUser() throws Exception {
409         // Setup package notifications.
410         String package0 = "test.package.user0";
411         int uid0 = 1001;
412         setUpPackageWithUid(package0, uid0);
413         NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
414         assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
415 
416         String package10 = "test.package.user10";
417         int uid10 = 1001001;
418         setUpPackageWithUid(package10, uid10);
419         NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH);
420         assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false));
421 
422         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
423         appPermissions.put(new Pair(uid0, package0), new Pair(false, false));
424         appPermissions.put(new Pair(uid10, package10), new Pair(true, false));
425 
426         when(mPermissionHelper.getNotificationPermissionValues(10))
427                 .thenReturn(appPermissions);
428 
429         ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10);
430 
431         // Reset state.
432         mHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0});
433         mHelper.onPackagesChanged(true, 10, new String[] {package10}, new int[] {uid10});
434 
435         // Parse backup data.
436         loadStreamXml(baos, true, 0);
437         loadStreamXml(baos, true, 10);
438 
439         assertEquals(
440                 channel10,
441                 mHelper.getNotificationChannel(package10, uid10, channel10.getId(), false));
442         assertNull(mHelper.getNotificationChannel(package0, uid0, channel0.getId(), false));
443     }
444 
445     @Test
testReadXml_onlyRestoresTargetUser()446     public void testReadXml_onlyRestoresTargetUser() throws Exception {
447         // Setup package in user 0.
448         String package0 = "test.package.user0";
449         int uid0 = 1001;
450         setUpPackageWithUid(package0, uid0);
451         NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
452         assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
453 
454         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
455         appPermissions.put(new Pair(uid0, package0), new Pair(true, false));
456 
457         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
458                 .thenReturn(appPermissions);
459 
460         ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0);
461 
462         // Reset state.
463         mHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0});
464 
465         // Restore should convert the uid according to the target user.
466         int expectedUid = 1001001;
467         setUpPackageWithUid(package0, expectedUid);
468         // Parse backup data.
469         loadStreamXml(baos, true, 10);
470 
471         assertEquals(
472                 channel0,
473                 mHelper.getNotificationChannel(package0, expectedUid, channel0.getId(), false));
474         assertNull(mHelper.getNotificationChannel(package0, uid0, channel0.getId(), false));
475     }
476 
477     @Test
testChannelXml()478     public void testChannelXml() throws Exception {
479         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
480         ncg.setBlocked(true);
481         ncg.setDescription("group desc");
482         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
483         NotificationChannel channel1 =
484                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
485         NotificationChannel channel2 =
486                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
487         channel2.setDescription("descriptions for all");
488         channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
489         channel2.enableLights(true);
490         channel2.setBypassDnd(true);
491         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
492         channel2.enableVibration(true);
493         channel2.setGroup(ncg.getId());
494         channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
495         channel2.setLightColor(Color.BLUE);
496         channel2.setConversationId("id1", "conversation");
497         channel2.setDemoted(true);
498 
499         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
500         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
501         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false));
502         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false));
503 
504         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
505 
506         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
507                 UserHandle.USER_ALL, channel1.getId(), channel2.getId(),
508                 NotificationChannel.DEFAULT_CHANNEL_ID);
509         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
510                 UID_N_MR1});
511 
512         loadStreamXml(baos, false, UserHandle.USER_ALL);
513 
514         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
515         assertEquals(channel1,
516                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
517         compareChannels(channel2,
518                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
519 
520         List<NotificationChannelGroup> actualGroups = mHelper.getNotificationChannelGroups(
521                 PKG_N_MR1, UID_N_MR1, false, true, false).getList();
522         boolean foundNcg = false;
523         for (NotificationChannelGroup actual : actualGroups) {
524             if (ncg.getId().equals(actual.getId())) {
525                 foundNcg = true;
526                 compareGroups(ncg, actual);
527             } else if (ncg2.getId().equals(actual.getId())) {
528                 compareGroups(ncg2, actual);
529             }
530         }
531         assertTrue(foundNcg);
532 
533         boolean foundChannel2Group = false;
534         for (NotificationChannelGroup actual : actualGroups) {
535             if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
536                 foundChannel2Group = true;
537                 break;
538             }
539         }
540         assertTrue(foundChannel2Group);
541     }
542 
543     @Test
testChannelXmlForBackup()544     public void testChannelXmlForBackup() throws Exception {
545         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
546         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
547         NotificationChannel channel1 =
548                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
549         NotificationChannel channel2 =
550                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
551         channel2.setDescription("descriptions for all");
552         channel2.setSound(SOUND_URI, mAudioAttributes);
553         channel2.enableLights(true);
554         channel2.setBypassDnd(true);
555         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
556         channel2.enableVibration(false);
557         channel2.setGroup(ncg.getId());
558         channel2.setLightColor(Color.BLUE);
559         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
560         channel3.enableVibration(true);
561 
562         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
563         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
564         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
565         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
566         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
567         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
568 
569         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
570         mHelper.setInvalidMessageSent(PKG_P, UID_P);
571         mHelper.setValidMessageSent(PKG_P, UID_P);
572         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
573         mHelper.setValidBubbleSent(PKG_P, UID_P);
574 
575         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
576                 USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
577                 NotificationChannel.DEFAULT_CHANNEL_ID);
578         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1, PKG_O},
579                 new int[]{UID_N_MR1, UID_O});
580 
581         mHelper.setShowBadge(PKG_O, UID_O, true);
582 
583         loadStreamXml(baos, true, USER_SYSTEM);
584 
585         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
586         assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P));
587         assertFalse(mHelper.hasSentInvalidMsg(PKG_N_MR1, UID_N_MR1));
588         assertTrue(mHelper.hasSentValidMsg(PKG_P, UID_P));
589         assertTrue(mHelper.didUserEverDemoteInvalidMsgApp(PKG_P, UID_P));
590         assertTrue(mHelper.hasSentValidBubble(PKG_P, UID_P));
591         assertEquals(channel1,
592                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
593         compareChannels(channel2,
594                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
595         compareChannels(channel3,
596                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
597 
598         List<NotificationChannelGroup> actualGroups = mHelper.getNotificationChannelGroups(
599                 PKG_N_MR1, UID_N_MR1, false, true, false).getList();
600         boolean foundNcg = false;
601         for (NotificationChannelGroup actual : actualGroups) {
602             if (ncg.getId().equals(actual.getId())) {
603                 foundNcg = true;
604                 compareGroups(ncg, actual);
605             } else if (ncg2.getId().equals(actual.getId())) {
606                 compareGroups(ncg2, actual);
607             }
608         }
609         assertTrue(foundNcg);
610 
611         boolean foundChannel2Group = false;
612         for (NotificationChannelGroup actual : actualGroups) {
613             if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
614                 foundChannel2Group = true;
615                 break;
616             }
617         }
618         assertTrue(foundChannel2Group);
619     }
620 
621     @Test
testReadXml_oldXml_migrates()622     public void testReadXml_oldXml_migrates() throws Exception {
623         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
624                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
625 
626         String xml = "<ranking version=\"2\">\n"
627                 + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1
628                 + "\" show_badge=\"true\">\n"
629                 + "<channel id=\"idn\" name=\"name\" importance=\"2\" />\n"
630                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
631                 + "</package>\n"
632                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" importance=\"0\">\n"
633                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
634                 + "</package>\n"
635                 + "<package name=\"" + PKG_P + "\" uid=\"" + UID_P + "\" importance=\"2\">\n"
636                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
637                 + "</package>\n"
638                 + "</ranking>\n";
639 
640         loadByteArrayXml(xml.getBytes(), false, USER_SYSTEM);
641 
642         // expected values
643         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
644         idn.setSound(null, new AudioAttributes.Builder()
645                 .setUsage(USAGE_NOTIFICATION)
646                 .setContentType(CONTENT_TYPE_SONIFICATION)
647                 .setFlags(0)
648                 .build());
649         idn.setShowBadge(false);
650         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
651         ido.setShowBadge(true);
652         ido.setSound(null, new AudioAttributes.Builder()
653                 .setUsage(USAGE_NOTIFICATION)
654                 .setContentType(CONTENT_TYPE_SONIFICATION)
655                 .setFlags(0)
656                 .build());
657         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
658         idp.lockFields(2);
659         idp.setSound(null, new AudioAttributes.Builder()
660                 .setUsage(USAGE_NOTIFICATION)
661                 .setContentType(CONTENT_TYPE_SONIFICATION)
662                 .setFlags(0)
663                 .build());
664 
665         // Notifications enabled, not user set
666         PackagePermission nMr1Expected = new PackagePermission(PKG_N_MR1, 0, true, false);
667         // Notifications not enabled, so user set
668         PackagePermission oExpected = new PackagePermission(PKG_O, 0, false, true);
669         // Notifications enabled, user set b/c channel modified
670         PackagePermission pExpected = new PackagePermission(PKG_P, 0, true, true);
671 
672         // verify data
673         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
674 
675         assertEquals(idn, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
676         compareChannels(ido, mHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
677         compareChannels(idp, mHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
678 
679         verify(mPermissionHelper).setNotificationPermission(nMr1Expected);
680         verify(mPermissionHelper).setNotificationPermission(oExpected);
681         verify(mPermissionHelper).setNotificationPermission(pExpected);
682 
683         // verify that we also write a state for review_permissions_notification to eventually
684         // show a notification
685         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW,
686                 Settings.Global.getInt(mContext.getContentResolver(),
687                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
688                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
689     }
690 
691     @Test
testReadXml_oldXml_backup_migratesWhenPkgInstalled()692     public void testReadXml_oldXml_backup_migratesWhenPkgInstalled() throws Exception {
693         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
694                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
695 
696         when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
697         when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
698         when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
699         when(mPm.getApplicationInfoAsUser(eq("pkg1"), anyInt(), anyInt())).thenThrow(
700                 new PackageManager.NameNotFoundException());
701         when(mPm.getApplicationInfoAsUser(eq("pkg2"), anyInt(), anyInt())).thenThrow(
702                 new PackageManager.NameNotFoundException());
703         when(mPm.getApplicationInfoAsUser(eq("pkg3"), anyInt(), anyInt())).thenThrow(
704                 new PackageManager.NameNotFoundException());
705 
706         String xml = "<ranking version=\"2\">\n"
707                 + "<package name=\"pkg1\" show_badge=\"true\">\n"
708                 + "<channel id=\"idn\" name=\"name\" importance=\"2\" />\n"
709                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
710                 + "</package>\n"
711                 + "<package name=\"pkg2\" importance=\"0\">\n"
712                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
713                 + "</package>\n"
714                 + "<package name=\"pkg3\" importance=\"2\">\n"
715                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
716                 + "</package>\n"
717                 + "</ranking>\n";
718         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
719         idn.setSound(null, new AudioAttributes.Builder()
720                 .setUsage(USAGE_NOTIFICATION)
721                 .setContentType(CONTENT_TYPE_SONIFICATION)
722                 .setFlags(0)
723                 .build());
724         idn.setShowBadge(false);
725         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
726         ido.setShowBadge(true);
727         ido.setSound(null, new AudioAttributes.Builder()
728                 .setUsage(USAGE_NOTIFICATION)
729                 .setContentType(CONTENT_TYPE_SONIFICATION)
730                 .setFlags(0)
731                 .build());
732         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
733         idp.lockFields(2);
734         idp.setSound(null, new AudioAttributes.Builder()
735                 .setUsage(USAGE_NOTIFICATION)
736                 .setContentType(CONTENT_TYPE_SONIFICATION)
737                 .setFlags(0)
738                 .build());
739 
740         // Notifications enabled, not user set
741         PackagePermission pkg1Expected = new PackagePermission("pkg1", 0, true, false);
742         // Notifications not enabled, so user set
743         PackagePermission pkg2Expected = new PackagePermission("pkg2", 0, false, true);
744         // Notifications enabled, user set b/c channel modified
745         PackagePermission pkg3Expected = new PackagePermission("pkg3", 0, true, true);
746 
747         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
748 
749         verify(mPermissionHelper, never()).setNotificationPermission(any());
750 
751         when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(11);
752         when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(12);
753         when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(13);
754 
755         mHelper.onPackagesChanged(
756                 false, 0, new String[]{"pkg1", "pkg2", "pkg3"}, new int[] {11, 12, 13});
757 
758         assertTrue(mHelper.canShowBadge("pkg1", 11));
759 
760         assertEquals(idn, mHelper.getNotificationChannel("pkg1", 11, idn.getId(), false));
761         compareChannels(ido, mHelper.getNotificationChannel("pkg2", 12, ido.getId(), false));
762         compareChannels(idp, mHelper.getNotificationChannel("pkg3", 13, idp.getId(), false));
763 
764         verify(mPermissionHelper).setNotificationPermission(pkg1Expected);
765         verify(mPermissionHelper).setNotificationPermission(pkg2Expected);
766         verify(mPermissionHelper).setNotificationPermission(pkg3Expected);
767     }
768 
769     @Test
testReadXml_newXml_noMigration_showPermissionNotification()770     public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
771         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
772                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
773 
774         String xml = "<ranking version=\"3\">\n"
775                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
776                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
777                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
778                 + "</package>\n"
779                 + "<package name=\"" + PKG_O + "\" >\n"
780                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
781                 + "</package>\n"
782                 + "<package name=\"" + PKG_P + "\" >\n"
783                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
784                 + "</package>\n"
785                 + "</ranking>\n";
786         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
787         idn.setSound(null, new AudioAttributes.Builder()
788                 .setUsage(USAGE_NOTIFICATION)
789                 .setContentType(CONTENT_TYPE_SONIFICATION)
790                 .setFlags(0)
791                 .build());
792         idn.setShowBadge(false);
793         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
794         ido.setShowBadge(true);
795         ido.setSound(null, new AudioAttributes.Builder()
796                 .setUsage(USAGE_NOTIFICATION)
797                 .setContentType(CONTENT_TYPE_SONIFICATION)
798                 .setFlags(0)
799                 .build());
800         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
801         idp.lockFields(2);
802         idp.setSound(null, new AudioAttributes.Builder()
803                 .setUsage(USAGE_NOTIFICATION)
804                 .setContentType(CONTENT_TYPE_SONIFICATION)
805                 .setFlags(0)
806                 .build());
807 
808         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
809 
810         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
811 
812         assertEquals(idn, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
813         compareChannels(ido, mHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
814         compareChannels(idp, mHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
815 
816         verify(mPermissionHelper, never()).setNotificationPermission(any());
817 
818         // verify that we do, however, write a state for review_permissions_notification to
819         // eventually show a notification, since this XML version is older than the notification
820         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW,
821                 Settings.Global.getInt(mContext.getContentResolver(),
822                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
823                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
824     }
825 
826     @Test
testReadXml_newXml_permissionNotificationOff()827     public void testReadXml_newXml_permissionNotificationOff() throws Exception {
828         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
829                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
830 
831         String xml = "<ranking version=\"3\">\n"
832                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
833                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
834                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
835                 + "</package>\n"
836                 + "<package name=\"" + PKG_O + "\" >\n"
837                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
838                 + "</package>\n"
839                 + "<package name=\"" + PKG_P + "\" >\n"
840                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
841                 + "</package>\n"
842                 + "</ranking>\n";
843         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
844         idn.setSound(null, new AudioAttributes.Builder()
845                 .setUsage(USAGE_NOTIFICATION)
846                 .setContentType(CONTENT_TYPE_SONIFICATION)
847                 .setFlags(0)
848                 .build());
849         idn.setShowBadge(false);
850         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
851         ido.setShowBadge(true);
852         ido.setSound(null, new AudioAttributes.Builder()
853                 .setUsage(USAGE_NOTIFICATION)
854                 .setContentType(CONTENT_TYPE_SONIFICATION)
855                 .setFlags(0)
856                 .build());
857         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
858         idp.lockFields(2);
859         idp.setSound(null, new AudioAttributes.Builder()
860                 .setUsage(USAGE_NOTIFICATION)
861                 .setContentType(CONTENT_TYPE_SONIFICATION)
862                 .setFlags(0)
863                 .build());
864 
865         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
866 
867         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
868 
869         assertEquals(idn, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
870         compareChannels(ido, mHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
871         compareChannels(idp, mHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
872 
873         verify(mPermissionHelper, never()).setNotificationPermission(any());
874 
875         // while this is the same case as above, if the permission helper is set to not show the
876         // review permissions notification it should not write anything to the settings int
877         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN,
878                 Settings.Global.getInt(mContext.getContentResolver(),
879                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
880                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
881     }
882 
883     @Test
testReadXml_newXml_noMigration_noPermissionNotification()884     public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
885         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
886                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
887 
888         String xml = "<ranking version=\"4\">\n"
889                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
890                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
891                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n"
892                 + "</package>\n"
893                 + "<package name=\"" + PKG_O + "\" >\n"
894                 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n"
895                 + "</package>\n"
896                 + "<package name=\"" + PKG_P + "\" >\n"
897                 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n"
898                 + "</package>\n"
899                 + "</ranking>\n";
900         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
901         idn.setSound(null, new AudioAttributes.Builder()
902                 .setUsage(USAGE_NOTIFICATION)
903                 .setContentType(CONTENT_TYPE_SONIFICATION)
904                 .setFlags(0)
905                 .build());
906         idn.setShowBadge(false);
907         NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW);
908         ido.setShowBadge(true);
909         ido.setSound(null, new AudioAttributes.Builder()
910                 .setUsage(USAGE_NOTIFICATION)
911                 .setContentType(CONTENT_TYPE_SONIFICATION)
912                 .setFlags(0)
913                 .build());
914         NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH);
915         idp.lockFields(2);
916         idp.setSound(null, new AudioAttributes.Builder()
917                 .setUsage(USAGE_NOTIFICATION)
918                 .setContentType(CONTENT_TYPE_SONIFICATION)
919                 .setFlags(0)
920                 .build());
921 
922         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
923 
924         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
925 
926         assertEquals(idn, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false));
927         compareChannels(ido, mHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false));
928         compareChannels(idp, mHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false));
929 
930         verify(mPermissionHelper, never()).setNotificationPermission(any());
931 
932         // this XML is new enough, we should not be attempting to show a notification or anything
933         assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN,
934                 Settings.Global.getInt(mContext.getContentResolver(),
935                         Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
936                         NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN));
937     }
938 
939     @Test
testReadXml_oldXml_migration_NoUid()940     public void testReadXml_oldXml_migration_NoUid() throws Exception {
941         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
942                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
943 
944         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
945         String xml = "<ranking version=\"2\">\n"
946                 + "<package name=\"something\" show_badge=\"true\">\n"
947                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
948                 + "</package>\n"
949                 + "</ranking>\n";
950         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
951         idn.setSound(null, new AudioAttributes.Builder()
952                 .setUsage(USAGE_NOTIFICATION)
953                 .setContentType(CONTENT_TYPE_SONIFICATION)
954                 .setFlags(0)
955                 .build());
956         idn.setShowBadge(false);
957 
958         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
959         verify(mPermissionHelper, never()).setNotificationPermission(any());
960 
961         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234);
962         final ApplicationInfo app = new ApplicationInfo();
963         app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
964         when(mPm.getApplicationInfoAsUser(eq("something"), anyInt(), anyInt())).thenReturn(app);
965 
966         mHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234});
967 
968 
969         verify(mPermissionHelper, times(1)).setNotificationPermission(any());
970     }
971 
972     @Test
testReadXml_newXml_noMigration_NoUid()973     public void testReadXml_newXml_noMigration_NoUid() throws Exception {
974         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
975                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
976 
977         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
978         String xml = "<ranking version=\"3\">\n"
979                 + "<package name=\"something\" show_badge=\"true\">\n"
980                 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
981                 + "</package>\n"
982                 + "</ranking>\n";
983         NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
984         idn.setSound(null, new AudioAttributes.Builder()
985                 .setUsage(USAGE_NOTIFICATION)
986                 .setContentType(CONTENT_TYPE_SONIFICATION)
987                 .setFlags(0)
988                 .build());
989         idn.setShowBadge(false);
990 
991         loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
992 
993         when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234);
994         final ApplicationInfo app = new ApplicationInfo();
995         app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
996         when(mPm.getApplicationInfoAsUser(eq("something"), anyInt(), anyInt())).thenReturn(app);
997 
998         mHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234});
999 
1000 
1001         verify(mPermissionHelper, never()).setNotificationPermission(any());
1002     }
1003 
1004     @Test
testChannelXmlForNonBackup_postMigration()1005     public void testChannelXmlForNonBackup_postMigration() throws Exception {
1006         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1007                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
1008 
1009         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1010         appPermissions.put(new Pair(1, "first"), new Pair(true, false));
1011         appPermissions.put(new Pair(3, "third"), new Pair(false, false));
1012         appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));
1013         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false));
1014         appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
1015 
1016         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1017                 .thenReturn(appPermissions);
1018 
1019         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1020         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1021         NotificationChannel channel1 =
1022                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1023         channel1.setSound(null, null);
1024         NotificationChannel channel2 =
1025                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1026         channel2.setDescription("descriptions for all");
1027         channel2.setSound(null, null);
1028         channel2.enableLights(true);
1029         channel2.setBypassDnd(true);
1030         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1031         channel2.enableVibration(false);
1032         channel2.setGroup(ncg.getId());
1033         channel2.setLightColor(Color.BLUE);
1034         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
1035         channel3.enableVibration(true);
1036 
1037         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
1038         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
1039         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
1040         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
1041         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
1042         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
1043 
1044         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
1045         mHelper.setInvalidMessageSent(PKG_P, UID_P);
1046         mHelper.setValidMessageSent(PKG_P, UID_P);
1047         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
1048 
1049         ByteArrayOutputStream baos = writeXmlAndPurge(
1050                 PKG_N_MR1, UID_N_MR1, false, USER_SYSTEM);
1051         String expected = "<ranking version=\"4\">\n"
1052                 + "<package name=\"com.example.o\" show_badge=\"true\" "
1053                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1054                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" uid=\"1111\">\n"
1055                 + "<channel id=\"id\" name=\"name\" importance=\"2\" "
1056                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1057                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
1058                 + "</package>\n"
1059                 + "<package name=\"com.example.p\" show_badge=\"true\" "
1060                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
1061                 + " user_demote_msg_app=\"true\" uid=\"2222\" />\n"
1062                 + "<package name=\"com.example.n_mr1\" show_badge=\"true\" "
1063                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1064                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" uid=\"0\">\n"
1065                 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
1066                 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
1067                 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
1068                 + "orig_imp=\"4\" />\n"
1069                 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
1070                 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" "
1071                 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n"
1072                 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" "
1073                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1074                 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
1075                 + "orig_imp=\"4\" />\n"
1076                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
1077                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1078                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1079                 + "</package>\n"
1080                 + "</ranking>";
1081         assertThat(baos.toString()).contains(expected);
1082     }
1083 
1084     @Test
testChannelXmlForBackup_postMigration()1085     public void testChannelXmlForBackup_postMigration() throws Exception {
1086         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1087                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
1088 
1089         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1090         appPermissions.put(new Pair(1, "first"), new Pair(true, false));
1091         appPermissions.put(new Pair(3, "third"), new Pair(false, false));
1092         appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));
1093         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false));
1094         appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
1095 
1096         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1097                 .thenReturn(appPermissions);
1098 
1099         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1100         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1101         NotificationChannel channel1 =
1102                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1103         channel1.setSound(null, null);
1104         NotificationChannel channel2 =
1105                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1106         channel2.setDescription("descriptions for all");
1107         channel2.setSound(null, null);
1108         channel2.enableLights(true);
1109         channel2.setBypassDnd(true);
1110         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1111         channel2.enableVibration(false);
1112         channel2.setGroup(ncg.getId());
1113         channel2.setLightColor(Color.BLUE);
1114         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
1115         channel3.enableVibration(true);
1116 
1117         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
1118         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
1119         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
1120         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
1121         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
1122         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
1123 
1124         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
1125         mHelper.setInvalidMessageSent(PKG_P, UID_P);
1126         mHelper.setValidMessageSent(PKG_P, UID_P);
1127         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
1128 
1129         ByteArrayOutputStream baos = writeXmlAndPurge(
1130                 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM);
1131         String expected = "<ranking version=\"4\">\n"
1132                 // Importance 0 because off in permissionhelper
1133                 + "<package name=\"com.example.o\" importance=\"0\" show_badge=\"true\" "
1134                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1135                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\">\n"
1136                 + "<channel id=\"id\" name=\"name\" importance=\"2\" "
1137                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1138                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
1139                 + "</package>\n"
1140                 // Importance default because on in permission helper
1141                 + "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" "
1142                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
1143                 + " user_demote_msg_app=\"true\" />\n"
1144                 // Importance default because on in permission helper
1145                 + "<package name=\"com.example.n_mr1\" importance=\"3\" show_badge=\"true\" "
1146                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1147                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\">\n"
1148                 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
1149                 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
1150                 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
1151                 + "orig_imp=\"4\" />\n"
1152                 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
1153                 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" "
1154                 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n"
1155                 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" "
1156                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1157                 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
1158                 + "orig_imp=\"4\" />\n"
1159                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
1160                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1161                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1162                 + "</package>\n"
1163                 // Packages that exist solely in permissionhelper
1164                 + "<package name=\"first\" importance=\"3\" />\n"
1165                 + "<package name=\"third\" importance=\"0\" />\n"
1166                 + "</ranking>";
1167         assertThat(baos.toString()).contains(expected);
1168     }
1169 
1170     @Test
testChannelXmlForBackup_postMigration_noExternal()1171     public void testChannelXmlForBackup_postMigration_noExternal() throws Exception {
1172         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1173                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
1174 
1175         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1176         appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));
1177         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false));
1178         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1179                 .thenReturn(appPermissions);
1180 
1181         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1182         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1183         NotificationChannel channel1 =
1184                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1185         channel1.setSound(null, null);
1186         NotificationChannel channel2 =
1187                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1188         channel2.setDescription("descriptions for all");
1189         channel2.setSound(null, null);
1190         channel2.enableLights(true);
1191         channel2.setBypassDnd(true);
1192         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1193         channel2.enableVibration(false);
1194         channel2.setGroup(ncg.getId());
1195         channel2.setLightColor(Color.BLUE);
1196         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
1197         channel3.enableVibration(true);
1198 
1199         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
1200         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
1201         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
1202         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
1203         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
1204         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
1205 
1206         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
1207         mHelper.setInvalidMessageSent(PKG_P, UID_P);
1208         mHelper.setValidMessageSent(PKG_P, UID_P);
1209         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
1210 
1211         ByteArrayOutputStream baos = writeXmlAndPurge(
1212                 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM);
1213         String expected = "<ranking version=\"4\">\n"
1214                 // Importance 0 because off in permissionhelper
1215                 + "<package name=\"com.example.o\" importance=\"0\" show_badge=\"true\" "
1216                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1217                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\">\n"
1218                 + "<channel id=\"id\" name=\"name\" importance=\"2\" "
1219                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1220                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
1221                 + "</package>\n"
1222                 // Importance default because on in permission helper
1223                 + "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" "
1224                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
1225                 + " user_demote_msg_app=\"true\" />\n"
1226                 // Importance missing because missing from permission helper
1227                 + "<package name=\"com.example.n_mr1\" show_badge=\"true\" "
1228                 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
1229                 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\">\n"
1230                 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
1231                 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
1232                 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
1233                 + "orig_imp=\"4\" />\n"
1234                 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
1235                 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" "
1236                 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n"
1237                 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" "
1238                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1239                 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
1240                 + "orig_imp=\"4\" />\n"
1241                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
1242                 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
1243                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1244                 + "</package>\n"
1245                 + "</ranking>";
1246         assertThat(baos.toString()).contains(expected);
1247     }
1248 
1249     @Test
testChannelXmlForBackup_postMigration_noLocalSettings()1250     public void testChannelXmlForBackup_postMigration_noLocalSettings() throws Exception {
1251         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
1252                 mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
1253 
1254         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1255         appPermissions.put(new Pair(1, "first"), new Pair(true, false));
1256         appPermissions.put(new Pair(3, "third"), new Pair(false, false));
1257         appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));
1258         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false));
1259         appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
1260 
1261         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1262                 .thenReturn(appPermissions);
1263 
1264         ByteArrayOutputStream baos = writeXmlAndPurge(
1265                 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM);
1266         String expected = "<ranking version=\"4\">\n"
1267                 // Packages that exist solely in permissionhelper
1268                 + "<package name=\"" + PKG_P + "\" importance=\"3\" />\n"
1269                 + "<package name=\"" + PKG_O + "\" importance=\"0\" />\n"
1270                 + "<package name=\"" + PKG_N_MR1 + "\" importance=\"3\" />\n"
1271                 + "<package name=\"first\" importance=\"3\" />\n"
1272                 + "<package name=\"third\" importance=\"0\" />\n"
1273                 + "</ranking>";
1274         assertThat(baos.toString()).contains(expected);
1275     }
1276 
1277     @Test
testBackupXml_backupCanonicalizedSoundUri()1278     public void testBackupXml_backupCanonicalizedSoundUri() throws Exception {
1279         NotificationChannel channel =
1280                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1281         channel.setSound(SOUND_URI, mAudioAttributes);
1282         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1283 
1284         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1285                 USER_SYSTEM, channel.getId());
1286 
1287         // Testing that in restore we are given the canonical version
1288         loadStreamXml(baos, true, USER_SYSTEM);
1289         verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
1290     }
1291 
1292     @Test
testRestoreXml_withExistentCanonicalizedSoundUri()1293     public void testRestoreXml_withExistentCanonicalizedSoundUri() throws Exception {
1294         Uri localUri = Uri.parse("content://" + TEST_AUTHORITY + "/local/url");
1295         Uri canonicalBasedOnLocal = localUri.buildUpon()
1296                 .appendQueryParameter("title", "Test")
1297                 .appendQueryParameter("canonical", "1")
1298                 .build();
1299         doReturn(canonicalBasedOnLocal)
1300                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
1301         doReturn(localUri)
1302                 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
1303         doReturn(localUri)
1304                 .when(mTestIContentProvider).uncanonicalize(any(), eq(canonicalBasedOnLocal));
1305 
1306         NotificationChannel channel =
1307                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1308         channel.setSound(SOUND_URI, mAudioAttributes);
1309         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1310         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1311                 USER_SYSTEM, channel.getId());
1312 
1313         loadStreamXml(baos, true, USER_SYSTEM);
1314 
1315         NotificationChannel actualChannel = mHelper.getNotificationChannel(
1316                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1317         assertEquals(localUri, actualChannel.getSound());
1318     }
1319 
1320     @Test
testRestoreXml_withNonExistentCanonicalizedSoundUri()1321     public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
1322         Thread.sleep(3000);
1323         doReturn(null)
1324                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
1325         doReturn(null)
1326                 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
1327 
1328         NotificationChannel channel =
1329                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1330         channel.setSound(SOUND_URI, mAudioAttributes);
1331         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1332         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1333                 USER_SYSTEM, channel.getId());
1334 
1335         loadStreamXml(baos, true, USER_SYSTEM);
1336 
1337         NotificationChannel actualChannel = mHelper.getNotificationChannel(
1338                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1339         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
1340     }
1341 
1342 
1343     /**
1344      * Although we don't make backups with uncanonicalized uris anymore, we used to, so we have to
1345      * handle its restore properly.
1346      */
1347     @Test
testRestoreXml_withUncanonicalizedNonLocalSoundUri()1348     public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
1349         // Not a local uncanonicalized uri, simulating that it fails to exist locally
1350         doReturn(null)
1351                 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
1352         String id = "id";
1353         String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
1354                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
1355                 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
1356                 + "sound=\"" + SOUND_URI + "\" "
1357                 + "usage=\"6\" content_type=\"0\" flags=\"1\" show_badge=\"true\" />\n"
1358                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" "
1359                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
1360                 + "</package>\n"
1361                 + "</ranking>\n";
1362 
1363         loadByteArrayXml(
1364                 backupWithUncanonicalizedSoundUri.getBytes(), true, USER_SYSTEM);
1365 
1366         NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
1367         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
1368     }
1369 
1370     @Test
testBackupRestoreXml_withNullSoundUri()1371     public void testBackupRestoreXml_withNullSoundUri() throws Exception {
1372         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
1373         appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
1374 
1375         when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
1376                 .thenReturn(appPermissions);
1377 
1378         NotificationChannel channel =
1379                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
1380         channel.setSound(null, mAudioAttributes);
1381         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1382         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1383                 USER_SYSTEM, channel.getId());
1384 
1385         loadStreamXml(baos, true, USER_SYSTEM);
1386 
1387         NotificationChannel actualChannel = mHelper.getNotificationChannel(
1388                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1389         assertEquals(null, actualChannel.getSound());
1390     }
1391 
1392     @Test
testChannelXml_backup()1393     public void testChannelXml_backup() throws Exception {
1394         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
1395         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
1396         NotificationChannel channel1 =
1397                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1398         NotificationChannel channel2 =
1399                 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
1400         NotificationChannel channel3 =
1401                 new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
1402         channel3.setGroup(ncg.getId());
1403 
1404         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
1405         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
1406         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
1407         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
1408         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
1409 
1410         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId());
1411         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId());
1412         assertEquals(channel2,
1413                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
1414 
1415         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
1416                 USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
1417                 NotificationChannel.DEFAULT_CHANNEL_ID);
1418         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
1419                 UID_N_MR1});
1420 
1421         TypedXmlPullParser parser = Xml.newFastPullParser();
1422         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
1423                 null);
1424         parser.nextTag();
1425         mHelper.readXml(parser, true, USER_SYSTEM);
1426 
1427         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
1428         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
1429         assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG_N_MR1, UID_N_MR1));
1430         assertEquals(channel2,
1431                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
1432     }
1433 
1434     @Test
testChannelXml_defaultChannelLegacyApp_noUserSettings()1435     public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
1436         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1437                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
1438 
1439         loadStreamXml(baos, false, UserHandle.USER_ALL);
1440 
1441         final NotificationChannel updated = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
1442                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
1443         assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
1444         assertFalse(updated.canBypassDnd());
1445         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
1446         assertEquals(0, updated.getUserLockedFields());
1447     }
1448 
1449     @Test
testChannelXml_defaultChannelUpdatedApp_userSettings()1450     public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
1451         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
1452                 UID_N_MR1,
1453                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
1454         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
1455         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
1456 
1457         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1458                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
1459 
1460         loadStreamXml(baos, false, UserHandle.USER_ALL);
1461 
1462         assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
1463                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
1464     }
1465 
1466     @Test
testChannelXml_upgradeCreateDefaultChannel()1467     public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
1468         final String preupgradeXml = "<ranking version=\"1\">\n"
1469                 + "<package name=\"" + PKG_N_MR1
1470                 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
1471                 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
1472                 + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID_N_MR1 + "\" />\n"
1473                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\""
1474                 + Notification.VISIBILITY_PRIVATE + "\" />\n"
1475                 + "</ranking>";
1476         TypedXmlPullParser parser = Xml.newFastPullParser();
1477         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
1478                 null);
1479         parser.nextTag();
1480         mHelper.readXml(parser, false, UserHandle.USER_ALL);
1481 
1482         final NotificationChannel updated1 =
1483             mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
1484         assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
1485         assertTrue(updated1.canBypassDnd());
1486         assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
1487         assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
1488                 | NotificationChannel.USER_LOCKED_PRIORITY
1489                 | NotificationChannel.USER_LOCKED_VISIBILITY,
1490                 updated1.getUserLockedFields());
1491 
1492         // No Default Channel created for updated packages
1493         assertEquals(null, mHelper.getNotificationChannel(PKG_O, UID_O,
1494                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
1495     }
1496 
1497     @Test
testChannelXml_upgradeDeletesDefaultChannel()1498     public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception {
1499         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
1500                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
1501         assertTrue(defaultChannel != null);
1502         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1503                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
1504         // Load package at higher sdk.
1505         final ApplicationInfo upgraded = new ApplicationInfo();
1506         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
1507         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
1508         loadStreamXml(baos, false, UserHandle.USER_ALL);
1509 
1510         // Default Channel should be gone.
1511         assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
1512                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
1513     }
1514 
1515     @Test
testDeletesDefaultChannelAfterChannelIsCreated()1516     public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception {
1517         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1518                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
1519         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1520                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
1521 
1522         // Load package at higher sdk.
1523         final ApplicationInfo upgraded = new ApplicationInfo();
1524         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
1525         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
1526         loadStreamXml(baos, false, UserHandle.USER_ALL);
1527 
1528         // Default Channel should be gone.
1529         assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
1530                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
1531     }
1532 
1533     @Test
testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels()1534     public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
1535         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
1536                 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
1537         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1538                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
1539 
1540         loadStreamXml(baos, false, UserHandle.USER_ALL);
1541 
1542         // Should still have the newly created channel that wasn't in the xml.
1543         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "bananas", false) != null);
1544     }
1545 
1546     @Test
testCreateChannel_badImportance()1547     public void testCreateChannel_badImportance() throws Exception {
1548         try {
1549             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1550                     new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1),
1551                     true, false);
1552             fail("Was allowed to create a channel with invalid importance");
1553         } catch (IllegalArgumentException e) {
1554             // yay
1555         }
1556         try {
1557             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1558                     new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED),
1559                     true, false);
1560             fail("Was allowed to create a channel with invalid importance");
1561         } catch (IllegalArgumentException e) {
1562             // yay
1563         }
1564         try {
1565             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1566                     new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1),
1567                     true, false);
1568             fail("Was allowed to create a channel with invalid importance");
1569         } catch (IllegalArgumentException e) {
1570             // yay
1571         }
1572         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1573                 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false));
1574         assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
1575                 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false));
1576     }
1577 
1578 
1579     @Test
testUpdate()1580     public void testUpdate() throws Exception {
1581         // no fields locked by user
1582         final NotificationChannel channel =
1583                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1584         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
1585         channel.enableLights(true);
1586         channel.setBypassDnd(true);
1587         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1588 
1589         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false));
1590 
1591         // same id, try to update all fields
1592         final NotificationChannel channel2 =
1593                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
1594         channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
1595         channel2.enableLights(false);
1596         channel2.setBypassDnd(false);
1597         channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
1598 
1599         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true);
1600 
1601         // all fields should be changed
1602         assertEquals(channel2,
1603                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false));
1604 
1605         verify(mHandler, times(1)).requestSort();
1606     }
1607 
1608     @Test
testUpdate_preUpgrade_updatesAppFields()1609     public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
1610         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
1611         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
1612         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
1613                 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
1614 
1615         NotificationChannel defaultChannel = mHelper.getNotificationChannel(
1616                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
1617 
1618         defaultChannel.setShowBadge(false);
1619         defaultChannel.setImportance(IMPORTANCE_NONE);
1620         defaultChannel.setBypassDnd(true);
1621         defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1622 
1623         mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
1624         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
1625 
1626         // ensure app level fields are changed
1627         assertFalse(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
1628         assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
1629         assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1,
1630                 UID_N_MR1));
1631     }
1632 
1633     @Test
testUpdate_postUpgrade_noUpdateAppFields()1634     public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception {
1635         final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1636 
1637         mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false);
1638         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
1639         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
1640         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
1641                 mHelper.getPackageVisibility(PKG_O, UID_O));
1642 
1643         channel.setShowBadge(false);
1644         channel.setImportance(IMPORTANCE_NONE);
1645         channel.setBypassDnd(true);
1646         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1647 
1648         mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true);
1649 
1650         // ensure app level fields are not changed
1651         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
1652         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
1653         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
1654                 mHelper.getPackageVisibility(PKG_O, UID_O));
1655     }
1656 
1657     @Test
testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels()1658     public void testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels() throws Exception {
1659         final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1660 
1661         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false);
1662         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
1663         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
1664         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
1665                 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
1666 
1667         channel.setShowBadge(false);
1668         channel.setImportance(IMPORTANCE_NONE);
1669         channel.setBypassDnd(true);
1670         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1671 
1672         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true);
1673 
1674         NotificationChannel defaultChannel = mHelper.getNotificationChannel(
1675                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
1676 
1677         defaultChannel.setShowBadge(false);
1678         defaultChannel.setImportance(IMPORTANCE_NONE);
1679         defaultChannel.setBypassDnd(true);
1680         defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1681 
1682         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
1683 
1684         // ensure app level fields are not changed
1685         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
1686         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
1687         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
1688                 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
1689     }
1690 
1691     @Test
testGetNotificationChannel_ReturnsNullForUnknownChannel()1692     public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception {
1693         assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "garbage", false));
1694     }
1695 
1696     @Test
testCreateChannel_CannotChangeHiddenFields()1697     public void testCreateChannel_CannotChangeHiddenFields() {
1698         final NotificationChannel channel =
1699                 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
1700         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
1701         channel.enableLights(true);
1702         channel.setBypassDnd(true);
1703         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1704         channel.setShowBadge(true);
1705         channel.setAllowBubbles(false);
1706         channel.setImportantConversation(true);
1707         int lockMask = 0;
1708         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
1709             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
1710         }
1711         channel.lockFields(lockMask);
1712 
1713         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false));
1714 
1715         NotificationChannel savedChannel =
1716                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1717 
1718         assertEquals(channel.getName(), savedChannel.getName());
1719         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
1720         assertFalse(savedChannel.canBypassDnd());
1721         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
1722         assertFalse(channel.isImportantConversation());
1723         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
1724         assertEquals(channel.canBubble(), savedChannel.canBubble());
1725 
1726         verify(mHandler, never()).requestSort();
1727     }
1728 
1729     @Test
testCreateChannel_CannotChangeHiddenFieldsAssistant()1730     public void testCreateChannel_CannotChangeHiddenFieldsAssistant() {
1731         final NotificationChannel channel =
1732                 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
1733         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
1734         channel.enableLights(true);
1735         channel.setBypassDnd(true);
1736         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1737         channel.setShowBadge(true);
1738         channel.setAllowBubbles(false);
1739         int lockMask = 0;
1740         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
1741             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
1742         }
1743         channel.lockFields(lockMask);
1744 
1745         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1746 
1747         NotificationChannel savedChannel =
1748                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1749 
1750         assertEquals(channel.getName(), savedChannel.getName());
1751         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
1752         assertFalse(savedChannel.canBypassDnd());
1753         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
1754         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
1755         assertEquals(channel.canBubble(), savedChannel.canBubble());
1756     }
1757 
1758     @Test
testClearLockedFields()1759     public void testClearLockedFields() {
1760         final NotificationChannel channel = getChannel();
1761         mHelper.clearLockedFieldsLocked(channel);
1762         assertEquals(0, channel.getUserLockedFields());
1763 
1764         channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
1765                 | NotificationChannel.USER_LOCKED_IMPORTANCE);
1766         mHelper.clearLockedFieldsLocked(channel);
1767         assertEquals(0, channel.getUserLockedFields());
1768     }
1769 
1770     @Test
testLockFields_soundAndVibration()1771     public void testLockFields_soundAndVibration() {
1772         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
1773 
1774         final NotificationChannel update1 = getChannel();
1775         update1.setSound(new Uri.Builder().scheme("test").build(),
1776                 new AudioAttributes.Builder().build());
1777         update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
1778         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
1779         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
1780                 | NotificationChannel.USER_LOCKED_SOUND,
1781                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
1782                         .getUserLockedFields());
1783 
1784         NotificationChannel update2 = getChannel();
1785         update2.enableVibration(true);
1786         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
1787         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
1788                         | NotificationChannel.USER_LOCKED_SOUND
1789                         | NotificationChannel.USER_LOCKED_VIBRATION,
1790                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
1791                         .getUserLockedFields());
1792     }
1793 
1794     @Test
testLockFields_vibrationAndLights()1795     public void testLockFields_vibrationAndLights() {
1796         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
1797 
1798         final NotificationChannel update1 = getChannel();
1799         update1.setVibrationPattern(new long[]{7945, 46 ,246});
1800         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
1801         assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
1802                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
1803                         .getUserLockedFields());
1804 
1805         final NotificationChannel update2 = getChannel();
1806         update2.enableLights(true);
1807         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
1808         assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
1809                         | NotificationChannel.USER_LOCKED_LIGHTS,
1810                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
1811                         .getUserLockedFields());
1812     }
1813 
1814     @Test
testLockFields_lightsAndImportance()1815     public void testLockFields_lightsAndImportance() {
1816         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
1817 
1818         final NotificationChannel update1 = getChannel();
1819         update1.setLightColor(Color.GREEN);
1820         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
1821         assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
1822                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
1823                         .getUserLockedFields());
1824 
1825         final NotificationChannel update2 = getChannel();
1826         update2.setImportance(IMPORTANCE_DEFAULT);
1827         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
1828         assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
1829                         | NotificationChannel.USER_LOCKED_IMPORTANCE,
1830                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
1831                         .getUserLockedFields());
1832     }
1833 
1834     @Test
testLockFields_visibilityAndDndAndBadge()1835     public void testLockFields_visibilityAndDndAndBadge() {
1836         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
1837         assertEquals(0,
1838                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
1839                         .getUserLockedFields());
1840 
1841         final NotificationChannel update1 = getChannel();
1842         update1.setBypassDnd(true);
1843         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
1844         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
1845                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
1846                         .getUserLockedFields());
1847 
1848         final NotificationChannel update2 = getChannel();
1849         update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1850         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
1851         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
1852                         | NotificationChannel.USER_LOCKED_VISIBILITY,
1853                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
1854                         .getUserLockedFields());
1855 
1856         final NotificationChannel update3 = getChannel();
1857         update3.setShowBadge(false);
1858         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true);
1859         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
1860                         | NotificationChannel.USER_LOCKED_VISIBILITY
1861                         | NotificationChannel.USER_LOCKED_SHOW_BADGE,
1862                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update3.getId(), false)
1863                         .getUserLockedFields());
1864     }
1865 
1866     @Test
testLockFields_allowBubble()1867     public void testLockFields_allowBubble() {
1868         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
1869         assertEquals(0,
1870                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
1871                         .getUserLockedFields());
1872 
1873         final NotificationChannel update = getChannel();
1874         update.setAllowBubbles(true);
1875         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true);
1876         assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE,
1877                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
1878                         .getUserLockedFields());
1879     }
1880 
1881     @Test
testDeleteNonExistentChannel()1882     public void testDeleteNonExistentChannel() throws Exception {
1883         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist");
1884     }
1885 
1886     @Test
testDoubleDeleteChannel()1887     public void testDoubleDeleteChannel() throws Exception {
1888         NotificationChannel channel = getChannel();
1889         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1890         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
1891         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
1892         assertEquals(2, mLogger.getCalls().size());
1893         assertEquals(
1894                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
1895                 mLogger.get(0).event);
1896         assertEquals(
1897                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_DELETED,
1898                 mLogger.get(1).event);
1899         // No log for the second delete of the same channel.
1900     }
1901 
1902     @Test
testGetDeletedChannel()1903     public void testGetDeletedChannel() throws Exception {
1904         NotificationChannel channel = getChannel();
1905         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
1906         channel.enableLights(true);
1907         channel.setBypassDnd(true);
1908         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
1909         channel.enableVibration(true);
1910         channel.setVibrationPattern(new long[]{100, 67, 145, 156});
1911 
1912         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1913         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
1914 
1915         // Does not return deleted channel
1916         NotificationChannel response =
1917                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
1918         assertNull(response);
1919 
1920         // Returns deleted channel
1921         response = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true);
1922         compareChannels(channel, response);
1923         assertTrue(response.isDeleted());
1924     }
1925 
1926     @Test
testGetDeletedChannels()1927     public void testGetDeletedChannels() throws Exception {
1928         Map<String, NotificationChannel> channelMap = new HashMap<>();
1929         NotificationChannel channel =
1930                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1931         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
1932         channel.enableLights(true);
1933         channel.setBypassDnd(true);
1934         channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
1935         channel.enableVibration(true);
1936         channel.setVibrationPattern(new long[]{100, 67, 145, 156});
1937         channelMap.put(channel.getId(), channel);
1938         NotificationChannel channel2 =
1939                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
1940         channelMap.put(channel2.getId(), channel2);
1941         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1942         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
1943 
1944         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
1945 
1946         // Returns only non-deleted channels
1947         List<NotificationChannel> channels =
1948                 mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList();
1949         assertEquals(2, channels.size());   // Default channel + non-deleted channel
1950         for (NotificationChannel nc : channels) {
1951             if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
1952                 compareChannels(channel2, nc);
1953             }
1954         }
1955 
1956         // Returns deleted channels too
1957         channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList();
1958         assertEquals(3, channels.size());               // Includes default channel
1959         for (NotificationChannel nc : channels) {
1960             if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
1961                 compareChannels(channelMap.get(nc.getId()), nc);
1962             }
1963         }
1964     }
1965 
1966     @Test
testGetDeletedChannelCount()1967     public void testGetDeletedChannelCount() throws Exception {
1968         NotificationChannel channel =
1969                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1970         NotificationChannel channel2 =
1971                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
1972         NotificationChannel channel3 =
1973                 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH);
1974         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1975         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
1976         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
1977 
1978         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
1979         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId());
1980 
1981         assertEquals(2, mHelper.getDeletedChannelCount(PKG_N_MR1, UID_N_MR1));
1982         assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID_O));
1983     }
1984 
1985     @Test
testGetBlockedChannelCount()1986     public void testGetBlockedChannelCount() throws Exception {
1987         NotificationChannel channel =
1988                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1989         NotificationChannel channel2 =
1990                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE);
1991         NotificationChannel channel3 =
1992                 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE);
1993         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
1994         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
1995         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
1996 
1997         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId());
1998 
1999         assertEquals(1, mHelper.getBlockedChannelCount(PKG_N_MR1, UID_N_MR1));
2000         assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID_O));
2001     }
2002 
2003     @Test
testGetChannelsBypassingDndCount_noChannelsBypassing()2004     public void testGetChannelsBypassingDndCount_noChannelsBypassing() throws Exception {
2005         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2006                 UID_N_MR1).getList().size());
2007     }
2008 
2009     @Test
testGetChannelsBypassingDnd_noChannelsForUidBypassing()2010     public void testGetChannelsBypassingDnd_noChannelsForUidBypassing()
2011             throws Exception {
2012         int uid = 222;
2013         NotificationChannel channel = new NotificationChannel("id", "name",
2014                 NotificationManager.IMPORTANCE_MAX);
2015         channel.setBypassDnd(true);
2016         mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true);
2017 
2018         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2019                 uid).getList().size());
2020     }
2021 
2022     @Test
testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked()2023     public void testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked() {
2024         int uid = UID_N_MR1;
2025         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2026         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2027                 NotificationManager.IMPORTANCE_MAX);
2028         channel1.setBypassDnd(true);
2029         channel1.setGroup(ncg.getId());
2030         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg,  /* fromTargetApp */ true);
2031         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true);
2032 
2033         assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2034                 uid).getList().size());
2035 
2036         // disable group
2037         ncg.setBlocked(true);
2038         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg,  /* fromTargetApp */ false);
2039         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2040                 uid).getList().size());
2041     }
2042 
2043     @Test
testGetChannelsBypassingDndCount_multipleChannelsBypassing()2044     public void testGetChannelsBypassingDndCount_multipleChannelsBypassing() {
2045         int uid = UID_N_MR1;
2046         NotificationChannel channel1 = new NotificationChannel("id1", "name1",
2047                 NotificationManager.IMPORTANCE_MAX);
2048         NotificationChannel channel2 = new NotificationChannel("id2", "name2",
2049                 NotificationManager.IMPORTANCE_MAX);
2050         NotificationChannel channel3 = new NotificationChannel("id3", "name3",
2051                 NotificationManager.IMPORTANCE_MAX);
2052         channel1.setBypassDnd(true);
2053         channel2.setBypassDnd(true);
2054         channel3.setBypassDnd(true);
2055         // has DND access, so can set bypassDnd attribute
2056         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true);
2057         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
2058         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel3, true, true);
2059         assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2060                 uid).getList().size());
2061 
2062         // setBypassDnd false for some channels
2063         channel1.setBypassDnd(false);
2064         channel2.setBypassDnd(false);
2065         assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2066                 uid).getList().size());
2067 
2068         // setBypassDnd false for rest of the channels
2069         channel3.setBypassDnd(false);
2070         assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
2071                 uid).getList().size());
2072     }
2073 
2074     @Test
testCreateAndDeleteCanChannelsBypassDnd_localSettings()2075     public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() {
2076         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2077         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2078 
2079         // create notification channel that can't bypass dnd
2080         // expected result: areChannelsBypassingDnd = false
2081         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2082         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2083         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false);
2084         assertFalse(mHelper.areChannelsBypassingDnd());
2085         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2086         resetZenModeHelper();
2087 
2088         // create notification channel that can bypass dnd
2089         // expected result: areChannelsBypassingDnd = true
2090         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2091         channel2.setBypassDnd(true);
2092         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
2093         assertTrue(mHelper.areChannelsBypassingDnd());
2094         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2095         resetZenModeHelper();
2096 
2097         // delete channels
2098         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId());
2099         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
2100         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2101         resetZenModeHelper();
2102 
2103         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId());
2104         assertFalse(mHelper.areChannelsBypassingDnd());
2105         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2106         resetZenModeHelper();
2107     }
2108 
2109     @Test
testCreateAndUpdateChannelsBypassingDnd_permissionHelper()2110     public void testCreateAndUpdateChannelsBypassingDnd_permissionHelper() {
2111         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2112         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2113 
2114         // create notification channel that can't bypass dnd
2115         // expected result: areChannelsBypassingDnd = false
2116         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2117         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2118         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false);
2119         assertFalse(mHelper.areChannelsBypassingDnd());
2120         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2121         resetZenModeHelper();
2122 
2123         // Recreate a channel & now the app has dnd access granted and can set the bypass dnd field
2124         NotificationChannel update = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2125         update.setBypassDnd(true);
2126         mHelper.createNotificationChannel(PKG_N_MR1, uid, update, true, true);
2127 
2128         assertTrue(mHelper.areChannelsBypassingDnd());
2129         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2130         resetZenModeHelper();
2131     }
2132 
2133     @Test
testCreateAndDeleteCanChannelsBypassDnd_permissionHelper()2134     public void testCreateAndDeleteCanChannelsBypassDnd_permissionHelper() {
2135         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2136         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2137 
2138         // create notification channel that can't bypass dnd
2139         // expected result: areChannelsBypassingDnd = false
2140         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2141         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2142         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false);
2143         assertFalse(mHelper.areChannelsBypassingDnd());
2144         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2145         resetZenModeHelper();
2146 
2147         // create notification channel that can bypass dnd, using local app level settings
2148         // expected result: areChannelsBypassingDnd = true
2149         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2150         channel2.setBypassDnd(true);
2151         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
2152         assertTrue(mHelper.areChannelsBypassingDnd());
2153         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2154         resetZenModeHelper();
2155 
2156         // delete channels
2157         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId());
2158         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
2159         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2160         resetZenModeHelper();
2161 
2162         mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId());
2163         assertFalse(mHelper.areChannelsBypassingDnd());
2164         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2165         resetZenModeHelper();
2166     }
2167 
2168     @Test
testBlockedGroupDoesNotBypassDnd()2169     public void testBlockedGroupDoesNotBypassDnd() {
2170         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2171         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2172 
2173         // start in a 'allowed to bypass dnd state'
2174         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2175                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2176         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
2177         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
2178                 mPermissionHelper, mLogger,
2179                 mAppOpsManager, mStatsEventBuilderFactory, false);
2180 
2181 
2182         // create notification channel that can bypass dnd, but app is blocked
2183         // expected result: areChannelsBypassingDnd = false
2184         NotificationChannelGroup group = new NotificationChannelGroup("group", "group");
2185         group.setBlocked(true);
2186         mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, group, false);
2187         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2188         channel2.setGroup("group");
2189         channel2.setBypassDnd(true);
2190         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
2191         assertFalse(mHelper.areChannelsBypassingDnd());
2192         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2193         resetZenModeHelper();
2194     }
2195 
2196     @Test
testBlockedAppsDoNotBypassDnd_localSettings()2197     public void testBlockedAppsDoNotBypassDnd_localSettings() {
2198         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2199         when(mPermissionHelper.hasPermission(uid)).thenReturn(false);
2200 
2201         // start in a 'allowed to bypass dnd state'
2202         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2203                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2204         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
2205         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
2206                 mPermissionHelper, mLogger,
2207                 mAppOpsManager, mStatsEventBuilderFactory, false);
2208 
2209         // create notification channel that can bypass dnd, but app is blocked
2210         // expected result: areChannelsBypassingDnd = false
2211         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2212         channel2.setBypassDnd(true);
2213         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
2214         assertFalse(mHelper.areChannelsBypassingDnd());
2215         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2216         resetZenModeHelper();
2217     }
2218 
2219     @Test
testBlockedAppsDoNotBypassDnd_permissionHelper()2220     public void testBlockedAppsDoNotBypassDnd_permissionHelper() {
2221         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2222         when(mPermissionHelper.hasPermission(uid)).thenReturn(false);
2223 
2224         // start in a 'allowed to bypass dnd state'
2225         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2226                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2227         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
2228         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
2229                 mPermissionHelper, mLogger,
2230                 mAppOpsManager, mStatsEventBuilderFactory, false);
2231 
2232         // create notification channel that can bypass dnd, but app is blocked
2233         // expected result: areChannelsBypassingDnd = false
2234         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2235         channel2.setBypassDnd(true);
2236         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
2237         assertFalse(mHelper.areChannelsBypassingDnd());
2238         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2239         resetZenModeHelper();
2240     }
2241 
2242     @Test
testUpdateCanChannelsBypassDnd()2243     public void testUpdateCanChannelsBypassDnd() {
2244         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
2245         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
2246 
2247         // create notification channel that can't bypass dnd
2248         // expected result: areChannelsBypassingDnd = false
2249         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
2250         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
2251         mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false);
2252         assertFalse(mHelper.areChannelsBypassingDnd());
2253         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2254         resetZenModeHelper();
2255 
2256         // update channel so it CAN bypass dnd:
2257         // expected result: areChannelsBypassingDnd = true
2258         channel.setBypassDnd(true);
2259         mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true);
2260         assertTrue(mHelper.areChannelsBypassingDnd());
2261         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2262         resetZenModeHelper();
2263 
2264         // update channel so it can't bypass dnd:
2265         // expected result: areChannelsBypassingDnd = false
2266         channel.setBypassDnd(false);
2267         mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true);
2268         assertFalse(mHelper.areChannelsBypassingDnd());
2269         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2270         resetZenModeHelper();
2271     }
2272 
2273     @Test
testSetupNewZenModeHelper_canBypass()2274     public void testSetupNewZenModeHelper_canBypass() {
2275         // start notification policy off with mAreChannelsBypassingDnd = true, but
2276         // RankingHelper should change to false
2277         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
2278                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
2279         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
2280         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
2281                 mPermissionHelper, mLogger,
2282                 mAppOpsManager, mStatsEventBuilderFactory, false);
2283         assertFalse(mHelper.areChannelsBypassingDnd());
2284         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
2285         resetZenModeHelper();
2286     }
2287 
2288     @Test
testSetupNewZenModeHelper_cannotBypass()2289     public void testSetupNewZenModeHelper_cannotBypass() {
2290         // start notification policy off with mAreChannelsBypassingDnd = false
2291         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
2292         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
2293         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
2294                 mPermissionHelper, mLogger,
2295                 mAppOpsManager, mStatsEventBuilderFactory, false);
2296         assertFalse(mHelper.areChannelsBypassingDnd());
2297         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
2298         resetZenModeHelper();
2299     }
2300 
2301     @Test
testCreateDeletedChannel()2302     public void testCreateDeletedChannel() throws Exception {
2303         long[] vibration = new long[]{100, 67, 145, 156};
2304         NotificationChannel channel =
2305                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2306         channel.setVibrationPattern(vibration);
2307 
2308         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
2309         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
2310 
2311         NotificationChannel newChannel = new NotificationChannel(
2312                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
2313         newChannel.setVibrationPattern(new long[]{100});
2314 
2315         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false);
2316 
2317         // No long deleted, using old settings
2318         compareChannels(channel,
2319                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
2320     }
2321 
2322     @Test
testOnlyHasDefaultChannel()2323     public void testOnlyHasDefaultChannel() throws Exception {
2324         assertTrue(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
2325         assertFalse(mHelper.onlyHasDefaultChannel(PKG_O, UID_O));
2326 
2327         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
2328         assertFalse(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
2329     }
2330 
2331     @Test
testCreateChannel_defaultChannelId()2332     public void testCreateChannel_defaultChannelId() throws Exception {
2333         try {
2334             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel(
2335                     NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false);
2336             fail("Allowed to create default channel");
2337         } catch (IllegalArgumentException e) {
2338             // pass
2339         }
2340     }
2341 
2342     @Test
testCreateChannel_alreadyExists()2343     public void testCreateChannel_alreadyExists() throws Exception {
2344         long[] vibration = new long[]{100, 67, 145, 156};
2345         NotificationChannel channel =
2346                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2347         channel.setVibrationPattern(vibration);
2348 
2349         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false));
2350 
2351         NotificationChannel newChannel = new NotificationChannel(
2352                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
2353         newChannel.setVibrationPattern(new long[]{100});
2354         newChannel.setAllowBubbles(!channel.canBubble());
2355         newChannel.setLightColor(Color.BLUE);
2356         newChannel.setSound(Uri.EMPTY, null);
2357         newChannel.setShowBadge(!channel.canShowBadge());
2358 
2359         assertFalse(mHelper.createNotificationChannel(
2360                 PKG_N_MR1, UID_N_MR1, newChannel, true, false));
2361 
2362         // Old settings not overridden
2363         compareChannels(channel,
2364                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
2365 
2366         assertEquals(1, mLogger.getCalls().size());
2367         assertEquals(
2368                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
2369                 mLogger.get(0).event);
2370     }
2371 
2372     @Test
testCreateChannel_noOverrideSound()2373     public void testCreateChannel_noOverrideSound() throws Exception {
2374         Uri sound = new Uri.Builder().scheme("test").build();
2375         final NotificationChannel channel = new NotificationChannel("id2", "name2",
2376                  NotificationManager.IMPORTANCE_DEFAULT);
2377         channel.setSound(sound, mAudioAttributes);
2378         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
2379         assertEquals(sound, mHelper.getNotificationChannel(
2380                 PKG_N_MR1, UID_N_MR1, channel.getId(), false).getSound());
2381     }
2382 
2383     @Test
testPermanentlyDeleteChannels()2384     public void testPermanentlyDeleteChannels() throws Exception {
2385         NotificationChannel channel1 =
2386                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2387         NotificationChannel channel2 =
2388                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2389 
2390         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2391         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
2392 
2393         mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1);
2394 
2395         // Only default channel remains
2396         assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList().size());
2397     }
2398 
2399     @Test
testDeleteGroup()2400     public void testDeleteGroup() throws Exception {
2401         NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
2402         NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted");
2403         NotificationChannel nonGroupedNonDeletedChannel =
2404                 new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH);
2405         NotificationChannel groupedButNotDeleted =
2406                 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
2407         groupedButNotDeleted.setGroup("not");
2408         NotificationChannel groupedAndDeleted =
2409                 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
2410         groupedAndDeleted.setGroup("totally");
2411 
2412         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
2413         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true);
2414         mHelper.createNotificationChannel(
2415                 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false);
2416         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false);
2417         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false);
2418 
2419         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId());
2420 
2421         assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1));
2422         assertNotNull(
2423                 mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
2424 
2425         assertNull(mHelper.getNotificationChannel(
2426                 PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
2427         compareChannels(groupedAndDeleted, mHelper.getNotificationChannel(
2428                 PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
2429 
2430         compareChannels(groupedButNotDeleted, mHelper.getNotificationChannel(
2431                 PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
2432         compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
2433                 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel.getId(), false));
2434 
2435         // notDeleted
2436         assertEquals(1, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).size());
2437 
2438         verify(mHandler, never()).requestSort();
2439 
2440         assertEquals(7, mLogger.getCalls().size());
2441         assertEquals(
2442                 NotificationChannelLogger.NotificationChannelEvent
2443                         .NOTIFICATION_CHANNEL_GROUP_DELETED,
2444                 mLogger.get(5).event);  // Next-to-last log is the deletion of the channel group.
2445         assertEquals(
2446                 NotificationChannelLogger.NotificationChannelEvent
2447                         .NOTIFICATION_CHANNEL_DELETED,
2448                 mLogger.get(6).event);  // Final log is the deletion of the channel.
2449     }
2450 
2451     @Test
testOnUserRemoved()2452     public void testOnUserRemoved() throws Exception {
2453         int[] user0Uids = {98, 235, 16, 3782};
2454         int[] user1Uids = new int[user0Uids.length];
2455         for (int i = 0; i < user0Uids.length; i++) {
2456             user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i];
2457 
2458             final ApplicationInfo legacy = new ApplicationInfo();
2459             legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
2460             when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
2461 
2462             // create records with the default channel for all user 0 and user 1 uids
2463             mHelper.canShowBadge(PKG_N_MR1, user0Uids[i]);
2464             mHelper.canShowBadge(PKG_N_MR1, user1Uids[i]);
2465         }
2466 
2467         mHelper.onUserRemoved(1);
2468 
2469         // user 0 records remain
2470         for (int i = 0; i < user0Uids.length; i++) {
2471             assertEquals(1,
2472                     mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false).getList().size());
2473         }
2474         // user 1 records are gone
2475         for (int i = 0; i < user1Uids.length; i++) {
2476             assertEquals(0,
2477                     mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false).getList().size());
2478         }
2479     }
2480 
2481     @Test
testOnPackageChanged_packageRemoval()2482     public void testOnPackageChanged_packageRemoval() throws Exception {
2483         // Deleted
2484         NotificationChannel channel1 =
2485                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2486         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2487 
2488         assertTrue(mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1},
2489                 new int[]{UID_N_MR1}));
2490 
2491         assertEquals(0, mHelper.getNotificationChannels(
2492                 PKG_N_MR1, UID_N_MR1, true).getList().size());
2493 
2494         // Not deleted
2495         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2496 
2497         assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM,
2498                 new String[]{PKG_N_MR1}, new int[]{UID_N_MR1}));
2499         assertEquals(2, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
2500     }
2501 
2502     @Test
testOnPackageChanged_packageRemoval_groups()2503     public void testOnPackageChanged_packageRemoval_groups() throws Exception {
2504         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2505         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
2506         NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
2507         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
2508 
2509         mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
2510                 UID_N_MR1});
2511 
2512         assertEquals(0, mHelper.getNotificationChannelGroups(
2513                 PKG_N_MR1, UID_N_MR1, true, true, false).getList().size());
2514     }
2515 
2516     @Test
testOnPackageChange_downgradeTargetSdk()2517     public void testOnPackageChange_downgradeTargetSdk() throws Exception {
2518         // create channel as api 26
2519         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
2520 
2521         // install new app version targeting 25
2522         final ApplicationInfo legacy = new ApplicationInfo();
2523         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
2524         when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(legacy);
2525         mHelper.onPackagesChanged(
2526                 false, USER_SYSTEM, new String[]{PKG_O}, new int[]{UID_O});
2527 
2528         // make sure the default channel was readded
2529         //assertEquals(2, mHelper.getNotificationChannels(PKG_O, UID_O, false).getList().size());
2530         assertNotNull(mHelper.getNotificationChannel(
2531                 PKG_O, UID_O, NotificationChannel.DEFAULT_CHANNEL_ID, false));
2532     }
2533 
2534     @Test
testClearData()2535     public void testClearData() {
2536         ArraySet<String> pkg = new ArraySet<>();
2537         pkg.add(PKG_O);
2538         ArraySet<Pair<String, Integer>> pkgPair = new ArraySet<>();
2539         pkgPair.add(new Pair(PKG_O, UID_O));
2540         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
2541         mHelper.createNotificationChannelGroup(
2542                 PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true);
2543         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkgPair);
2544         mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1);
2545         mHelper.setBubblesAllowed(PKG_O, UID_O, DEFAULT_BUBBLE_PREFERENCE);
2546         mHelper.setShowBadge(PKG_O, UID_O, false);
2547         mHelper.setAppImportanceLocked(PKG_O, UID_O);
2548 
2549         mHelper.clearData(PKG_O, UID_O);
2550 
2551         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), DEFAULT_BUBBLE_PREFERENCE);
2552         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
2553         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
2554         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
2555         assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true).getList().size());
2556         assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size());
2557 
2558         NotificationChannel channel = getChannel();
2559         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
2560 
2561         assertTrue(channel.isImportanceLockedByCriticalDeviceFunction());
2562     }
2563 
2564     @Test
testRecordDefaults()2565     public void testRecordDefaults() throws Exception {
2566         assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
2567         assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
2568     }
2569 
2570     @Test
testCreateGroup()2571     public void testCreateGroup() {
2572         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2573         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
2574         assertEquals(ncg,
2575                 mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
2576         verify(mHandler, never()).requestSort();
2577         assertEquals(1, mLogger.getCalls().size());
2578         assertEquals(
2579                 NotificationChannelLogger.NotificationChannelEvent
2580                         .NOTIFICATION_CHANNEL_GROUP_CREATED,
2581                 mLogger.get(0).event);
2582     }
2583 
2584     @Test
testCannotCreateChannel_badGroup()2585     public void testCannotCreateChannel_badGroup() {
2586         NotificationChannel channel1 =
2587                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2588         channel1.setGroup("garbage");
2589         try {
2590             mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2591             fail("Created a channel with a bad group");
2592         } catch (IllegalArgumentException e) {
2593         }
2594         assertEquals(0, mLogger.getCalls().size());
2595     }
2596 
2597     @Test
testCannotCreateChannel_goodGroup()2598     public void testCannotCreateChannel_goodGroup() {
2599         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2600         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
2601         NotificationChannel channel1 =
2602                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2603         channel1.setGroup(ncg.getId());
2604         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2605 
2606         assertEquals(ncg.getId(), mHelper.getNotificationChannel(
2607                 PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
2608     }
2609 
2610     @Test
testGetChannelGroups()2611     public void testGetChannelGroups() {
2612         NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
2613         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true);
2614         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2615         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
2616         NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
2617         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
2618 
2619         NotificationChannel channel1 =
2620                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2621         channel1.setGroup(ncg.getId());
2622         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2623         NotificationChannel channel1a =
2624                 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
2625         channel1a.setGroup(ncg.getId());
2626         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1a, true, false);
2627 
2628         NotificationChannel channel2 =
2629                 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
2630         channel2.setGroup(ncg2.getId());
2631         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
2632 
2633         NotificationChannel channel3 =
2634                 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
2635         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
2636 
2637         List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
2638                 PKG_N_MR1, UID_N_MR1, true, true, false).getList();
2639         assertEquals(3, actual.size());
2640         for (NotificationChannelGroup group : actual) {
2641             if (group.getId() == null) {
2642                 assertEquals(2, group.getChannels().size()); // misc channel too
2643                 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
2644                         || channel3.getId().equals(group.getChannels().get(1).getId()));
2645             } else if (group.getId().equals(ncg.getId())) {
2646                 assertEquals(2, group.getChannels().size());
2647                 if (group.getChannels().get(0).getId().equals(channel1.getId())) {
2648                     assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId()));
2649                 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) {
2650                     assertTrue(group.getChannels().get(1).getId().equals(channel1.getId()));
2651                 } else {
2652                     fail("expected channel not found");
2653                 }
2654             } else if (group.getId().equals(ncg2.getId())) {
2655                 assertEquals(1, group.getChannels().size());
2656                 assertEquals(channel2.getId(), group.getChannels().get(0).getId());
2657             }
2658         }
2659     }
2660 
2661     @Test
testGetChannelGroups_noSideEffects()2662     public void testGetChannelGroups_noSideEffects() {
2663         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2664         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
2665 
2666         NotificationChannel channel1 =
2667                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2668         channel1.setGroup(ncg.getId());
2669         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2670         mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false).getList();
2671 
2672         channel1.setImportance(IMPORTANCE_LOW);
2673         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true);
2674 
2675         List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
2676                 PKG_N_MR1, UID_N_MR1, true, true, false).getList();
2677 
2678         assertEquals(2, actual.size());
2679         for (NotificationChannelGroup group : actual) {
2680             if (Objects.equals(group.getId(), ncg.getId())) {
2681                 assertEquals(1, group.getChannels().size());
2682             }
2683         }
2684     }
2685 
2686     @Test
testGetChannelGroups_includeEmptyGroups()2687     public void testGetChannelGroups_includeEmptyGroups() {
2688         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
2689         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
2690         NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2");
2691         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true);
2692 
2693         NotificationChannel channel1 =
2694                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2695         channel1.setGroup(ncg.getId());
2696         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
2697 
2698         List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
2699                 PKG_N_MR1, UID_N_MR1, false, false, true).getList();
2700 
2701         assertEquals(2, actual.size());
2702         for (NotificationChannelGroup group : actual) {
2703             if (Objects.equals(group.getId(), ncg.getId())) {
2704                 assertEquals(1, group.getChannels().size());
2705             }
2706             if (Objects.equals(group.getId(), ncgEmpty.getId())) {
2707                 assertEquals(0, group.getChannels().size());
2708             }
2709         }
2710     }
2711 
2712     @Test
testCreateChannel_updateName()2713     public void testCreateChannel_updateName() {
2714         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
2715         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false));
2716         NotificationChannel actual =
2717                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
2718         assertEquals("hello", actual.getName());
2719 
2720         nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
2721         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false));
2722 
2723         actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
2724         assertEquals("goodbye", actual.getName());
2725         assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
2726 
2727         verify(mHandler, times(1)).requestSort();
2728     }
2729 
2730     @Test
testCreateChannel_addToGroup()2731     public void testCreateChannel_addToGroup() {
2732         NotificationChannelGroup group = new NotificationChannelGroup("group", "");
2733         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
2734         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
2735         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false));
2736         NotificationChannel actual =
2737                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
2738         assertNull(actual.getGroup());
2739 
2740         nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
2741         nc.setGroup(group.getId());
2742         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false));
2743 
2744         actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
2745         assertNotNull(actual.getGroup());
2746         assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
2747 
2748         verify(mHandler, times(1)).requestSort();
2749         assertEquals(3, mLogger.getCalls().size());
2750         assertEquals(
2751                 NotificationChannelLogger.NotificationChannelEvent
2752                         .NOTIFICATION_CHANNEL_GROUP_CREATED,
2753                 mLogger.get(0).event);
2754         assertEquals(
2755                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
2756                 mLogger.get(1).event);
2757         assertEquals(
2758                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED,
2759                 mLogger.get(2).event);
2760     }
2761 
2762     @Test
testDumpChannelsJson()2763     public void testDumpChannelsJson() throws Exception {
2764         final ApplicationInfo upgrade = new ApplicationInfo();
2765         upgrade.targetSdkVersion = Build.VERSION_CODES.O;
2766         try {
2767             when(mPm.getApplicationInfoAsUser(
2768                     anyString(), anyInt(), anyInt())).thenReturn(upgrade);
2769         } catch (PackageManager.NameNotFoundException e) {
2770         }
2771         ArrayMap<String, Integer> expectedChannels = new ArrayMap<>();
2772         int numPackages = ThreadLocalRandom.current().nextInt(1, 5);
2773         for (int i = 0; i < numPackages; i++) {
2774             String pkgName = "pkg" + i;
2775             int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
2776             for (int j = 0; j < numChannels; j++) {
2777                 mHelper.createNotificationChannel(pkgName, UID_N_MR1,
2778                         new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false);
2779             }
2780             expectedChannels.put(pkgName, numChannels);
2781         }
2782 
2783         // delete the first channel of the first package
2784         String pkg = expectedChannels.keyAt(0);
2785         mHelper.deleteNotificationChannel("pkg" + 0, UID_N_MR1, "0");
2786         // dump should not include deleted channels
2787         int count = expectedChannels.get(pkg);
2788         expectedChannels.put(pkg, count - 1);
2789 
2790         JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter());
2791         assertEquals(numPackages, actual.length());
2792         for (int i = 0; i < numPackages; i++) {
2793             JSONObject object = actual.getJSONObject(i);
2794             assertTrue(expectedChannels.containsKey(object.get("packageName")));
2795             assertEquals(expectedChannels.get(object.get("packageName")).intValue(),
2796                     object.getInt("channelCount"));
2797         }
2798     }
2799 
2800     @Test
testDumpJson_postPermissionMigration()2801     public void testDumpJson_postPermissionMigration() throws Exception {
2802         // when getting a json dump, we want to verify that:
2803         //   - all notification importance info should come from the permission, even if the data
2804         //     isn't there yet but is present in package preferences
2805         //   - if there are permissions granted or denied from packages PreferencesHelper doesn't
2806         //     know about, those should still be included
2807 
2808         // package permissions map to be passed in
2809         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
2810         appPermissions.put(new Pair(1, "first"), new Pair(true, false));    // not in local prefs
2811         appPermissions.put(new Pair(3, "third"), new Pair(false, false));   // not in local prefs
2812         appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));  // in local prefs
2813         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
2814 
2815         NotificationChannel channel1 =
2816                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
2817         NotificationChannel channel2 =
2818                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
2819         NotificationChannel channel3 = new NotificationChannel("id3", "name3", IMPORTANCE_HIGH);
2820 
2821         mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false);
2822         mHelper.createNotificationChannel(PKG_P, UID_P, channel2, false, false);
2823         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
2824         mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
2825 
2826         // in the json array, all of the individual package preferences are simply elements in the
2827         // values array. this set is to collect expected outputs for each of our packages.
2828         // the key/value pairs are: (userId, package name) -> expected importance
2829         ArrayMap<Pair<Integer, String>, String> expected = new ArrayMap<>();
2830 
2831         // packages that only exist via the app permissions; should be present
2832         expected.put(new Pair(UserHandle.getUserId(1), "first"), "DEFAULT");
2833         expected.put(new Pair(UserHandle.getUserId(3), "third"), "NONE");
2834 
2835         // packages that exist in both app permissions & local preferences
2836         expected.put(new Pair(UserHandle.getUserId(UID_P), PKG_P), "DEFAULT");
2837         expected.put(new Pair(UserHandle.getUserId(UID_O), PKG_O), "NONE");
2838 
2839         // package that only exists in local preferences; expect no importance output
2840         expected.put(new Pair(UserHandle.getUserId(UID_N_MR1), PKG_N_MR1), null);
2841 
2842         JSONArray actual = (JSONArray) mHelper.dumpJson(
2843                 new NotificationManagerService.DumpFilter(), appPermissions)
2844                 .get("PackagePreferencess");
2845         assertThat(actual.length()).isEqualTo(expected.size());
2846         for (int i = 0; i < actual.length(); i++) {
2847             JSONObject pkgInfo = actual.getJSONObject(i);
2848             Pair<Integer, String> pkgKey =
2849                     new Pair(pkgInfo.getInt("userId"), pkgInfo.getString("packageName"));
2850             assertTrue(expected.containsKey(pkgKey));
2851             if (pkgInfo.has("importance")) {
2852                 assertThat(pkgInfo.getString("importance")).isEqualTo(expected.get(pkgKey));
2853             } else {
2854                 assertThat(expected.get(pkgKey)).isNull();
2855             }
2856         }
2857     }
2858 
2859     @Test
testDumpJson_givenNullInput_postMigration()2860     public void testDumpJson_givenNullInput_postMigration() throws Exception {
2861         // simple test just to make sure nothing dies if we pass in null input even post migration
2862         // for some reason, even though in practice this should not be how one calls this method
2863 
2864         // some packages exist
2865         mHelper.canShowBadge(PKG_O, UID_O);
2866         mHelper.canShowBadge(PKG_P, UID_P);
2867 
2868         JSONArray actual = (JSONArray) mHelper.dumpJson(
2869                 new NotificationManagerService.DumpFilter(), null)
2870                 .get("PackagePreferencess");
2871 
2872         // there should still be info for the packages
2873         assertThat(actual.length()).isEqualTo(2);
2874 
2875         // but they should not have importance info because the migration is enabled and it got
2876         // no info
2877         for (int i = 0; i < actual.length(); i++) {
2878             assertFalse(actual.getJSONObject(i).has("importance"));
2879         }
2880     }
2881 
2882     @Test
testDumpBansJson_postPermissionMigration()2883     public void testDumpBansJson_postPermissionMigration() throws Exception {
2884         // confirm that the package bans that are in the output include all packages that
2885         // have their permission set to false, and not based on PackagePreferences importance
2886 
2887         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
2888         appPermissions.put(new Pair(1, "first"), new Pair(true, false));    // not in local prefs
2889         appPermissions.put(new Pair(3, "third"), new Pair(false, false));   // not in local prefs
2890         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
2891 
2892         mHelper.canShowBadge(PKG_O, UID_O);
2893 
2894         // expected output
2895         ArraySet<Pair<Integer, String>> expected = new ArraySet<>();
2896         expected.add(new Pair(UserHandle.getUserId(3), "third"));
2897         expected.add(new Pair(UserHandle.getUserId(UID_O), PKG_O));
2898 
2899         // make sure that's the only thing in the package ban output
2900         JSONArray actual = mHelper.dumpBansJson(
2901                 new NotificationManagerService.DumpFilter(), appPermissions);
2902         assertThat(actual.length()).isEqualTo(expected.size());
2903 
2904         for (int i = 0; i < actual.length(); i++) {
2905             JSONObject ban = actual.getJSONObject(i);
2906             assertTrue(expected.contains(
2907                     new Pair(ban.getInt("userId"), ban.getString("packageName"))));
2908         }
2909     }
2910 
2911     @Test
testDumpBansJson_givenNullInput()2912     public void testDumpBansJson_givenNullInput() throws Exception {
2913         // no one should do this, but...
2914 
2915         JSONArray actual = mHelper.dumpBansJson(
2916                 new NotificationManagerService.DumpFilter(), null);
2917         assertThat(actual.length()).isEqualTo(0);
2918     }
2919 
2920     @Test
testDumpString_postPermissionMigration()2921     public void testDumpString_postPermissionMigration() {
2922         // confirm that the string resulting from dumpImpl contains only importances from permission
2923 
2924         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
2925         appPermissions.put(new Pair(1, "first"), new Pair(true, false));    // not in local prefs
2926         appPermissions.put(new Pair(3, "third"), new Pair(false, true));   // not in local prefs
2927         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
2928 
2929         // local package preferences
2930         mHelper.canShowBadge(PKG_O, UID_O);
2931         mHelper.canShowBadge(PKG_P, UID_P);
2932 
2933         // get dump output as a string so we can inspect the contents later
2934         StringWriter sw = new StringWriter();
2935         PrintWriter pw = new PrintWriter(sw);
2936         mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), appPermissions);
2937         pw.flush();
2938         String actual = sw.toString();
2939 
2940         // expected (substring) output for each preference via permissions
2941         ArrayList<String> expected = new ArrayList<>();
2942         expected.add("first (1) importance=DEFAULT userSet=false");
2943         expected.add("third (3) importance=NONE userSet=true");
2944         expected.add(PKG_O + " (" + UID_O + ") importance=NONE userSet=false");
2945         expected.add(PKG_P + " (" + UID_P + ")");
2946 
2947         // make sure we don't have package preference info
2948         ArrayList<String> notExpected = new ArrayList<>();
2949         notExpected.add(PKG_O + " (" + UID_O + ") importance=HIGH");
2950         notExpected.add(PKG_P + " (" + UID_P + ") importance=");  // no importance for PKG_P
2951 
2952         for (String exp : expected) {
2953             assertTrue(actual.contains(exp));
2954         }
2955 
2956         for (String notExp : notExpected) {
2957             assertFalse(actual.contains(notExp));
2958         }
2959     }
2960 
2961     @Test
testDumpString_givenNullInput()2962     public void testDumpString_givenNullInput() {
2963         // test that this doesn't choke on null input
2964 
2965         // local package preferences
2966         mHelper.canShowBadge(PKG_O, UID_O);
2967         mHelper.canShowBadge(PKG_P, UID_P);
2968 
2969         // get dump output
2970         StringWriter sw = new StringWriter();
2971         PrintWriter pw = new PrintWriter(sw);
2972         mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), null);
2973         pw.flush();
2974         String actual = sw.toString();
2975 
2976         // nobody gets any importance
2977         assertFalse(actual.contains("importance="));
2978     }
2979 
2980     @Test
testDumpProto_postPermissionMigration()2981     public void testDumpProto_postPermissionMigration() throws Exception {
2982         // test that dumping to proto gets the importances from the right place
2983 
2984         // permissions -- these should take precedence
2985         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
2986         appPermissions.put(new Pair(1, "first"), new Pair(true, false));    // not in local prefs
2987         appPermissions.put(new Pair(3, "third"), new Pair(false, false));   // not in local prefs
2988         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
2989 
2990         // local package preferences
2991         mHelper.canShowBadge(PKG_O, UID_O);
2992         mHelper.canShowBadge(PKG_P, UID_P);
2993 
2994         // expected output: all the packages, but only the ones provided via appPermissions
2995         // should have importance set (aka not PKG_P)
2996         // map format: (uid, package name) -> importance (int)
2997         ArrayMap<Pair<Integer, String>, Integer> expected = new ArrayMap<>();
2998         expected.put(new Pair(1, "first"), IMPORTANCE_DEFAULT);
2999         expected.put(new Pair(3, "third"), IMPORTANCE_NONE);
3000         expected.put(new Pair(UID_O, PKG_O), IMPORTANCE_NONE);
3001 
3002         // unfortunately, due to how nano protos work, there's no distinction between unset
3003         // fields and default-value fields, so we have no choice here but to check for a value of 0.
3004         // at least we can make sure the local importance for PKG_P in this test is not 0 (NONE).
3005         expected.put(new Pair(UID_P, PKG_P), 0);
3006 
3007         // get the proto output and inspect its contents
3008         ProtoOutputStream proto = new ProtoOutputStream();
3009         mHelper.dump(proto, new NotificationManagerService.DumpFilter(), appPermissions);
3010 
3011         RankingHelperProto actual = RankingHelperProto.parseFrom(proto.getBytes());
3012         assertThat(actual.records.length).isEqualTo(expected.size());
3013         for (int i = 0; i < actual.records.length; i++) {
3014             RankingHelperProto.RecordProto record = actual.records[i];
3015             Pair<Integer, String> pkgKey = new Pair(record.uid, record.package_);
3016             assertTrue(expected.containsKey(pkgKey));
3017             assertThat(record.importance).isEqualTo(expected.get(pkgKey));
3018         }
3019     }
3020 
3021     @Test
testBadgingOverrideTrue()3022     public void testBadgingOverrideTrue() throws Exception {
3023         Secure.putIntForUser(getContext().getContentResolver(),
3024                 Secure.NOTIFICATION_BADGING, 1,
3025                 USER.getIdentifier());
3026         mHelper.updateBadgingEnabled(); // would be called by settings observer
3027         assertTrue(mHelper.badgingEnabled(USER));
3028     }
3029 
3030     @Test
testBadgingOverrideFalse()3031     public void testBadgingOverrideFalse() throws Exception {
3032         Secure.putIntForUser(getContext().getContentResolver(),
3033                 Secure.NOTIFICATION_BADGING, 0,
3034                 USER.getIdentifier());
3035         mHelper.updateBadgingEnabled(); // would be called by settings observer
3036         assertFalse(mHelper.badgingEnabled(USER));
3037     }
3038 
3039     @Test
testBadgingForUserAll()3040     public void testBadgingForUserAll() throws Exception {
3041         try {
3042             mHelper.badgingEnabled(UserHandle.ALL);
3043         } catch (Exception e) {
3044             fail("just don't throw");
3045         }
3046     }
3047 
3048     @Test
testBadgingOverrideUserIsolation()3049     public void testBadgingOverrideUserIsolation() throws Exception {
3050         Secure.putIntForUser(getContext().getContentResolver(),
3051                 Secure.NOTIFICATION_BADGING, 0,
3052                 USER.getIdentifier());
3053         Secure.putIntForUser(getContext().getContentResolver(),
3054                 Secure.NOTIFICATION_BADGING, 1,
3055                 USER2.getIdentifier());
3056         mHelper.updateBadgingEnabled(); // would be called by settings observer
3057         assertFalse(mHelper.badgingEnabled(USER));
3058         assertTrue(mHelper.badgingEnabled(USER2));
3059     }
3060 
3061     @Test
testBubblesOverrideTrue()3062     public void testBubblesOverrideTrue() {
3063         Secure.putIntForUser(getContext().getContentResolver(),
3064                 Secure.NOTIFICATION_BUBBLES, 1,
3065                 USER.getIdentifier());
3066         mHelper.updateBubblesEnabled(); // would be called by settings observer
3067         assertTrue(mHelper.bubblesEnabled(USER));
3068     }
3069 
3070     @Test
testBubblesOverrideFalse()3071     public void testBubblesOverrideFalse() {
3072         Secure.putIntForUser(getContext().getContentResolver(),
3073                 Secure.NOTIFICATION_BUBBLES, 0,
3074                 USER.getIdentifier());
3075         mHelper.updateBubblesEnabled(); // would be called by settings observer
3076         assertFalse(mHelper.bubblesEnabled(USER));
3077     }
3078 
3079     @Test
testBubblesOverrideUserIsolation()3080     public void testBubblesOverrideUserIsolation() throws Exception {
3081         Secure.putIntForUser(getContext().getContentResolver(),
3082                 Secure.NOTIFICATION_BUBBLES, 0,
3083                 USER.getIdentifier());
3084         Secure.putIntForUser(getContext().getContentResolver(),
3085                 Secure.NOTIFICATION_BUBBLES, 1,
3086                 USER2.getIdentifier());
3087         mHelper.updateBubblesEnabled(); // would be called by settings observer
3088         assertFalse(mHelper.bubblesEnabled(USER));
3089         assertTrue(mHelper.bubblesEnabled(USER2));
3090     }
3091 
3092     @Test
testShowQSMediaOverrideTrue()3093     public void testShowQSMediaOverrideTrue() {
3094         Global.putInt(getContext().getContentResolver(),
3095                 Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1);
3096         mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer
3097         assertTrue(mHelper.isMediaNotificationFilteringEnabled());
3098     }
3099 
3100     @Test
testShowQSMediaOverrideFalse()3101     public void testShowQSMediaOverrideFalse() {
3102         Global.putInt(getContext().getContentResolver(),
3103                 Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0);
3104         mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer
3105         assertFalse(mHelper.isMediaNotificationFilteringEnabled());
3106     }
3107 
3108     @Test
testOnLocaleChanged_updatesDefaultChannels()3109     public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
3110         String newLabel = "bananas!";
3111         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
3112                 UID_N_MR1,
3113                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
3114         assertFalse(newLabel.equals(defaultChannel.getName()));
3115 
3116         Resources res = mock(Resources.class);
3117         when(mContext.getResources()).thenReturn(res);
3118         when(res.getString(com.android.internal.R.string.default_notification_channel_label))
3119                 .thenReturn(newLabel);
3120 
3121         mHelper.onLocaleChanged(mContext, USER.getIdentifier());
3122 
3123         assertEquals(newLabel, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
3124                 NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
3125     }
3126 
3127     @Test
testIsGroupBlocked_noGroup()3128     public void testIsGroupBlocked_noGroup() throws Exception {
3129         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, null));
3130 
3131         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, "non existent group"));
3132     }
3133 
3134     @Test
testIsGroupBlocked_notBlocked()3135     public void testIsGroupBlocked_notBlocked() throws Exception {
3136         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
3137         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
3138 
3139         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
3140     }
3141 
3142     @Test
testIsGroupBlocked_blocked()3143     public void testIsGroupBlocked_blocked() throws Exception {
3144         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
3145         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
3146         group.setBlocked(true);
3147         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, false);
3148 
3149         assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
3150     }
3151 
3152     @Test
testIsGroupBlocked_appCannotCreateAsBlocked()3153     public void testIsGroupBlocked_appCannotCreateAsBlocked() throws Exception {
3154         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
3155         group.setBlocked(true);
3156         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
3157         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
3158 
3159         NotificationChannelGroup group3 = group.clone();
3160         group3.setBlocked(false);
3161         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true);
3162         assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
3163     }
3164 
3165     @Test
testIsGroup_appCannotResetBlock()3166     public void testIsGroup_appCannotResetBlock() throws Exception {
3167         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
3168         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
3169         NotificationChannelGroup group2 = group.clone();
3170         group2.setBlocked(true);
3171         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group2, false);
3172         assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
3173 
3174         NotificationChannelGroup group3 = group.clone();
3175         group3.setBlocked(false);
3176         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true);
3177         assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
3178     }
3179 
3180     @Test
testGetNotificationChannelGroupWithChannels()3181     public void testGetNotificationChannelGroupWithChannels() throws Exception {
3182         NotificationChannelGroup group = new NotificationChannelGroup("group", "");
3183         NotificationChannelGroup other = new NotificationChannelGroup("something else", "");
3184         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
3185         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true);
3186 
3187         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
3188         a.setGroup(group.getId());
3189         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
3190         b.setGroup(other.getId());
3191         NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
3192         c.setGroup(group.getId());
3193         NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT);
3194 
3195         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, a, true, false);
3196         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, true, false);
3197         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, c, true, false);
3198         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, d, true, false);
3199         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, c.getId());
3200 
3201         NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels(
3202                 PKG_N_MR1, UID_N_MR1, group.getId(), true);
3203         assertEquals(2, retrieved.getChannels().size());
3204         compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
3205         compareChannels(c, findChannel(retrieved.getChannels(), c.getId()));
3206 
3207         retrieved = mHelper.getNotificationChannelGroupWithChannels(
3208                 PKG_N_MR1, UID_N_MR1, group.getId(), false);
3209         assertEquals(1, retrieved.getChannels().size());
3210         compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
3211     }
3212 
3213     @Test
testAndroidPkgCannotBypassDnd_creation()3214     public void testAndroidPkgCannotBypassDnd_creation() {
3215         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3216         test.setBypassDnd(true);
3217 
3218         mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false);
3219 
3220         assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
3221                 .canBypassDnd());
3222     }
3223 
3224     @Test
testDndPkgCanBypassDnd_creation()3225     public void testDndPkgCanBypassDnd_creation() {
3226         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3227         test.setBypassDnd(true);
3228 
3229         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true);
3230 
3231         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd());
3232     }
3233 
3234     @Test
testNormalPkgCannotBypassDnd_creation()3235     public void testNormalPkgCannotBypassDnd_creation() {
3236         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3237         test.setBypassDnd(true);
3238 
3239         mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false);
3240 
3241         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd());
3242     }
3243 
3244     @Test
testAndroidPkgCannotBypassDnd_update()3245     public void testAndroidPkgCannotBypassDnd_update() throws Exception {
3246         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3247         mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false);
3248 
3249         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3250         update.setBypassDnd(true);
3251         assertFalse(mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false));
3252 
3253         assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
3254                 .canBypassDnd());
3255     }
3256 
3257     @Test
testDndPkgCanBypassDnd_update()3258     public void testDndPkgCanBypassDnd_update() throws Exception {
3259         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3260         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true);
3261 
3262         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3263         update.setBypassDnd(true);
3264         assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, true));
3265 
3266         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd());
3267     }
3268 
3269     @Test
testNormalPkgCannotBypassDnd_update()3270     public void testNormalPkgCannotBypassDnd_update() {
3271         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3272         mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false);
3273         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
3274         update.setBypassDnd(true);
3275         mHelper.createNotificationChannel(PKG_N_MR1, 1000, update, true, false);
3276         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd());
3277     }
3278 
3279     @Test
testXml_statusBarIcons_default()3280     public void testXml_statusBarIcons_default() throws Exception {
3281         String preQXml = "<ranking version=\"1\">\n"
3282                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
3283                 + "<channel id=\"something\" name=\"name\" importance=\"2\" "
3284                 + "show_badge=\"true\" />\n"
3285                 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" "
3286                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
3287                 + "</package>\n"
3288                 + "</ranking>\n";
3289         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3290                 mPermissionHelper, mLogger,
3291                 mAppOpsManager, mStatsEventBuilderFactory, false);
3292         loadByteArrayXml(preQXml.getBytes(), true, USER_SYSTEM);
3293 
3294         assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
3295                 mHelper.shouldHideSilentStatusIcons());
3296     }
3297 
3298     @Test
testXml_statusBarIcons()3299     public void testXml_statusBarIcons() throws Exception {
3300         mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
3301 
3302         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3303         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3304                 mPermissionHelper, mLogger,
3305                 mAppOpsManager, mStatsEventBuilderFactory, false);
3306         loadStreamXml(baos, false, UserHandle.USER_ALL);
3307 
3308         assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
3309                 mHelper.shouldHideSilentStatusIcons());
3310     }
3311 
3312     @Test
testSetNotificationDelegate()3313     public void testSetNotificationDelegate() {
3314         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3315         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
3316     }
3317 
3318     @Test
testRevokeNotificationDelegate()3319     public void testRevokeNotificationDelegate() {
3320         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3321         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
3322 
3323         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3324     }
3325 
3326     @Test
testRevokeNotificationDelegate_noDelegateExistsNoCrash()3327     public void testRevokeNotificationDelegate_noDelegateExistsNoCrash() {
3328         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
3329 
3330         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3331     }
3332 
3333     @Test
testToggleNotificationDelegate()3334     public void testToggleNotificationDelegate() {
3335         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3336         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
3337 
3338         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3339 
3340         mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
3341         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
3342     }
3343 
3344     @Test
testToggleNotificationDelegate_noDelegateExistsNoCrash()3345     public void testToggleNotificationDelegate_noDelegateExistsNoCrash() {
3346         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
3347         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3348 
3349         mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
3350         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3351     }
3352 
3353     @Test
testIsDelegateAllowed_noSource()3354     public void testIsDelegateAllowed_noSource() {
3355         assertFalse(mHelper.isDelegateAllowed("does not exist", -1, "whatever", 0));
3356     }
3357 
3358     @Test
testIsDelegateAllowed_noDelegate()3359     public void testIsDelegateAllowed_noDelegate() {
3360         mHelper.canShowBadge(PKG_O, UID_O);
3361 
3362         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0));
3363     }
3364 
3365     @Test
testIsDelegateAllowed_delegateDisabledByApp()3366     public void testIsDelegateAllowed_delegateDisabledByApp() {
3367         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3368         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
3369 
3370         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
3371     }
3372 
3373     @Test
testIsDelegateAllowed_wrongDelegate()3374     public void testIsDelegateAllowed_wrongDelegate() {
3375         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3376         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
3377 
3378         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "banana", 27));
3379     }
3380 
3381     @Test
testIsDelegateAllowed_delegateDisabledByUser()3382     public void testIsDelegateAllowed_delegateDisabledByUser() {
3383         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3384         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
3385 
3386         assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
3387     }
3388 
3389     @Test
testIsDelegateAllowed()3390     public void testIsDelegateAllowed() {
3391         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3392 
3393         assertTrue(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
3394     }
3395 
3396     @Test
testDelegateXml_noDelegate()3397     public void testDelegateXml_noDelegate() throws Exception {
3398         mHelper.canShowBadge(PKG_O, UID_O);
3399 
3400         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3401         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3402                 mPermissionHelper, mLogger,
3403                 mAppOpsManager, mStatsEventBuilderFactory, false);
3404         loadStreamXml(baos, false, UserHandle.USER_ALL);
3405 
3406         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3407     }
3408 
3409     @Test
testDelegateXml_delegate()3410     public void testDelegateXml_delegate() throws Exception {
3411         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3412 
3413         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3414         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3415                 mPermissionHelper, mLogger,
3416                 mAppOpsManager, mStatsEventBuilderFactory, false);
3417         loadStreamXml(baos, false, UserHandle.USER_ALL);
3418 
3419         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
3420     }
3421 
3422     @Test
testDelegateXml_disabledDelegate()3423     public void testDelegateXml_disabledDelegate() throws Exception {
3424         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3425         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
3426 
3427         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3428         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3429                 mPermissionHelper, mLogger,
3430                 mAppOpsManager, mStatsEventBuilderFactory, false);
3431         loadStreamXml(baos, false, UserHandle.USER_ALL);
3432 
3433         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3434     }
3435 
3436     @Test
testDelegateXml_userDisabledDelegate()3437     public void testDelegateXml_userDisabledDelegate() throws Exception {
3438         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3439         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
3440 
3441         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3442         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3443                 mPermissionHelper, mLogger,
3444                 mAppOpsManager, mStatsEventBuilderFactory, false);
3445         loadStreamXml(baos, false, UserHandle.USER_ALL);
3446 
3447         // appears disabled
3448         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3449 
3450         // but was loaded and can be toggled back on
3451         mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
3452         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
3453     }
3454 
3455     @Test
testDelegateXml_entirelyDisabledDelegate()3456     public void testDelegateXml_entirelyDisabledDelegate() throws Exception {
3457         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3458         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
3459         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
3460 
3461         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3462         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3463                 mPermissionHelper, mLogger,
3464                 mAppOpsManager, mStatsEventBuilderFactory, false);
3465         loadStreamXml(baos, false, UserHandle.USER_ALL);
3466 
3467         // appears disabled
3468         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3469 
3470         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
3471         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
3472 
3473         mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
3474         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
3475     }
3476 
3477     @Test
testBubblePreference_defaults()3478     public void testBubblePreference_defaults() throws Exception {
3479         assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
3480 
3481         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3482         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3483                 mPermissionHelper, mLogger,
3484                 mAppOpsManager, mStatsEventBuilderFactory, false);
3485         loadStreamXml(baos, false, UserHandle.USER_ALL);
3486 
3487         assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
3488         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
3489     }
3490 
3491     @Test
testBubblePreference_upgradeWithSAWPermission()3492     public void testBubblePreference_upgradeWithSAWPermission() throws Exception {
3493         when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
3494                 anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED);
3495 
3496         final String xml = "<ranking version=\"1\">\n"
3497                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n"
3498                 + "<channel id=\"someId\" name=\"hi\""
3499                 + " importance=\"3\"/>"
3500                 + "</package>"
3501                 + "</ranking>";
3502         TypedXmlPullParser parser = Xml.newFastPullParser();
3503         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
3504                 null);
3505         parser.nextTag();
3506         mHelper.readXml(parser, false, UserHandle.USER_ALL);
3507 
3508         assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
3509         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
3510     }
3511 
3512     @Test
testBubblePreference_upgradeWithSAWThenUserOverride()3513     public void testBubblePreference_upgradeWithSAWThenUserOverride() throws Exception {
3514         when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
3515                 anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED);
3516 
3517         final String xml = "<ranking version=\"1\">\n"
3518                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n"
3519                 + "<channel id=\"someId\" name=\"hi\""
3520                 + " importance=\"3\"/>"
3521                 + "</package>"
3522                 + "</ranking>";
3523         TypedXmlPullParser parser = Xml.newFastPullParser();
3524         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
3525                 null);
3526         parser.nextTag();
3527         mHelper.readXml(parser, false, UserHandle.USER_ALL);
3528 
3529         assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
3530         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
3531 
3532         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED);
3533         assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
3534         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
3535                 mHelper.getAppLockedFields(PKG_O, UID_O));
3536 
3537         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3538         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3539                 mPermissionHelper, mLogger,
3540                 mAppOpsManager, mStatsEventBuilderFactory, false);
3541         loadStreamXml(baos, false, UserHandle.USER_ALL);
3542 
3543         assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
3544         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
3545                 mHelper.getAppLockedFields(PKG_O, UID_O));
3546     }
3547 
3548     @Test
testBubblePrefence_noSAWCheckForUnknownUid()3549     public void testBubblePrefence_noSAWCheckForUnknownUid() throws Exception {
3550         final String xml = "<ranking version=\"1\">\n"
3551                 + "<package name=\"" + PKG_O + "\" uid=\"" + UNKNOWN_UID + "\">\n"
3552                 + "<channel id=\"someId\" name=\"hi\""
3553                 + " importance=\"3\"/>"
3554                 + "</package>"
3555                 + "</ranking>";
3556         TypedXmlPullParser parser = Xml.newFastPullParser();
3557         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
3558                 null);
3559         parser.nextTag();
3560         mHelper.readXml(parser, false, UserHandle.USER_ALL);
3561 
3562         assertEquals(DEFAULT_BUBBLE_PREFERENCE, mHelper.getBubblePreference(PKG_O, UID_O));
3563         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
3564         verify(mAppOpsManager, never()).noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
3565                 anyString(), eq(null), anyString());
3566     }
3567 
3568     @Test
testBubblePreference_xml()3569     public void testBubblePreference_xml() throws Exception {
3570         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
3571         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
3572         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
3573                 mHelper.getAppLockedFields(PKG_O, UID_O));
3574 
3575         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
3576         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
3577                 mPermissionHelper, mLogger,
3578                 mAppOpsManager, mStatsEventBuilderFactory, false);
3579         loadStreamXml(baos, false, UserHandle.USER_ALL);
3580 
3581         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
3582         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
3583                 mHelper.getAppLockedFields(PKG_O, UID_O));
3584     }
3585 
3586     @Test
testUpdateNotificationChannel_fixedPermission()3587     public void testUpdateNotificationChannel_fixedPermission() {
3588         List<UserInfo> users = ImmutableList.of(new UserInfo(UserHandle.USER_SYSTEM, "user0", 0));
3589         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
3590         PackageInfo pm = new PackageInfo();
3591         pm.packageName = PKG_O;
3592         pm.applicationInfo = new ApplicationInfo();
3593         pm.applicationInfo.uid = UID_O;
3594         List<PackageInfo> packages = ImmutableList.of(pm);
3595         when(mPm.getInstalledPackagesAsUser(any(), anyInt())).thenReturn(packages);
3596         mHelper.updateFixedImportance(users);
3597 
3598         assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
3599 
3600         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3601         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3602 
3603         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
3604         update.setAllowBubbles(false);
3605 
3606         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
3607 
3608         assertEquals(IMPORTANCE_HIGH,
3609                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3610         assertEquals(false,
3611                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
3612     }
3613 
3614     @Test
testUpdateNotificationChannel_defaultApp()3615     public void testUpdateNotificationChannel_defaultApp() {
3616         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3617         toAdd.add(new Pair(PKG_O, UID_O));
3618         mHelper.updateDefaultApps(0, null, toAdd);
3619         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3620         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3621 
3622         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
3623         update.setAllowBubbles(false);
3624 
3625         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
3626 
3627         assertEquals(IMPORTANCE_HIGH,
3628                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3629         assertEquals(false,
3630                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
3631     }
3632 
3633     @Test
testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt()3634     public void testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt() {
3635         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
3636 
3637         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_NONE);
3638         mHelper.createNotificationChannel(PKG_O, UID_O, a, false, false);
3639 
3640         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3641         update.setAllowBubbles(false);
3642 
3643         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
3644 
3645         assertEquals(IMPORTANCE_HIGH,
3646                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3647         assertEquals(false,
3648                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
3649     }
3650 
3651     @Test
testUpdateNotificationChannel_fixedPermission_butAppAllowsIt()3652     public void testUpdateNotificationChannel_fixedPermission_butAppAllowsIt() {
3653         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
3654 
3655         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3656         a.setBlockable(true);
3657         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3658 
3659         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
3660         update.setAllowBubbles(false);
3661 
3662         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
3663 
3664         assertEquals(IMPORTANCE_NONE,
3665                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3666         assertEquals(false,
3667                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
3668     }
3669 
3670     @Test
testUpdateNotificationChannel_notFixedPermission()3671     public void testUpdateNotificationChannel_notFixedPermission() {
3672         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false);
3673 
3674         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3675         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3676 
3677         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
3678         update.setAllowBubbles(false);
3679 
3680         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
3681 
3682         assertEquals(IMPORTANCE_NONE,
3683                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3684         assertEquals(false,
3685                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
3686     }
3687 
3688     @Test
testUpdateFixedImportance_multiUser()3689     public void testUpdateFixedImportance_multiUser() {
3690         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3691         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
3692         NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
3693         // different uids, same package
3694         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3695         mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
3696         mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true);
3697 
3698         UserInfo user = new UserInfo();
3699         user.id = 0;
3700         List<UserInfo> users = ImmutableList.of(user);
3701         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
3702         PackageInfo pm = new PackageInfo();
3703         pm.packageName = PKG_O;
3704         pm.applicationInfo = new ApplicationInfo();
3705         pm.applicationInfo.uid = UID_O;
3706         List<PackageInfo> packages = ImmutableList.of(pm);
3707         when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
3708         mHelper.updateFixedImportance(users);
3709 
3710         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3711                 .isImportanceLockedByCriticalDeviceFunction());
3712         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
3713                 .isImportanceLockedByCriticalDeviceFunction());
3714         assertFalse(mHelper.getNotificationChannel(
3715                         PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
3716                 .isImportanceLockedByCriticalDeviceFunction());
3717     }
3718 
3719     @Test
testUpdateFixedImportance_channelDoesNotExistYet()3720     public void testUpdateFixedImportance_channelDoesNotExistYet() {
3721         UserInfo user = new UserInfo();
3722         user.id = 0;
3723         List<UserInfo> users = ImmutableList.of(user);
3724         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
3725         PackageInfo pm = new PackageInfo();
3726         pm.packageName = PKG_O;
3727         pm.applicationInfo = new ApplicationInfo();
3728         pm.applicationInfo.uid = UID_O;
3729         List<PackageInfo> packages = ImmutableList.of(pm);
3730         when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
3731         mHelper.updateFixedImportance(users);
3732 
3733         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3734         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3735 
3736         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3737                 .isImportanceLockedByCriticalDeviceFunction());
3738     }
3739 
3740     @Test
testUpdateDefaultApps_add_multiUser()3741     public void testUpdateDefaultApps_add_multiUser() {
3742         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3743         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
3744         NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
3745         // different uids, same package
3746         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3747         mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
3748         mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true);
3749 
3750         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3751         toAdd.add(new Pair(PKG_O, UID_O));
3752         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3753 
3754         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3755                 .isImportanceLockedByCriticalDeviceFunction());
3756         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
3757                 .isImportanceLockedByCriticalDeviceFunction());
3758         assertFalse(mHelper.getNotificationChannel(
3759                 PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
3760                 .isImportanceLockedByCriticalDeviceFunction());
3761     }
3762 
3763     @Test
testUpdateDefaultApps_add_onlyGivenPkg()3764     public void testUpdateDefaultApps_add_onlyGivenPkg() {
3765         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3766         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
3767         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3768         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false);
3769 
3770         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3771         toAdd.add(new Pair(PKG_O, UID_O));
3772         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3773 
3774         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3775                 .isImportanceLockedByCriticalDeviceFunction());
3776         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
3777                 .isImportanceLockedByCriticalDeviceFunction());
3778     }
3779 
3780     @Test
testUpdateDefaultApps_remove()3781     public void testUpdateDefaultApps_remove() {
3782         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3783         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
3784         // different uids, same package
3785         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3786         mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
3787 
3788         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3789         toAdd.add(new Pair(PKG_O, UID_O));
3790         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3791 
3792         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3793                 .isImportanceLockedByCriticalDeviceFunction());
3794         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
3795                 .isImportanceLockedByCriticalDeviceFunction());
3796 
3797         ArraySet<String> toRemove = new ArraySet<>();
3798         toRemove.add(PKG_O);
3799         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, null);
3800 
3801         assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3802                 .isImportanceLockedByCriticalDeviceFunction());
3803         assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
3804                 .isImportanceLockedByCriticalDeviceFunction());
3805     }
3806 
3807     @Test
testUpdateDefaultApps_addAndRemove()3808     public void testUpdateDefaultApps_addAndRemove() {
3809         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3810         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
3811         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3812         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false);
3813 
3814         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3815         toAdd.add(new Pair(PKG_O, UID_O));
3816         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3817 
3818 
3819         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3820                 .isImportanceLockedByCriticalDeviceFunction());
3821         assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
3822                 .isImportanceLockedByCriticalDeviceFunction());
3823 
3824         // now the default is PKG_N_MR1
3825         ArraySet<String> toRemove = new ArraySet<>();
3826         toRemove.add(PKG_O);
3827         toAdd = new ArraySet<>();
3828         toAdd.add(new Pair(PKG_N_MR1, UID_N_MR1));
3829         mHelper.updateDefaultApps(USER.getIdentifier(), toRemove, toAdd);
3830 
3831         assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3832                 .isImportanceLockedByCriticalDeviceFunction());
3833         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
3834                 .isImportanceLockedByCriticalDeviceFunction());
3835     }
3836 
3837     @Test
testUpdateDefaultApps_appDoesNotExist_noCrash()3838     public void testUpdateDefaultApps_appDoesNotExist_noCrash() {
3839         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3840         toAdd.add(new Pair(PKG_O, UID_O));
3841         ArraySet<String> toRemove = new ArraySet<>();
3842         toRemove.add(PKG_N_MR1);
3843         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, toAdd);
3844     }
3845 
3846     @Test
testUpdateDefaultApps_channelDoesNotExistYet()3847     public void testUpdateDefaultApps_channelDoesNotExistYet() {
3848         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3849         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
3850         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3851 
3852         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3853         toAdd.add(new Pair(PKG_O, UID_O));
3854         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3855 
3856         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3857                 .isImportanceLockedByCriticalDeviceFunction());
3858 
3859         mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
3860         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
3861                 .isImportanceLockedByCriticalDeviceFunction());
3862     }
3863 
3864     @Test
testUpdateNotificationChannel_defaultAppLockedImportance()3865     public void testUpdateNotificationChannel_defaultAppLockedImportance() {
3866         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3867         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3868         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3869         toAdd.add(new Pair(PKG_O, UID_O));
3870         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3871 
3872         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
3873         update.setAllowBubbles(false);
3874 
3875         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
3876         assertEquals(IMPORTANCE_HIGH,
3877                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3878         assertEquals(false,
3879                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
3880 
3881         mHelper.updateNotificationChannel(PKG_O, UID_O, update, false);
3882         assertEquals(IMPORTANCE_HIGH,
3883                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3884 
3885         NotificationChannel updateImportanceLow = new NotificationChannel("a", "a",
3886                 IMPORTANCE_LOW);
3887         mHelper.updateNotificationChannel(PKG_O, UID_O, updateImportanceLow, true);
3888         assertEquals(IMPORTANCE_LOW,
3889                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
3890     }
3891 
3892     @Test
testDefaultApp_appHasNoSettingsYet()3893     public void testDefaultApp_appHasNoSettingsYet() {
3894         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3895         toAdd.add(new Pair(PKG_O, UID_O));
3896         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3897 
3898         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3899         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3900 
3901         assertTrue(a.isImportanceLockedByCriticalDeviceFunction());
3902     }
3903 
3904     @Test
testUpdateFixedImportance_thenDefaultAppsRemoves()3905     public void testUpdateFixedImportance_thenDefaultAppsRemoves() {
3906         UserInfo user = new UserInfo();
3907         user.id = 0;
3908         List<UserInfo> users = ImmutableList.of(user);
3909         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
3910         PackageInfo pm = new PackageInfo();
3911         pm.packageName = PKG_O;
3912         pm.applicationInfo = new ApplicationInfo();
3913         pm.applicationInfo.uid = UID_O;
3914         List<PackageInfo> packages = ImmutableList.of(pm);
3915         when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
3916         mHelper.updateFixedImportance(users);
3917 
3918         ArraySet<String> toRemove = new ArraySet<>();
3919         toRemove.add(PKG_O);
3920         mHelper.updateDefaultApps(0, toRemove, null);
3921 
3922         assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
3923 
3924         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3925         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3926 
3927         // Still locked by permission if not role
3928         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3929                 .isImportanceLockedByCriticalDeviceFunction());
3930     }
3931 
3932     @Test
testUpdateDefaultApps_thenNotFixedPermission()3933     public void testUpdateDefaultApps_thenNotFixedPermission() {
3934         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3935         toAdd.add(new Pair(PKG_O, UID_O));
3936         mHelper.updateDefaultApps(0, null, toAdd);
3937 
3938         UserInfo user = new UserInfo();
3939         user.id = 0;
3940         List<UserInfo> users = ImmutableList.of(user);
3941         when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false);
3942         PackageInfo pm = new PackageInfo();
3943         pm.packageName = PKG_O;
3944         pm.applicationInfo = new ApplicationInfo();
3945         pm.applicationInfo.uid = UID_O;
3946         List<PackageInfo> packages = ImmutableList.of(pm);
3947         when(mPm.getInstalledPackagesAsUser(any(), eq(0))).thenReturn(packages);
3948         mHelper.updateFixedImportance(users);
3949 
3950         assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O));
3951 
3952         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
3953         mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
3954 
3955         // Still locked by role if not permission
3956         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
3957                 .isImportanceLockedByCriticalDeviceFunction());
3958     }
3959 
3960     @Test
testChannelXml_backupDefaultApp()3961     public void testChannelXml_backupDefaultApp() throws Exception {
3962         NotificationChannel channel1 =
3963                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
3964 
3965         mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false);
3966 
3967         // clear data
3968         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, true,
3969                 USER_SYSTEM, channel1.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
3970         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_O}, new int[]{
3971                 UID_O});
3972 
3973         ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
3974         toAdd.add(new Pair(PKG_O, UID_O));
3975         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
3976 
3977         TypedXmlPullParser parser = Xml.newFastPullParser();
3978         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
3979                 null);
3980         parser.nextTag();
3981         mHelper.readXml(parser, true, USER_SYSTEM);
3982 
3983         assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, channel1.getId(), false)
3984                 .isImportanceLockedByCriticalDeviceFunction());
3985     }
3986 
3987     @Test
testSetBubblesAllowed_none()3988     public void testSetBubblesAllowed_none() {
3989         // Change it to non-default first
3990         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL);
3991         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL);
3992         verify(mHandler, times(1)).requestSort();
3993         reset(mHandler);
3994         // Now test
3995         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
3996         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
3997         verify(mHandler, times(1)).requestSort();
3998     }
3999 
4000     @Test
testSetBubblesAllowed_all()4001     public void testSetBubblesAllowed_all() {
4002         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL);
4003         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL);
4004         verify(mHandler, times(1)).requestSort();
4005     }
4006 
4007     @Test
testSetBubblesAllowed_selected()4008     public void testSetBubblesAllowed_selected() {
4009         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED);
4010         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_SELECTED);
4011         verify(mHandler, times(1)).requestSort();
4012     }
4013 
4014     @Test
testTooManyChannels()4015     public void testTooManyChannels() {
4016         for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) {
4017             NotificationChannel channel = new NotificationChannel(String.valueOf(i),
4018                     String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
4019             mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true);
4020         }
4021         try {
4022             NotificationChannel channel = new NotificationChannel(
4023                     String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT),
4024                     String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT),
4025                     NotificationManager.IMPORTANCE_HIGH);
4026             mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true);
4027             fail("Allowed to create too many notification channels");
4028         } catch (IllegalStateException e) {
4029             // great
4030         }
4031     }
4032 
4033     @Test
testTooManyChannels_xml()4034     public void testTooManyChannels_xml() throws Exception {
4035         String extraChannel = "EXTRA";
4036         String extraChannel1 = "EXTRA1";
4037 
4038         // create first... many... directly so we don't need a big xml blob in this test
4039         for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) {
4040             NotificationChannel channel = new NotificationChannel(String.valueOf(i),
4041                     String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
4042             mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true);
4043         }
4044 
4045         final String xml = "<ranking version=\"1\">\n"
4046                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4047                 + "<channel id=\"" + extraChannel + "\" name=\"hi\" importance=\"3\"/>"
4048                 + "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>"
4049                 + "</package>"
4050                 + "</ranking>";
4051         TypedXmlPullParser parser = Xml.newFastPullParser();
4052         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4053                 null);
4054         parser.nextTag();
4055         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4056 
4057         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true));
4058         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true));
4059     }
4060 
4061     @Test
testTooManyGroups()4062     public void testTooManyGroups() {
4063         for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
4064             NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
4065                     String.valueOf(i));
4066             mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
4067         }
4068         try {
4069             NotificationChannelGroup group = new NotificationChannelGroup(
4070                     String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT),
4071                     String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT));
4072             mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
4073             fail("Allowed to create too many notification channel groups");
4074         } catch (IllegalStateException e) {
4075             // great
4076         }
4077     }
4078 
4079     @Test
testTooManyGroups_xml()4080     public void testTooManyGroups_xml() throws Exception {
4081         String extraGroup = "EXTRA";
4082         String extraGroup1 = "EXTRA1";
4083 
4084         // create first... many... directly so we don't need a big xml blob in this test
4085         for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
4086             NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
4087                     String.valueOf(i));
4088             mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
4089         }
4090 
4091         final String xml = "<ranking version=\"1\">\n"
4092                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4093                 + "<channelGroup id=\"" + extraGroup + "\" name=\"hi\"/>"
4094                 + "<channelGroup id=\"" + extraGroup1 + "\" name=\"hi2\"/>"
4095                 + "</package>"
4096                 + "</ranking>";
4097         TypedXmlPullParser parser = Xml.newFastPullParser();
4098         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4099                 null);
4100         parser.nextTag();
4101         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4102 
4103         assertNull(mHelper.getNotificationChannelGroup(extraGroup, PKG_O, UID_O));
4104         assertNull(mHelper.getNotificationChannelGroup(extraGroup1, PKG_O, UID_O));
4105     }
4106 
4107     @Test
testRestoreMultiUser()4108     public void testRestoreMultiUser() throws Exception {
4109         String pkg = "restore_pkg";
4110         String channelId = "channelId";
4111         int user0Importance = 3;
4112         int user10Importance = 4;
4113         when(mPm.getPackageUidAsUser(eq(pkg), anyInt())).thenReturn(UserHandle.USER_NULL);
4114 
4115         // both users have the same package, but different notification settings
4116         final String xmlUser0 = "<ranking version=\"1\">\n"
4117                 + "<package name=\"" + pkg + "\" >\n"
4118                 + "<channel id=\"" + channelId + "\" name=\"hi\""
4119                 + " importance=\"" + user0Importance + "\"/>"
4120                 + "</package>"
4121                 + "</ranking>";
4122         final String xmlUser10 = "<ranking version=\"1\">\n"
4123                 + "<package name=\"" + pkg + "\" >\n"
4124                 + "<channel id=\"" + channelId + "\" name=\"hi\""
4125                 + " importance=\"" + user10Importance + "\"/>"
4126                 + "</package>"
4127                 + "</ranking>";
4128 
4129         // trigger a restore for both users
4130         TypedXmlPullParser parser = Xml.newFastPullParser();
4131         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
4132                 null);
4133         parser.nextTag();
4134         mHelper.readXml(parser, true, 0);
4135         parser = Xml.newFastPullParser();
4136         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
4137                 null);
4138         parser.nextTag();
4139         mHelper.readXml(parser, true, 10);
4140 
4141         // "install" package on both users
4142         String[] pkgList = new String[] {pkg};
4143         int[] uidList0 = new int[] {UserHandle.PER_USER_RANGE};
4144         int[] uidList10 = new int[] {UserHandle.PER_USER_RANGE + 1};
4145         when(mPm.getPackageUidAsUser(pkg, 0)).thenReturn(uidList0[0]);
4146         when(mPm.getPackageUidAsUser(pkg, 10)).thenReturn(uidList10[0]);
4147         ApplicationInfo info = new ApplicationInfo();
4148         info.targetSdkVersion = Build.VERSION_CODES.Q;
4149         when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(info);
4150 
4151         mHelper.onPackagesChanged(false, 0, pkgList, uidList0);
4152         mHelper.onPackagesChanged(false, 10, pkgList, uidList10);
4153 
4154         assertEquals(user0Importance,
4155                 mHelper.getNotificationChannel(pkg, uidList0[0], channelId, false).getImportance());
4156         assertEquals(user10Importance, mHelper.getNotificationChannel(
4157                 pkg, uidList10[0], channelId, false).getImportance());
4158     }
4159 
4160     @Test
testGetConversationNotificationChannel()4161     public void testGetConversationNotificationChannel() {
4162         String conversationId = "friend";
4163 
4164         NotificationChannel parent =
4165                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
4166         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4167 
4168         NotificationChannel friend = new NotificationChannel(String.format(
4169                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId),
4170                 "messages", IMPORTANCE_DEFAULT);
4171         friend.setConversationId(parent.getId(), conversationId);
4172         mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
4173 
4174         compareChannelsParentChild(parent, mHelper.getConversationNotificationChannel(
4175                 PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId);
4176     }
4177 
4178     @Test
testGetNotificationChannel_conversationProvidedByNotCustomizedYet()4179     public void testGetNotificationChannel_conversationProvidedByNotCustomizedYet() {
4180         String conversationId = "friend";
4181 
4182         NotificationChannel parent =
4183                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
4184         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4185 
4186         compareChannels(parent, mHelper.getConversationNotificationChannel(
4187                 PKG_O, UID_O, parent.getId(), conversationId, true, false));
4188     }
4189 
4190     @Test
testConversationNotificationChannelsRequireParents()4191     public void testConversationNotificationChannelsRequireParents() {
4192         String parentId = "does not exist";
4193         String conversationId = "friend";
4194 
4195         NotificationChannel friend = new NotificationChannel(String.format(
4196                 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId),
4197                 "messages", IMPORTANCE_DEFAULT);
4198         friend.setConversationId(parentId, conversationId);
4199 
4200         try {
4201             mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
4202             fail("allowed creation of conversation channel without a parent");
4203         } catch (IllegalArgumentException e) {
4204             // good
4205         }
4206     }
4207 
4208     @Test
testPlaceholderConversationId_shortcutRequired()4209     public void testPlaceholderConversationId_shortcutRequired() throws Exception {
4210         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4211                 mPermissionHelper, mLogger,
4212                 mAppOpsManager, mStatsEventBuilderFactory, false);
4213 
4214         final String xml = "<ranking version=\"1\">\n"
4215                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4216                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
4217                 + "</package>"
4218                 + "</ranking>";
4219         TypedXmlPullParser parser = Xml.newFastPullParser();
4220         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4221                 null);
4222         parser.nextTag();
4223         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4224 
4225         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
4226     }
4227 
4228     @Test
testNormalConversationId_shortcutRequired()4229     public void testNormalConversationId_shortcutRequired() throws Exception {
4230         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4231                 mPermissionHelper, mLogger,
4232                 mAppOpsManager, mStatsEventBuilderFactory, false);
4233 
4234         final String xml = "<ranking version=\"1\">\n"
4235                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4236                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"other\"/>"
4237                 + "</package>"
4238                 + "</ranking>";
4239         TypedXmlPullParser parser = Xml.newFastPullParser();
4240         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4241                 null);
4242         parser.nextTag();
4243         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4244 
4245         assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
4246     }
4247 
4248     @Test
testNoConversationId_shortcutRequired()4249     public void testNoConversationId_shortcutRequired() throws Exception {
4250         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4251                 mPermissionHelper, mLogger,
4252                 mAppOpsManager, mStatsEventBuilderFactory, false);
4253 
4254         final String xml = "<ranking version=\"1\">\n"
4255                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4256                 + "<channel id=\"id\" name=\"hi\" importance=\"3\"/>"
4257                 + "</package>"
4258                 + "</ranking>";
4259         TypedXmlPullParser parser = Xml.newFastPullParser();
4260         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4261                 null);
4262         parser.nextTag();
4263         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4264 
4265         assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
4266     }
4267 
4268     @Test
testDeleted_noTime()4269     public void testDeleted_noTime() throws Exception {
4270         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4271                 mPermissionHelper, mLogger,
4272                 mAppOpsManager, mStatsEventBuilderFactory, false);
4273 
4274         final String xml = "<ranking version=\"1\">\n"
4275                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4276                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\"/>"
4277                 + "</package>"
4278                 + "</ranking>";
4279         TypedXmlPullParser parser = Xml.newFastPullParser();
4280         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4281                 null);
4282         parser.nextTag();
4283         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4284 
4285         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
4286     }
4287 
4288     @Test
testDeleted_twice()4289     public void testDeleted_twice() throws Exception {
4290         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4291                 mPermissionHelper, mLogger,
4292                 mAppOpsManager, mStatsEventBuilderFactory, false);
4293 
4294         mHelper.createNotificationChannel(
4295                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
4296         assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
4297         assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
4298     }
4299 
4300     @Test
testDeleted_recentTime()4301     public void testDeleted_recentTime() throws Exception {
4302         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4303                 mPermissionHelper, mLogger,
4304                 mAppOpsManager, mStatsEventBuilderFactory, false);
4305 
4306         mHelper.createNotificationChannel(
4307                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
4308         mHelper.deleteNotificationChannel(PKG_P, UID_P, "id");
4309         NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
4310         assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
4311         assertTrue(nc1.isDeleted());
4312 
4313         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_P, UID_P, false,
4314                 USER_SYSTEM, "id", NotificationChannel.DEFAULT_CHANNEL_ID);
4315 
4316         TypedXmlPullParser parser = Xml.newFastPullParser();
4317         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
4318                 null);
4319         parser.nextTag();
4320         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4321                 mPermissionHelper, mLogger,
4322                 mAppOpsManager, mStatsEventBuilderFactory, false);
4323         mHelper.readXml(parser, true, USER_SYSTEM);
4324 
4325         NotificationChannel nc = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
4326         assertTrue(DateUtils.isToday(nc.getDeletedTimeMs()));
4327         assertTrue(nc.isDeleted());
4328     }
4329 
4330     @Test
testUnDelete_time()4331     public void testUnDelete_time() throws Exception {
4332         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4333                 mPermissionHelper, mLogger,
4334                 mAppOpsManager, mStatsEventBuilderFactory, false);
4335 
4336         mHelper.createNotificationChannel(
4337                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
4338         mHelper.deleteNotificationChannel(PKG_P, UID_P, "id");
4339         NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
4340         assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
4341         assertTrue(nc1.isDeleted());
4342 
4343         mHelper.createNotificationChannel(
4344                 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
4345         nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
4346         assertEquals(-1, nc1.getDeletedTimeMs());
4347         assertFalse(nc1.isDeleted());
4348     }
4349 
4350     @Test
testDeleted_longTime()4351     public void testDeleted_longTime() throws Exception {
4352         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
4353                 mPermissionHelper, mLogger,
4354                 mAppOpsManager, mStatsEventBuilderFactory, false);
4355 
4356         long time = System.currentTimeMillis() - (DateUtils.DAY_IN_MILLIS * 30);
4357 
4358         final String xml = "<ranking version=\"1\">\n"
4359                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
4360                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\" del_time=\""
4361                 + time + "\"/>"
4362                 + "</package>"
4363                 + "</ranking>";
4364         TypedXmlPullParser parser = Xml.newFastPullParser();
4365         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
4366                 null);
4367         parser.nextTag();
4368         mHelper.readXml(parser, false, UserHandle.USER_ALL);
4369 
4370         NotificationChannel nc = mHelper.getNotificationChannel(PKG_O, UID_O, "id", true);
4371         assertNull(nc);
4372     }
4373 
4374     @Test
testGetConversations_all()4375     public void testGetConversations_all() {
4376         String convoId = "convo";
4377         NotificationChannel messages =
4378                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4379         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4380         NotificationChannel calls =
4381                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
4382         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
4383         NotificationChannel p =
4384                 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
4385         mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false);
4386 
4387         NotificationChannel channel =
4388                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
4389         channel.setConversationId(messages.getId(), convoId);
4390         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4391 
4392         NotificationChannel diffConvo =
4393                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
4394         diffConvo.setConversationId(p.getId(), "different convo");
4395         mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false);
4396 
4397         NotificationChannel channel2 =
4398                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
4399         channel2.setConversationId(calls.getId(), convoId);
4400         channel2.setImportantConversation(true);
4401         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false);
4402 
4403         List<ConversationChannelWrapper> convos =
4404                 mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
4405 
4406         assertEquals(3, convos.size());
4407         assertTrue(conversationWrapperContainsChannel(convos, channel));
4408         assertTrue(conversationWrapperContainsChannel(convos, diffConvo));
4409         assertTrue(conversationWrapperContainsChannel(convos, channel2));
4410     }
4411 
4412     @Test
testGetConversations_multiUser()4413     public void testGetConversations_multiUser() {
4414         String convoId = "convo";
4415         NotificationChannel messages =
4416                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4417         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4418 
4419         NotificationChannel messagesUser10 =
4420                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4421         mHelper.createNotificationChannel(
4422                 PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false);
4423 
4424         NotificationChannel messagesFromB =
4425                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
4426         messagesFromB.setConversationId(messages.getId(), "different convo");
4427         mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false);
4428 
4429         NotificationChannel messagesFromBUser10 =
4430                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
4431         messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo");
4432         mHelper.createNotificationChannel(
4433                 PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false);
4434 
4435 
4436         List<ConversationChannelWrapper> convos =
4437                 mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
4438 
4439         assertEquals(1, convos.size());
4440         assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
4441 
4442         convos =
4443                 mHelper.getConversations(IntArray.wrap(new int[] {0, UserHandle.getUserId(UID_O + UserHandle.PER_USER_RANGE)}), false);
4444 
4445         assertEquals(2, convos.size());
4446         assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
4447         assertTrue(conversationWrapperContainsChannel(convos, messagesFromBUser10));
4448     }
4449 
4450     @Test
testGetConversations_notDemoted()4451     public void testGetConversations_notDemoted() {
4452         String convoId = "convo";
4453         NotificationChannel messages =
4454                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4455         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4456         NotificationChannel calls =
4457                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
4458         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
4459         NotificationChannel p =
4460                 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
4461         mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false);
4462 
4463         NotificationChannel channel =
4464                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
4465         channel.setConversationId(messages.getId(), convoId);
4466         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4467 
4468         NotificationChannel diffConvo =
4469                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
4470         diffConvo.setConversationId(p.getId(), "different convo");
4471         diffConvo.setDemoted(true);
4472         mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false);
4473 
4474         NotificationChannel channel2 =
4475                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
4476         channel2.setConversationId(calls.getId(), convoId);
4477         channel2.setImportantConversation(true);
4478         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false);
4479 
4480         List<ConversationChannelWrapper> convos =
4481                 mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
4482 
4483         assertEquals(2, convos.size());
4484         assertTrue(conversationWrapperContainsChannel(convos, channel));
4485         assertFalse(conversationWrapperContainsChannel(convos, diffConvo));
4486         assertTrue(conversationWrapperContainsChannel(convos, channel2));
4487     }
4488 
4489     @Test
testGetConversations_onlyImportant()4490     public void testGetConversations_onlyImportant() {
4491         String convoId = "convo";
4492         NotificationChannel messages =
4493                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4494         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4495         NotificationChannel calls =
4496                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
4497         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
4498         NotificationChannel p =
4499                 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT);
4500         mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false);
4501 
4502         NotificationChannel channel =
4503                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
4504         channel.setConversationId(messages.getId(), convoId);
4505         channel.setImportantConversation(true);
4506         mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false);
4507 
4508         NotificationChannel diffConvo =
4509                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
4510         diffConvo.setConversationId(p.getId(), "different convo");
4511         diffConvo.setImportantConversation(true);
4512         mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, false, false);
4513 
4514         NotificationChannel channel2 =
4515                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
4516         channel2.setConversationId(calls.getId(), convoId);
4517         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
4518 
4519         List<ConversationChannelWrapper> convos =
4520                 mHelper.getConversations(IntArray.wrap(new int[] {0}), true);
4521 
4522         assertEquals(2, convos.size());
4523         assertTrue(conversationWrapperContainsChannel(convos, channel));
4524         assertTrue(conversationWrapperContainsChannel(convos, diffConvo));
4525         assertFalse(conversationWrapperContainsChannel(convos, channel2));
4526     }
4527 
4528     @Test
testGetConversations_parentDeleted()4529     public void testGetConversations_parentDeleted() {
4530         String convoId = "convo";
4531         NotificationChannel messages =
4532                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4533         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4534 
4535         NotificationChannel channel =
4536                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
4537         channel.setConversationId(messages.getId(), convoId);
4538         channel.setImportantConversation(true);
4539         mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false);
4540 
4541         mHelper.permanentlyDeleteNotificationChannel(PKG_O, UID_O, "messages");
4542 
4543         List<ConversationChannelWrapper> convos =
4544                 mHelper.getConversations(IntArray.wrap(new int[] {0}), true);
4545 
4546         assertEquals(1, convos.size());
4547         assertTrue(conversationWrapperContainsChannel(convos, channel));
4548     }
4549 
conversationWrapperContainsChannel(List<ConversationChannelWrapper> list, NotificationChannel expected)4550     private boolean conversationWrapperContainsChannel(List<ConversationChannelWrapper> list,
4551             NotificationChannel expected) {
4552         for (ConversationChannelWrapper ccw : list) {
4553             if (ccw.getNotificationChannel().equals(expected)) {
4554                 return true;
4555             }
4556         }
4557 
4558         return false;
4559     }
4560 
4561     @Test
testGetConversations_invalidPkg()4562     public void testGetConversations_invalidPkg() {
4563         assertThat(mHelper.getConversations("bad", 1)).isEmpty();
4564     }
4565 
4566     @Test
testGetConversations_noConversations()4567     public void testGetConversations_noConversations() {
4568         NotificationChannel channel =
4569                 new NotificationChannel("not_convo", "not_convo", IMPORTANCE_DEFAULT);
4570         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4571 
4572         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
4573     }
4574 
4575     @Test
testGetConversations_noDisabledGroups()4576     public void testGetConversations_noDisabledGroups() {
4577         NotificationChannelGroup group = new NotificationChannelGroup("a", "a");
4578         group.setBlocked(true);
4579         mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false);
4580         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
4581         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4582 
4583         NotificationChannel channel =
4584                 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
4585         channel.setConversationId("parent", "convo");
4586         channel.setGroup(group.getId());
4587         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4588 
4589         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
4590     }
4591 
4592     @Test
testGetConversations_noDeleted()4593     public void testGetConversations_noDeleted() {
4594         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
4595         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4596         NotificationChannel channel =
4597                 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
4598         channel.setConversationId("parent", "convo");
4599         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4600         mHelper.deleteNotificationChannel(PKG_O, UID_O, channel.getId());
4601 
4602         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
4603     }
4604 
4605     @Test
testGetConversations_noDemoted()4606     public void testGetConversations_noDemoted() {
4607         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
4608         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4609         NotificationChannel channel =
4610                 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
4611         channel.setConversationId("parent", "convo");
4612         channel.setDemoted(true);
4613         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4614 
4615         assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
4616     }
4617 
4618     @Test
testGetConversations()4619     public void testGetConversations() {
4620         NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name");
4621         mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
4622 
4623         NotificationChannel messages =
4624                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4625         messages.setGroup(group.getId());
4626         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4627         NotificationChannel calls =
4628                 new NotificationChannel("calls", "Calls", IMPORTANCE_HIGH);
4629         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
4630 
4631         NotificationChannel channel =
4632                 new NotificationChannel("A person", "A lovely person", IMPORTANCE_DEFAULT);
4633         channel.setGroup(group.getId());
4634         channel.setConversationId(messages.getId(), channel.getName().toString());
4635         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4636 
4637         NotificationChannel channel2 =
4638                 new NotificationChannel("B person", "B fabulous person", IMPORTANCE_DEFAULT);
4639         channel2.setConversationId(calls.getId(), channel2.getName().toString());
4640         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
4641 
4642         Map<String, NotificationChannel> expected = new HashMap<>();
4643         expected.put(channel.getId(), channel);
4644         expected.put(channel2.getId(), channel2);
4645 
4646         Map<String, CharSequence> expectedGroup = new HashMap<>();
4647         expectedGroup.put(channel.getId(), group.getName());
4648         expectedGroup.put(channel2.getId(), null);
4649 
4650         Map<String, CharSequence> expectedParentLabel= new HashMap<>();
4651         expectedParentLabel.put(channel.getId(), messages.getName());
4652         expectedParentLabel.put(channel2.getId(), calls.getName());
4653 
4654         ArrayList<ConversationChannelWrapper> convos = mHelper.getConversations(PKG_O, UID_O);
4655         assertThat(convos).hasSize(2);
4656 
4657         for (ConversationChannelWrapper convo : convos) {
4658             assertThat(convo.getNotificationChannel())
4659                     .isEqualTo(expected.get(convo.getNotificationChannel().getId()));
4660             assertThat(convo.getParentChannelLabel())
4661                     .isEqualTo(expectedParentLabel.get(convo.getNotificationChannel().getId()));
4662             assertThat(convo.getGroupLabel())
4663                     .isEqualTo(expectedGroup.get(convo.getNotificationChannel().getId()));
4664         }
4665     }
4666 
4667     @Test
testDeleteConversations()4668     public void testDeleteConversations() {
4669         String convoId = "convo";
4670         String convoIdC = "convoC";
4671         NotificationChannel messages =
4672                 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
4673         mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
4674         NotificationChannel calls =
4675                 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT);
4676         mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
4677 
4678         NotificationChannel channel =
4679                 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
4680         channel.setConversationId(messages.getId(), convoId);
4681         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4682 
4683         NotificationChannel noMatch =
4684                 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
4685         noMatch.setConversationId(messages.getId(), "different convo");
4686         mHelper.createNotificationChannel(PKG_O, UID_O, noMatch, true, false);
4687 
4688         NotificationChannel channel2 =
4689                 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
4690         channel2.setConversationId(calls.getId(), convoId);
4691         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
4692 
4693         NotificationChannel channel3 =
4694                 new NotificationChannel("C person msgs", "msgs from C", IMPORTANCE_DEFAULT);
4695         channel3.setConversationId(messages.getId(), convoIdC);
4696         mHelper.createNotificationChannel(PKG_O, UID_O, channel3, true, false);
4697 
4698         assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false));
4699         assertEquals(channel2,
4700                 mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false));
4701         List<String> deleted = mHelper.deleteConversations(PKG_O, UID_O, Set.of(convoId, convoIdC));
4702         assertEquals(3, deleted.size());
4703 
4704         assertEquals(messages,
4705                 mHelper.getNotificationChannel(PKG_O, UID_O, messages.getId(), false));
4706         assertEquals(noMatch,
4707                 mHelper.getNotificationChannel(PKG_O, UID_O, noMatch.getId(), false));
4708 
4709         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false));
4710         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false));
4711         assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), true));
4712         assertEquals(channel2,
4713                 mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), true));
4714 
4715         assertEquals(9, mLogger.getCalls().size());
4716         assertEquals(
4717                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
4718                 mLogger.get(0).event);  // Channel messages
4719         assertEquals(
4720                 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
4721                 mLogger.get(1).event);  // Channel calls
4722         assertEquals(
4723                 NotificationChannelLogger.NotificationChannelEvent
4724                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
4725                 mLogger.get(2).event);  // Channel channel - Conversation A person msgs
4726         assertEquals(
4727                 NotificationChannelLogger.NotificationChannelEvent
4728                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
4729                 mLogger.get(3).event);  // Channel noMatch - Conversation B person msgs
4730         assertEquals(
4731                 NotificationChannelLogger.NotificationChannelEvent
4732                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
4733                 mLogger.get(4).event);  // Channel channel2 - Conversation A person calls
4734         assertEquals(
4735                 NotificationChannelLogger.NotificationChannelEvent
4736                         .NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
4737                 mLogger.get(5).event);  // Channel channel3 - Conversation C person msgs
4738         assertEquals(
4739                 NotificationChannelLogger.NotificationChannelEvent
4740                         .NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
4741                 mLogger.get(6).event);  // Delete Channel channel - Conversation A person msgs
4742         assertEquals(
4743                 NotificationChannelLogger.NotificationChannelEvent
4744                         .NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
4745                 mLogger.get(7).event);  // Delete Channel channel2 - Conversation A person calls
4746         assertEquals(
4747                 NotificationChannelLogger.NotificationChannelEvent
4748                         .NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
4749                 mLogger.get(8).event);  // Delete Channel channel3 - Conversation C person msgs
4750     }
4751 
4752     @Test
testInvalidMessageSent()4753     public void testInvalidMessageSent() {
4754         // create package preferences
4755         mHelper.canShowBadge(PKG_P, UID_P);
4756 
4757         // check default value
4758         assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P));
4759 
4760         // change it
4761         mHelper.setInvalidMessageSent(PKG_P, UID_P);
4762         assertTrue(mHelper.isInInvalidMsgState(PKG_P, UID_P));
4763         assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P));
4764     }
4765 
4766     @Test
testValidMessageSent()4767     public void testValidMessageSent() {
4768         // create package preferences
4769         mHelper.canShowBadge(PKG_P, UID_P);
4770 
4771         // get into the bad state
4772         mHelper.setInvalidMessageSent(PKG_P, UID_P);
4773 
4774         // and then fix it
4775         mHelper.setValidMessageSent(PKG_P, UID_P);
4776 
4777         assertTrue(mHelper.hasSentValidMsg(PKG_P, UID_P));
4778         assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P));
4779     }
4780 
4781     @Test
testUserDemotedInvalidMsgApp()4782     public void testUserDemotedInvalidMsgApp() {
4783         // create package preferences
4784         mHelper.canShowBadge(PKG_P, UID_P);
4785 
4786         // demotion means nothing before msg notif sent
4787         mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
4788         assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
4789 
4790         // it's valid when incomplete msgs have been sent
4791         mHelper.setInvalidMessageSent(PKG_P, UID_P);
4792         assertTrue(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
4793 
4794         // and is invalid once complete msgs are sent
4795         mHelper.setValidMessageSent(PKG_P, UID_P);
4796         assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
4797     }
4798 
4799     @Test
testValidBubbleSent()4800     public void testValidBubbleSent() {
4801         // create package preferences
4802         mHelper.canShowBadge(PKG_P, UID_P);
4803         // false by default
4804         assertFalse(mHelper.hasSentValidBubble(PKG_P, UID_P));
4805 
4806         // set something valid was sent
4807         mHelper.setValidBubbleSent(PKG_P, UID_P);
4808         assertTrue(mHelper.hasSentValidBubble(PKG_P, UID_P));
4809     }
4810 
4811     @Test
testPullPackageChannelPreferencesStats()4812     public void testPullPackageChannelPreferencesStats() {
4813         String channelId = "parent";
4814         String name = "messages";
4815         NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
4816         mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false);
4817         NotificationChannel channel =
4818                 new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT);
4819         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
4820         NotificationChannel fodderB = new NotificationChannel("b", "b", IMPORTANCE_HIGH);
4821         mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false);
4822 
4823         ArrayList<StatsEvent> events = new ArrayList<>();
4824         mHelper.pullPackageChannelPreferencesStats(events);
4825 
4826         int found = 0;
4827         for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
4828             if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
4829                     && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
4830                 ++found;
4831                 assertEquals("uid", UID_O, builder.getValue(UID_FIELD_NUMBER));
4832                 assertTrue("uid annotation", builder.getBooleanAnnotation(
4833                         UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID));
4834                 assertEquals("importance", IMPORTANCE_DEFAULT, builder.getValue(
4835                         IMPORTANCE_FIELD_NUMBER));
4836                 assertEquals("name", name, builder.getValue(CHANNEL_NAME_FIELD_NUMBER));
4837                 assertFalse("isconv", builder.getBoolean(IS_CONVERSATION_FIELD_NUMBER));
4838                 assertFalse("deleted", builder.getBoolean(IS_DELETED_FIELD_NUMBER));
4839             }
4840         }
4841     }
4842 
4843     @Test
testPullPackageChannelPreferencesStats_one_to_one()4844     public void testPullPackageChannelPreferencesStats_one_to_one() {
4845         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
4846         mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false);
4847         NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW);
4848         mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false);
4849         NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH);
4850         mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false);
4851 
4852         List<String> channels = new LinkedList<>(Arrays.asList("a", "b", "c"));
4853 
4854         ArrayList<StatsEvent> events = new ArrayList<>();
4855         mHelper.pullPackageChannelPreferencesStats(events);
4856 
4857         int found = 0;
4858         for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
4859             if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES) {
4860                 Object id = builder.getValue(CHANNEL_ID_FIELD_NUMBER);
4861                 assertTrue("missing channel in the output", channels.contains(id));
4862                 channels.remove(id);
4863             }
4864         }
4865         assertTrue("unexpected channel in output", channels.isEmpty());
4866     }
4867 
4868     @Test
testPullPackageChannelPreferencesStats_conversation()4869     public void testPullPackageChannelPreferencesStats_conversation() {
4870         String conversationId = "friend";
4871 
4872         NotificationChannel parent =
4873                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
4874         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4875 
4876         String channelId = String.format(
4877                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId);
4878         String name = "conversation";
4879         NotificationChannel friend = new NotificationChannel(channelId,
4880                 name, IMPORTANCE_DEFAULT);
4881         friend.setConversationId(parent.getId(), conversationId);
4882         mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
4883 
4884         ArrayList<StatsEvent> events = new ArrayList<>();
4885         mHelper.pullPackageChannelPreferencesStats(events);
4886 
4887         for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
4888             if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
4889                     && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
4890                 assertTrue("isConveration should be true", builder.getBoolean(
4891                         IS_CONVERSATION_FIELD_NUMBER));
4892                 assertFalse("not demoted", builder.getBoolean(
4893                         IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
4894                 assertFalse("not important", builder.getBoolean(
4895                         IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
4896             }
4897         }
4898     }
4899 
4900     @Test
testPullPackageChannelPreferencesStats_conversation_demoted()4901     public void testPullPackageChannelPreferencesStats_conversation_demoted() {
4902         NotificationChannel parent =
4903                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
4904         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4905         String channelId = String.format(
4906                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend");
4907         NotificationChannel friend = new NotificationChannel(channelId,
4908                 "conversation", IMPORTANCE_DEFAULT);
4909         friend.setConversationId(parent.getId(), "friend");
4910         friend.setDemoted(true);
4911         mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
4912 
4913         ArrayList<StatsEvent> events = new ArrayList<>();
4914         mHelper.pullPackageChannelPreferencesStats(events);
4915 
4916         for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
4917             if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
4918                     && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
4919                 assertTrue("isConveration should be true", builder.getBoolean(
4920                         IS_CONVERSATION_FIELD_NUMBER));
4921                 assertTrue("is demoted", builder.getBoolean(
4922                         IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
4923                 assertFalse("not important", builder.getBoolean(
4924                         IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
4925             }
4926         }
4927     }
4928 
4929     @Test
testPullPackageChannelPreferencesStats_conversation_priority()4930     public void testPullPackageChannelPreferencesStats_conversation_priority() {
4931         NotificationChannel parent =
4932                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
4933         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
4934         String channelId = String.format(
4935                 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend");
4936         NotificationChannel friend = new NotificationChannel(channelId,
4937                 "conversation", IMPORTANCE_DEFAULT);
4938         friend.setConversationId(parent.getId(), "friend");
4939         friend.setImportantConversation(true);
4940         mHelper.createNotificationChannel(PKG_O, UID_O, friend, false, false);
4941 
4942         ArrayList<StatsEvent> events = new ArrayList<>();
4943         mHelper.pullPackageChannelPreferencesStats(events);
4944 
4945         for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
4946             if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
4947                     && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
4948                 assertTrue("isConveration should be true", builder.getBoolean(
4949                         IS_CONVERSATION_FIELD_NUMBER));
4950                 assertFalse("not demoted", builder.getBoolean(
4951                         IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
4952                 assertTrue("is important", builder.getBoolean(
4953                         IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
4954             }
4955         }
4956     }
4957 
4958     @Test
testPullPackagePreferencesStats_postPermissionMigration()4959     public void testPullPackagePreferencesStats_postPermissionMigration() {
4960 
4961         // build a collection of app permissions that should be passed in but ignored
4962         ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
4963         appPermissions.put(new Pair(1, "first"), new Pair(true, false));    // not in local prefs
4964         appPermissions.put(new Pair(3, "third"), new Pair(false, true));   // not in local prefs
4965         appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, true)); // in local prefs
4966 
4967         // local preferences
4968         mHelper.canShowBadge(PKG_O, UID_O);
4969         mHelper.canShowBadge(PKG_P, UID_P);
4970 
4971         // expected output. format: uid -> importance, as only uid (and not package name)
4972         // is in PackageNotificationPreferences
4973         ArrayMap<Integer, Pair<Integer, Boolean>> expected = new ArrayMap<>();
4974         expected.put(1, new Pair(IMPORTANCE_DEFAULT, false));
4975         expected.put(3, new Pair(IMPORTANCE_NONE, true));
4976         expected.put(UID_O, new Pair(IMPORTANCE_NONE, true));     // banned by permissions
4977         expected.put(UID_P, new Pair(IMPORTANCE_NONE, false));    // defaults to none, false
4978 
4979         ArrayList<StatsEvent> events = new ArrayList<>();
4980         mHelper.pullPackagePreferencesStats(events, appPermissions);
4981 
4982         for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
4983             if (builder.getAtomId() == PACKAGE_NOTIFICATION_PREFERENCES) {
4984                 int uid = builder.getInt(PackageNotificationPreferences.UID_FIELD_NUMBER);
4985                 boolean userSet = builder.getBoolean(
4986                         PackageNotificationPreferences.USER_SET_IMPORTANCE_FIELD_NUMBER);
4987 
4988                 // if it's one of the expected ids, then make sure the importance matches
4989                 assertTrue(expected.containsKey(uid));
4990                 assertThat(expected.get(uid).first).isEqualTo(
4991                         builder.getInt(PackageNotificationPreferences.IMPORTANCE_FIELD_NUMBER));
4992                 assertThat(expected.get(uid).second).isEqualTo(userSet);
4993             }
4994         }
4995     }
4996 
4997     @Test
testUnlockNotificationChannelImportance()4998     public void testUnlockNotificationChannelImportance() {
4999         NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
5000         mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
5001         channel.lockFields(USER_LOCKED_IMPORTANCE);
5002         assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
5003 
5004         mHelper.unlockNotificationChannelImportance(PKG_O, UID_O, channel.getId());
5005         assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
5006 
5007     }
5008 
5009     @Test
testUnlockAllNotificationChannels()5010     public void testUnlockAllNotificationChannels() {
5011         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
5012         mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false);
5013         NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
5014         mHelper.createNotificationChannel(PKG_P, UID_P, channelB, true, false);
5015         NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH);
5016         mHelper.createNotificationChannel(PKG_P, UID_O, channelC, false, false);
5017 
5018         channelA.lockFields(USER_LOCKED_IMPORTANCE);
5019         channelB.lockFields(USER_LOCKED_IMPORTANCE);
5020         channelC.lockFields(USER_LOCKED_IMPORTANCE);
5021 
5022         assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
5023         assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
5024         assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
5025 
5026         mHelper.unlockAllNotificationChannels();
5027         assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
5028         assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
5029         assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
5030     }
5031 }
5032