RankingHelperTest.java revision e0b25746267972b370a1c773ad18d146ee8163c3
1/*
2 * Copyright (C) 2014 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 */
16package com.android.server.notification;
17
18import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
19import static android.app.NotificationManager.IMPORTANCE_HIGH;
20import static android.app.NotificationManager.IMPORTANCE_LOW;
21import static android.app.NotificationManager.IMPORTANCE_NONE;
22import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
23
24import static junit.framework.Assert.assertNull;
25import static junit.framework.Assert.fail;
26
27import org.json.JSONArray;
28import org.json.JSONObject;
29import org.junit.Before;
30import org.junit.Test;
31import org.junit.runner.RunWith;
32
33import com.android.internal.util.FastXmlSerializer;
34
35import org.mockito.Mock;
36import org.mockito.MockitoAnnotations;
37import org.xmlpull.v1.XmlPullParser;
38import org.xmlpull.v1.XmlSerializer;
39
40import android.app.Notification;
41import android.app.NotificationChannelGroup;
42import android.content.Context;
43import android.app.NotificationChannel;
44import android.app.NotificationManager;
45import android.content.pm.ApplicationInfo;
46import android.content.pm.PackageManager;
47import android.graphics.Color;
48import android.media.AudioAttributes;
49import android.net.Uri;
50import android.os.Build;
51import android.os.UserHandle;
52import android.service.notification.NotificationListenerService;
53import android.service.notification.StatusBarNotification;
54import android.support.test.InstrumentationRegistry;
55import android.support.test.runner.AndroidJUnit4;
56import android.test.suitebuilder.annotation.SmallTest;
57import android.util.ArrayMap;
58import android.util.Slog;
59import android.util.Xml;
60
61import java.io.BufferedInputStream;
62import java.io.BufferedOutputStream;
63import java.io.ByteArrayInputStream;
64import java.io.ByteArrayOutputStream;
65import java.util.ArrayList;
66import java.util.Arrays;
67import java.util.HashMap;
68import java.util.List;
69import java.util.Map;
70import java.util.Objects;
71import java.util.concurrent.ThreadLocalRandom;
72
73import static org.junit.Assert.assertEquals;
74import static org.junit.Assert.assertFalse;
75import static org.junit.Assert.assertNotNull;
76import static org.junit.Assert.assertTrue;
77import static org.mockito.Matchers.anyInt;
78import static org.mockito.Matchers.anyString;
79import static org.mockito.Matchers.eq;
80import static org.mockito.Mockito.when;
81
82@SmallTest
83@RunWith(AndroidJUnit4.class)
84public class RankingHelperTest {
85    private static final String PKG = "com.android.server.notification";
86    private static final int UID = 0;
87    private static final String UPDATED_PKG = "updatedPkg";
88    private static final int UID2 = 1111111;
89    private static final String TEST_CHANNEL_ID = "test_channel_id";
90
91    @Mock NotificationUsageStats mUsageStats;
92    @Mock RankingHandler mHandler;
93    @Mock PackageManager mPm;
94    @Mock Context mContext;
95
96    private Notification mNotiGroupGSortA;
97    private Notification mNotiGroupGSortB;
98    private Notification mNotiNoGroup;
99    private Notification mNotiNoGroup2;
100    private Notification mNotiNoGroupSortA;
101    private NotificationRecord mRecordGroupGSortA;
102    private NotificationRecord mRecordGroupGSortB;
103    private NotificationRecord mRecordNoGroup;
104    private NotificationRecord mRecordNoGroup2;
105    private NotificationRecord mRecordNoGroupSortA;
106    private RankingHelper mHelper;
107    private AudioAttributes mAudioAttributes;
108
109    private Context getContext() {
110        return InstrumentationRegistry.getTargetContext();
111    }
112
113    @Before
114    public void setUp() throws Exception {
115        MockitoAnnotations.initMocks(this);
116        UserHandle user = UserHandle.ALL;
117
118        final ApplicationInfo legacy = new ApplicationInfo();
119        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
120        final ApplicationInfo upgrade = new ApplicationInfo();
121        upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
122        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
123        when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
124        when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
125        when(mContext.getResources()).thenReturn(
126                InstrumentationRegistry.getContext().getResources());
127        when(mContext.getPackageManager()).thenReturn(mPm);
128        when(mContext.getApplicationInfo()).thenReturn(legacy);
129
130        mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
131                new String[] {ImportanceExtractor.class.getName()});
132
133        mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
134                .setContentTitle("A")
135                .setGroup("G")
136                .setSortKey("A")
137                .setWhen(1205)
138                .build();
139        mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification(
140                PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user,
141                null, System.currentTimeMillis()), getDefaultChannel());
142
143        mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID)
144                .setContentTitle("B")
145                .setGroup("G")
146                .setSortKey("B")
147                .setWhen(1200)
148                .build();
149        mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification(
150                PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user,
151                null, System.currentTimeMillis()), getDefaultChannel());
152
153        mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID)
154                .setContentTitle("C")
155                .setWhen(1201)
156                .build();
157        mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification(
158                PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user,
159                null, System.currentTimeMillis()), getDefaultChannel());
160
161        mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
162                .setContentTitle("D")
163                .setWhen(1202)
164                .build();
165        mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification(
166                PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user,
167                null, System.currentTimeMillis()), getDefaultChannel());
168
169        mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
170                .setContentTitle("E")
171                .setWhen(1201)
172                .setSortKey("A")
173                .build();
174        mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification(
175                PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user,
176                null, System.currentTimeMillis()), getDefaultChannel());
177
178        mAudioAttributes = new AudioAttributes.Builder()
179                .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
180                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
181                .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
182                .build();
183    }
184
185    private NotificationChannel getDefaultChannel() {
186        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
187                IMPORTANCE_LOW);
188    }
189
190    private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup,
191            String... channelIds)
192            throws Exception {
193        XmlSerializer serializer = new FastXmlSerializer();
194        ByteArrayOutputStream baos = new ByteArrayOutputStream();
195        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
196        serializer.startDocument(null, true);
197        serializer.startTag(null, "ranking");
198        mHelper.writeXml(serializer, forBackup);
199        serializer.endTag(null, "ranking");
200        serializer.endDocument();
201        serializer.flush();
202
203        for (String channelId : channelIds) {
204            mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
205        }
206        return baos;
207    }
208
209    private void loadStreamXml(ByteArrayOutputStream stream) throws Exception {
210        XmlPullParser parser = Xml.newPullParser();
211        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(stream.toByteArray())),
212                null);
213        parser.nextTag();
214        mHelper.readXml(parser, false);
215    }
216
217    private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
218        assertEquals(expected.getId(), actual.getId());
219        assertEquals(expected.getName(), actual.getName());
220        assertEquals(expected.getDescription(), actual.getDescription());
221        assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
222        assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
223        assertEquals(expected.getImportance(), actual.getImportance());
224        assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
225        assertEquals(expected.getSound(), actual.getSound());
226        assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
227        assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
228        assertEquals(expected.getGroup(), actual.getGroup());
229        assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes());
230        assertEquals(expected.getLightColor(), actual.getLightColor());
231    }
232
233    private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
234        assertEquals(expected.getId(), actual.getId());
235        assertEquals(expected.getName(), actual.getName());
236    }
237
238    private NotificationChannel getChannel() {
239        return new NotificationChannel("id", "name", IMPORTANCE_LOW);
240    }
241
242    @Test
243    public void testFindAfterRankingWithASplitGroup() throws Exception {
244        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
245        notificationList.add(mRecordGroupGSortA);
246        notificationList.add(mRecordGroupGSortB);
247        notificationList.add(mRecordNoGroup);
248        notificationList.add(mRecordNoGroupSortA);
249        mHelper.sort(notificationList);
250        assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0);
251        assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0);
252        assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0);
253        assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0);
254    }
255
256    @Test
257    public void testSortShouldNotThrowWithPlainNotifications() throws Exception {
258        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
259        notificationList.add(mRecordNoGroup);
260        notificationList.add(mRecordNoGroup2);
261        mHelper.sort(notificationList);
262    }
263
264    @Test
265    public void testSortShouldNotThrowOneSorted() throws Exception {
266        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
267        notificationList.add(mRecordNoGroup);
268        notificationList.add(mRecordNoGroupSortA);
269        mHelper.sort(notificationList);
270    }
271
272    @Test
273    public void testSortShouldNotThrowOneNotification() throws Exception {
274        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
275        notificationList.add(mRecordNoGroup);
276        mHelper.sort(notificationList);
277    }
278
279    @Test
280    public void testSortShouldNotThrowOneSortKey() throws Exception {
281        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
282        notificationList.add(mRecordGroupGSortB);
283        mHelper.sort(notificationList);
284    }
285
286    @Test
287    public void testSortShouldNotThrowOnEmptyList() throws Exception {
288        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
289        mHelper.sort(notificationList);
290    }
291
292    @Test
293    public void testChannelXml() throws Exception {
294        NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
295        NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
296        NotificationChannel channel1 =
297                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
298        NotificationChannel channel2 =
299                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
300        channel2.setDescription("descriptions for all");
301        channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
302        channel2.enableLights(true);
303        channel2.setBypassDnd(true);
304        channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
305        channel2.enableVibration(true);
306        channel2.setGroup(ncg.getId());
307        channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
308        channel2.setLightColor(Color.BLUE);
309
310        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
311        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
312        mHelper.createNotificationChannel(PKG, UID, channel1, true);
313        mHelper.createNotificationChannel(PKG, UID, channel2, false);
314
315        mHelper.setShowBadge(PKG, UID, true);
316
317        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
318                channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
319        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
320
321        loadStreamXml(baos);
322
323        assertTrue(mHelper.canShowBadge(PKG, UID));
324        assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
325        compareChannels(channel2,
326                mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
327
328        List<NotificationChannelGroup> actualGroups =
329                mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
330        boolean foundNcg = false;
331        for (NotificationChannelGroup actual : actualGroups) {
332            if (ncg.getId().equals(actual.getId())) {
333                foundNcg = true;
334                compareGroups(ncg, actual);
335            } else if (ncg2.getId().equals(actual.getId())) {
336                compareGroups(ncg2, actual);
337            }
338        }
339        assertTrue(foundNcg);
340
341        boolean foundChannel2Group = false;
342        for (NotificationChannelGroup actual : actualGroups) {
343            if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
344                foundChannel2Group = true;
345                break;
346            }
347        }
348        assertTrue(foundChannel2Group);
349    }
350
351    @Test
352    public void testChannelXml_backup() throws Exception {
353        NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
354        NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
355        NotificationChannel channel1 =
356                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
357        NotificationChannel channel2 =
358                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
359        NotificationChannel channel3 =
360                new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
361        channel3.setGroup(ncg.getId());
362
363        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
364        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
365        mHelper.createNotificationChannel(PKG, UID, channel1, true);
366        mHelper.createNotificationChannel(PKG, UID, channel2, false);
367        mHelper.createNotificationChannel(PKG, UID, channel3, true);
368
369        mHelper.deleteNotificationChannel(PKG, UID, channel1.getId());
370        mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId());
371        assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
372
373        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
374                channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
375        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
376
377        XmlPullParser parser = Xml.newPullParser();
378        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
379                null);
380        parser.nextTag();
381        mHelper.readXml(parser, true);
382
383        assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
384        assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
385        assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
386        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
387        assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
388    }
389
390    @Test
391    public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
392        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
393                NotificationChannel.DEFAULT_CHANNEL_ID);
394
395        loadStreamXml(baos);
396
397        final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID,
398                NotificationChannel.DEFAULT_CHANNEL_ID, false);
399        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
400        assertFalse(updated.canBypassDnd());
401        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
402        assertEquals(0, updated.getUserLockedFields());
403    }
404
405    @Test
406    public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
407        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
408                NotificationChannel.DEFAULT_CHANNEL_ID, false);
409        defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
410        mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
411
412        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
413                NotificationChannel.DEFAULT_CHANNEL_ID);
414
415        loadStreamXml(baos);
416
417        assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
418                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
419    }
420
421    @Test
422    public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
423        final String preupgradeXml = "<ranking version=\"1\">\n"
424                + "<package name=\"" + PKG
425                + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
426                + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
427                + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID + "\" />\n"
428                + "<package name=\"" + UPDATED_PKG + "\" uid=\"" + UID2 + "\" visibility=\""
429                + Notification.VISIBILITY_PRIVATE + "\" />\n"
430                + "</ranking>";
431        XmlPullParser parser = Xml.newPullParser();
432        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
433                null);
434        parser.nextTag();
435        mHelper.readXml(parser, false);
436
437        final NotificationChannel updated1 =
438            mHelper.getNotificationChannel(PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
439        assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
440        assertTrue(updated1.canBypassDnd());
441        assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
442        assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
443                | NotificationChannel.USER_LOCKED_PRIORITY
444                | NotificationChannel.USER_LOCKED_VISIBILITY,
445                updated1.getUserLockedFields());
446
447        // No Default Channel created for updated packages
448        assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
449                NotificationChannel.DEFAULT_CHANNEL_ID, false));
450    }
451
452    @Test
453    public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception {
454        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
455                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
456        assertTrue(defaultChannel != null);
457        ByteArrayOutputStream baos =
458                writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID);
459        // Load package at higher sdk.
460        final ApplicationInfo upgraded = new ApplicationInfo();
461        upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
462        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
463        loadStreamXml(baos);
464
465        // Default Channel should be gone.
466        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
467                NotificationChannel.DEFAULT_CHANNEL_ID, false));
468    }
469
470    @Test
471    public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception {
472        mHelper.createNotificationChannel(PKG, UID,
473                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
474        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
475                NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
476
477        // Load package at higher sdk.
478        final ApplicationInfo upgraded = new ApplicationInfo();
479        upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
480        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
481        loadStreamXml(baos);
482
483        // Default Channel should be gone.
484        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
485                NotificationChannel.DEFAULT_CHANNEL_ID, false));
486    }
487
488    @Test
489    public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
490        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
491                NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
492        mHelper.createNotificationChannel(PKG, UID,
493                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
494
495        loadStreamXml(baos);
496
497        // Should still have the newly created channel that wasn't in the xml.
498        assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null);
499    }
500
501    @Test
502    public void testCreateChannel_blocked() throws Exception {
503        mHelper.setImportance(PKG, UID, IMPORTANCE_NONE);
504
505        mHelper.createNotificationChannel(PKG, UID,
506                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
507    }
508
509    @Test
510    public void testCreateChannel_ImportanceNone() throws Exception {
511        try {
512            mHelper.createNotificationChannel(PKG, UID,
513                    new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true);
514            fail("Was allowed to create a blocked channel");
515        } catch (IllegalArgumentException e) {
516            // yay
517        }
518    }
519
520
521    @Test
522    public void testUpdate() throws Exception {
523        // no fields locked by user
524        final NotificationChannel channel =
525                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
526        channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
527        channel.enableLights(true);
528        channel.setBypassDnd(true);
529        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
530
531        mHelper.createNotificationChannel(PKG, UID, channel, false);
532
533        // same id, try to update all fields
534        final NotificationChannel channel2 =
535                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
536        channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
537        channel2.enableLights(false);
538        channel2.setBypassDnd(false);
539        channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
540
541        mHelper.updateNotificationChannel(PKG, UID, channel2);
542
543        // all fields should be changed
544        assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false));
545    }
546
547    @Test
548    public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
549        mHelper.setImportance(PKG, UID, IMPORTANCE_UNSPECIFIED);
550        assertTrue(mHelper.canShowBadge(PKG, UID));
551        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
552        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
553                mHelper.getPackageVisibility(PKG, UID));
554
555        NotificationChannel defaultChannel = mHelper.getNotificationChannel(
556                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
557
558        defaultChannel.setShowBadge(false);
559        defaultChannel.setImportance(IMPORTANCE_NONE);
560        defaultChannel.setBypassDnd(true);
561        defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
562
563        mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
564
565        // ensure app level fields are changed
566        assertFalse(mHelper.canShowBadge(PKG, UID));
567        assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG, UID));
568        assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG, UID));
569        assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG, UID));
570    }
571
572    @Test
573    public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception {
574        final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
575
576        mHelper.createNotificationChannel(PKG, UID, channel, false);
577        assertTrue(mHelper.canShowBadge(PKG, UID));
578        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
579        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
580                mHelper.getPackageVisibility(PKG, UID));
581
582        channel.setShowBadge(false);
583        channel.setImportance(IMPORTANCE_NONE);
584        channel.setBypassDnd(true);
585        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
586
587        mHelper.updateNotificationChannel(PKG, UID, channel);
588
589        // ensure app level fields are not changed
590        assertTrue(mHelper.canShowBadge(PKG, UID));
591        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
592        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
593                mHelper.getPackageVisibility(PKG, UID));
594        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
595    }
596
597    @Test
598    public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception {
599        assertEquals(null, mHelper.getNotificationChannel(PKG, UID, "garbage", false));
600    }
601
602    @Test
603    public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
604        final NotificationChannel channel =
605                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
606        channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
607        channel.enableLights(true);
608        channel.setBypassDnd(true);
609        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
610        channel.setShowBadge(true);
611        int lockMask = 0;
612        for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
613            lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
614        }
615        channel.lockFields(lockMask);
616
617        mHelper.createNotificationChannel(PKG, UID, channel, true);
618
619        NotificationChannel savedChannel =
620                mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
621
622        assertEquals(channel.getName(), savedChannel.getName());
623        assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
624        assertFalse(savedChannel.canBypassDnd());
625        assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
626        assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
627    }
628
629    @Test
630    public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
631        final NotificationChannel channel =
632                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
633        channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
634        channel.enableLights(true);
635        channel.setBypassDnd(true);
636        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
637        channel.setShowBadge(true);
638        int lockMask = 0;
639        for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
640            lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
641        }
642        channel.lockFields(lockMask);
643
644        mHelper.createNotificationChannel(PKG, UID, channel, true);
645
646        NotificationChannel savedChannel =
647                mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
648
649        assertEquals(channel.getName(), savedChannel.getName());
650        assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
651        assertFalse(savedChannel.canBypassDnd());
652        assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
653        assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
654    }
655
656    @Test
657    public void testClearLockedFields() throws Exception {
658        final NotificationChannel channel = getChannel();
659        mHelper.clearLockedFields(channel);
660        assertEquals(0, channel.getUserLockedFields());
661
662        channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
663                | NotificationChannel.USER_LOCKED_IMPORTANCE);
664        mHelper.clearLockedFields(channel);
665        assertEquals(0, channel.getUserLockedFields());
666    }
667
668    @Test
669    public void testLockFields_soundAndVibration() throws Exception {
670        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
671
672        final NotificationChannel update1 = getChannel();
673        update1.setSound(new Uri.Builder().scheme("test").build(),
674                new AudioAttributes.Builder().build());
675        update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
676        mHelper.updateNotificationChannel(PKG, UID, update1);
677        assertEquals(NotificationChannel.USER_LOCKED_SOUND,
678                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
679                        .getUserLockedFields());
680
681        NotificationChannel update2 = getChannel();
682        update2.enableVibration(true);
683        mHelper.updateNotificationChannel(PKG, UID, update2);
684        assertEquals(NotificationChannel.USER_LOCKED_SOUND
685                        | NotificationChannel.USER_LOCKED_VIBRATION,
686                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
687                        .getUserLockedFields());
688    }
689
690    @Test
691    public void testLockFields_vibrationAndLights() throws Exception {
692        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
693
694        final NotificationChannel update1 = getChannel();
695        update1.setVibrationPattern(new long[]{7945, 46 ,246});
696        mHelper.updateNotificationChannel(PKG, UID, update1);
697        assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
698                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
699                        .getUserLockedFields());
700
701        final NotificationChannel update2 = getChannel();
702        update2.enableLights(true);
703        mHelper.updateNotificationChannel(PKG, UID, update2);
704        assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
705                        | NotificationChannel.USER_LOCKED_LIGHTS,
706                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
707                        .getUserLockedFields());
708    }
709
710    @Test
711    public void testLockFields_lightsAndImportance() throws Exception {
712        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
713
714        final NotificationChannel update1 = getChannel();
715        update1.setLightColor(Color.GREEN);
716        mHelper.updateNotificationChannel(PKG, UID, update1);
717        assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
718                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
719                        .getUserLockedFields());
720
721        final NotificationChannel update2 = getChannel();
722        update2.setImportance(IMPORTANCE_DEFAULT);
723        mHelper.updateNotificationChannel(PKG, UID, update2);
724        assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
725                        | NotificationChannel.USER_LOCKED_IMPORTANCE,
726                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
727                        .getUserLockedFields());
728    }
729
730    @Test
731    public void testLockFields_visibilityAndDndAndBadge() throws Exception {
732        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
733        assertEquals(0,
734                mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
735                        .getUserLockedFields());
736
737        final NotificationChannel update1 = getChannel();
738        update1.setBypassDnd(true);
739        mHelper.updateNotificationChannel(PKG, UID, update1);
740        assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
741                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
742                        .getUserLockedFields());
743
744        final NotificationChannel update2 = getChannel();
745        update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
746        mHelper.updateNotificationChannel(PKG, UID, update2);
747        assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
748                        | NotificationChannel.USER_LOCKED_VISIBILITY,
749                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
750                        .getUserLockedFields());
751
752        final NotificationChannel update3 = getChannel();
753        update3.setShowBadge(false);
754        mHelper.updateNotificationChannel(PKG, UID, update3);
755        assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
756                        | NotificationChannel.USER_LOCKED_VISIBILITY
757                        | NotificationChannel.USER_LOCKED_SHOW_BADGE,
758                mHelper.getNotificationChannel(PKG, UID, update3.getId(), false)
759                        .getUserLockedFields());
760    }
761
762    @Test
763    public void testDeleteNonExistentChannel() throws Exception {
764        mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
765    }
766
767    @Test
768    public void testGetDeletedChannel() throws Exception {
769        NotificationChannel channel = getChannel();
770        channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
771        channel.enableLights(true);
772        channel.setBypassDnd(true);
773        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
774        channel.enableVibration(true);
775        channel.setVibrationPattern(new long[]{100, 67, 145, 156});
776
777        mHelper.createNotificationChannel(PKG, UID, channel, true);
778        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
779
780        // Does not return deleted channel
781        NotificationChannel response =
782                mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
783        assertNull(response);
784
785        // Returns deleted channel
786        response = mHelper.getNotificationChannel(PKG, UID, channel.getId(), true);
787        compareChannels(channel, response);
788        assertTrue(response.isDeleted());
789    }
790
791    @Test
792    public void testGetDeletedChannels() throws Exception {
793        Map<String, NotificationChannel> channelMap = new HashMap<>();
794        NotificationChannel channel =
795                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
796        channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
797        channel.enableLights(true);
798        channel.setBypassDnd(true);
799        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
800        channel.enableVibration(true);
801        channel.setVibrationPattern(new long[]{100, 67, 145, 156});
802        channelMap.put(channel.getId(), channel);
803        NotificationChannel channel2 =
804                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
805        channelMap.put(channel2.getId(), channel2);
806        mHelper.createNotificationChannel(PKG, UID, channel, true);
807        mHelper.createNotificationChannel(PKG, UID, channel2, true);
808
809        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
810
811        // Returns only non-deleted channels
812        List<NotificationChannel> channels =
813                mHelper.getNotificationChannels(PKG, UID, false).getList();
814        assertEquals(2, channels.size());   // Default channel + non-deleted channel
815        for (NotificationChannel nc : channels) {
816            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
817                compareChannels(channel2, nc);
818            }
819        }
820
821        // Returns deleted channels too
822        channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
823        assertEquals(3, channels.size());               // Includes default channel
824        for (NotificationChannel nc : channels) {
825            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
826                compareChannels(channelMap.get(nc.getId()), nc);
827            }
828        }
829    }
830
831    @Test
832    public void testGetDeletedChannelCount() throws Exception {
833        NotificationChannel channel =
834                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
835        NotificationChannel channel2 =
836                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
837        NotificationChannel channel3 =
838                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
839        mHelper.createNotificationChannel(PKG, UID, channel, true);
840        mHelper.createNotificationChannel(PKG, UID, channel2, true);
841        mHelper.createNotificationChannel(PKG, UID, channel3, true);
842
843        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
844        mHelper.deleteNotificationChannel(PKG, UID, channel3.getId());
845
846        assertEquals(2, mHelper.getDeletedChannelCount(PKG, UID));
847        assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID2));
848    }
849
850    @Test
851    public void testCreateDeletedChannel() throws Exception {
852        long[] vibration = new long[]{100, 67, 145, 156};
853        NotificationChannel channel =
854                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
855        channel.setVibrationPattern(vibration);
856
857        mHelper.createNotificationChannel(PKG, UID, channel, true);
858        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
859
860        NotificationChannel newChannel = new NotificationChannel(
861                channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
862        newChannel.setVibrationPattern(new long[]{100});
863
864        mHelper.createNotificationChannel(PKG, UID, newChannel, true);
865
866        // No long deleted, using old settings
867        compareChannels(channel,
868                mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false));
869    }
870
871    @Test
872    public void testCreateChannel_defaultChannelId() throws Exception {
873        try {
874            mHelper.createNotificationChannel(PKG, UID, new NotificationChannel(
875                    NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true);
876            fail("Allowed to create default channel");
877        } catch (IllegalArgumentException e) {
878            // pass
879        }
880    }
881
882    @Test
883    public void testCreateChannel_alreadyExists() throws Exception {
884        long[] vibration = new long[]{100, 67, 145, 156};
885        NotificationChannel channel =
886                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
887        channel.setVibrationPattern(vibration);
888
889        mHelper.createNotificationChannel(PKG, UID, channel, true);
890
891        NotificationChannel newChannel = new NotificationChannel(
892                channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
893        newChannel.setVibrationPattern(new long[]{100});
894
895        mHelper.createNotificationChannel(PKG, UID, newChannel, true);
896
897        // Old settings not overridden
898        compareChannels(channel,
899                mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false));
900    }
901
902    @Test
903    public void testCreateChannel_noOverrideSound() throws Exception {
904        Uri sound = new Uri.Builder().scheme("test").build();
905        final NotificationChannel channel = new NotificationChannel("id2", "name2",
906                 NotificationManager.IMPORTANCE_DEFAULT);
907        channel.setSound(sound, mAudioAttributes);
908        mHelper.createNotificationChannel(PKG, UID, channel, true);
909        assertEquals(sound, mHelper.getNotificationChannel(
910                PKG, UID, channel.getId(), false).getSound());
911    }
912
913    @Test
914    public void testPermanentlyDeleteChannels() throws Exception {
915        NotificationChannel channel1 =
916                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
917        NotificationChannel channel2 =
918                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
919
920        mHelper.createNotificationChannel(PKG, UID, channel1, true);
921        mHelper.createNotificationChannel(PKG, UID, channel2, false);
922
923        mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
924
925        // Only default channel remains
926        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
927    }
928
929    @Test
930    public void testDeleteGroup() throws Exception {
931        NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
932        NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted");
933        NotificationChannel nonGroupedNonDeletedChannel =
934                new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH);
935        NotificationChannel groupedButNotDeleted =
936                new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
937        groupedButNotDeleted.setGroup("not");
938        NotificationChannel groupedAndDeleted =
939                new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
940        groupedAndDeleted.setGroup("totally");
941
942        mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true);
943        mHelper.createNotificationChannelGroup(PKG, UID, deleted, true);
944        mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true);
945        mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true);
946        mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true);
947
948        mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId());
949
950        assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG, UID));
951        assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG, UID));
952
953        assertNull(mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), false));
954        compareChannels(groupedAndDeleted,
955                mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), true));
956
957        compareChannels(groupedButNotDeleted,
958                mHelper.getNotificationChannel(PKG, UID, groupedButNotDeleted.getId(), false));
959        compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
960                PKG, UID, nonGroupedNonDeletedChannel.getId(), false));
961
962        // notDeleted
963        assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID).size());
964    }
965
966    @Test
967    public void testOnUserRemoved() throws Exception {
968        int[] user0Uids = {98, 235, 16, 3782};
969        int[] user1Uids = new int[user0Uids.length];
970        for (int i = 0; i < user0Uids.length; i++) {
971            user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i];
972
973            final ApplicationInfo legacy = new ApplicationInfo();
974            legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
975            when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
976
977            // create records with the default channel for all user 0 and user 1 uids
978            mHelper.getImportance(PKG, user0Uids[i]);
979            mHelper.getImportance(PKG, user1Uids[i]);
980        }
981
982        mHelper.onUserRemoved(1);
983
984        // user 0 records remain
985        for (int i = 0; i < user0Uids.length; i++) {
986            assertEquals(1,
987                    mHelper.getNotificationChannels(PKG, user0Uids[i], false).getList().size());
988        }
989        // user 1 records are gone
990        for (int i = 0; i < user1Uids.length; i++) {
991            assertEquals(0,
992                    mHelper.getNotificationChannels(PKG, user1Uids[i], false).getList().size());
993        }
994    }
995
996    @Test
997    public void testOnPackageChanged_packageRemoval() throws Exception {
998        // Deleted
999        NotificationChannel channel1 =
1000                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1001        mHelper.createNotificationChannel(PKG, UID, channel1, true);
1002
1003        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1004
1005        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
1006
1007        // Not deleted
1008        mHelper.createNotificationChannel(PKG, UID, channel1, true);
1009
1010        mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1011        assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
1012    }
1013
1014    @Test
1015    public void testOnPackageChanged_packageRemoval_importance() throws Exception {
1016        mHelper.setImportance(PKG, UID, NotificationManager.IMPORTANCE_HIGH);
1017
1018        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1019
1020        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
1021    }
1022
1023    @Test
1024    public void testOnPackageChanged_packageRemoval_groups() throws Exception {
1025        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1026        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1027        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
1028        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
1029
1030        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1031
1032        assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
1033    }
1034
1035    @Test
1036    public void testRecordDefaults() throws Exception {
1037        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
1038        assertEquals(true, mHelper.canShowBadge(PKG, UID));
1039        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
1040    }
1041
1042    @Test
1043    public void testCreateGroup() throws Exception {
1044        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1045        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1046        assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG, UID).iterator().next());
1047    }
1048
1049    @Test
1050    public void testCannotCreateChannel_badGroup() throws Exception {
1051        NotificationChannel channel1 =
1052                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1053        channel1.setGroup("garbage");
1054        try {
1055            mHelper.createNotificationChannel(PKG, UID, channel1, true);
1056            fail("Created a channel with a bad group");
1057        } catch (IllegalArgumentException e) {
1058        }
1059    }
1060
1061    @Test
1062    public void testCannotCreateChannel_goodGroup() throws Exception {
1063        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1064        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1065        NotificationChannel channel1 =
1066                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1067        channel1.setGroup(ncg.getId());
1068        mHelper.createNotificationChannel(PKG, UID, channel1, true);
1069
1070        assertEquals(ncg.getId(),
1071                mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup());
1072    }
1073
1074    @Test
1075    public void testGetChannelGroups() throws Exception {
1076        NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
1077        mHelper.createNotificationChannelGroup(PKG, UID, unused, true);
1078        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1079        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1080        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
1081        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
1082
1083        NotificationChannel channel1 =
1084                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1085        channel1.setGroup(ncg.getId());
1086        mHelper.createNotificationChannel(PKG, UID, channel1, true);
1087        NotificationChannel channel1a =
1088                new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
1089        channel1a.setGroup(ncg.getId());
1090        mHelper.createNotificationChannel(PKG, UID, channel1a, true);
1091
1092        NotificationChannel channel2 =
1093                new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
1094        channel2.setGroup(ncg2.getId());
1095        mHelper.createNotificationChannel(PKG, UID, channel2, true);
1096
1097        NotificationChannel channel3 =
1098                new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
1099        mHelper.createNotificationChannel(PKG, UID, channel3, true);
1100
1101        List<NotificationChannelGroup> actual =
1102                mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
1103        assertEquals(3, actual.size());
1104        for (NotificationChannelGroup group : actual) {
1105            if (group.getId() == null) {
1106                assertEquals(2, group.getChannels().size()); // misc channel too
1107                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
1108                        || channel3.getId().equals(group.getChannels().get(1).getId()));
1109            } else if (group.getId().equals(ncg.getId())) {
1110                assertEquals(2, group.getChannels().size());
1111                if (group.getChannels().get(0).getId().equals(channel1.getId())) {
1112                    assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId()));
1113                } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) {
1114                    assertTrue(group.getChannels().get(1).getId().equals(channel1.getId()));
1115                } else {
1116                    fail("expected channel not found");
1117                }
1118            } else if (group.getId().equals(ncg2.getId())) {
1119                assertEquals(1, group.getChannels().size());
1120                assertEquals(channel2.getId(), group.getChannels().get(0).getId());
1121            }
1122        }
1123    }
1124
1125    @Test
1126    public void testGetChannelGroups_noSideEffects() throws Exception {
1127        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1128        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1129
1130        NotificationChannel channel1 =
1131                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1132        channel1.setGroup(ncg.getId());
1133        mHelper.createNotificationChannel(PKG, UID, channel1, true);
1134        mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
1135
1136        channel1.setImportance(IMPORTANCE_LOW);
1137        mHelper.updateNotificationChannel(PKG, UID, channel1);
1138
1139        List<NotificationChannelGroup> actual =
1140                mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
1141
1142        assertEquals(2, actual.size());
1143        for (NotificationChannelGroup group : actual) {
1144            if (Objects.equals(group.getId(), ncg.getId())) {
1145                assertEquals(1, group.getChannels().size());
1146            }
1147        }
1148    }
1149
1150    @Test
1151    public void testCreateChannel_updateName() throws Exception {
1152        NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
1153        mHelper.createNotificationChannel(PKG, UID, nc, true);
1154        NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
1155        assertEquals("hello", actual.getName());
1156
1157        nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
1158        mHelper.createNotificationChannel(PKG, UID, nc, true);
1159
1160        actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
1161        assertEquals("goodbye", actual.getName());
1162        assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
1163    }
1164
1165    @Test
1166    public void testDumpChannelsJson() throws Exception {
1167        final ApplicationInfo upgrade = new ApplicationInfo();
1168        upgrade.targetSdkVersion = Build.VERSION_CODES.O;
1169        try {
1170            when(mPm.getApplicationInfoAsUser(
1171                    anyString(), anyInt(), anyInt())).thenReturn(upgrade);
1172        } catch (PackageManager.NameNotFoundException e) {
1173        }
1174        ArrayMap<String, Integer> expectedChannels = new ArrayMap<>();
1175        int numPackages = ThreadLocalRandom.current().nextInt(1, 5);
1176        for (int i = 0; i < numPackages; i++) {
1177            String pkgName = "pkg" + i;
1178            int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
1179            for (int j = 0; j < numChannels; j++) {
1180                mHelper.createNotificationChannel(pkgName, UID,
1181                        new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true);
1182            }
1183            expectedChannels.put(pkgName, numChannels);
1184        }
1185
1186        // delete the first channel of the first package
1187        String pkg = expectedChannels.keyAt(0);
1188        mHelper.deleteNotificationChannel("pkg" + 0, UID, "0");
1189        // dump should not include deleted channels
1190        int count = expectedChannels.get(pkg);
1191        expectedChannels.put(pkg, count - 1);
1192
1193        JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter());
1194        assertEquals(numPackages, actual.length());
1195        for (int i = 0; i < numPackages; i++) {
1196            JSONObject object = actual.getJSONObject(i);
1197            assertTrue(expectedChannels.containsKey(object.get("packageName")));
1198            assertEquals(expectedChannels.get(object.get("packageName")).intValue(),
1199                    object.getInt("channelCount"));
1200        }
1201    }
1202}
1203