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