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