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