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