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