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