RankingHelperTest.java revision 59e152e92e6ebb71bab974973ce29b4f8d11f7cf
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 junit.framework.Assert.assertNull;
19import static junit.framework.Assert.fail;
20
21import org.junit.Before;
22import org.junit.Test;
23import org.junit.runner.RunWith;
24
25import com.android.internal.util.FastXmlSerializer;
26
27import org.mockito.Mock;
28import org.mockito.MockitoAnnotations;
29import org.xmlpull.v1.XmlPullParser;
30import org.xmlpull.v1.XmlSerializer;
31
32import android.app.Notification;
33import android.app.NotificationChannelGroup;
34import android.content.Context;
35import android.app.NotificationChannel;
36import android.app.NotificationManager;
37import android.content.pm.ApplicationInfo;
38import android.content.pm.PackageManager;
39import android.net.Uri;
40import android.os.Build;
41import android.os.UserHandle;
42import android.service.notification.StatusBarNotification;
43import android.support.test.InstrumentationRegistry;
44import android.support.test.runner.AndroidJUnit4;
45import android.test.suitebuilder.annotation.SmallTest;
46import android.util.Xml;
47
48import java.io.BufferedInputStream;
49import java.io.BufferedOutputStream;
50import java.io.ByteArrayInputStream;
51import java.io.ByteArrayOutputStream;
52import java.util.ArrayList;
53import java.util.Arrays;
54import java.util.HashMap;
55import java.util.List;
56import java.util.Map;
57
58import static org.junit.Assert.assertEquals;
59import static org.junit.Assert.assertFalse;
60import static org.junit.Assert.assertNotNull;
61import static org.junit.Assert.assertTrue;
62import static org.mockito.Matchers.anyInt;
63import static org.mockito.Matchers.eq;
64import static org.mockito.Mockito.when;
65
66@SmallTest
67@RunWith(AndroidJUnit4.class)
68public class RankingHelperTest {
69    @Mock NotificationUsageStats mUsageStats;
70    @Mock RankingHandler handler;
71    @Mock PackageManager mPm;
72
73    private Notification mNotiGroupGSortA;
74    private Notification mNotiGroupGSortB;
75    private Notification mNotiNoGroup;
76    private Notification mNotiNoGroup2;
77    private Notification mNotiNoGroupSortA;
78    private NotificationRecord mRecordGroupGSortA;
79    private NotificationRecord mRecordGroupGSortB;
80    private NotificationRecord mRecordNoGroup;
81    private NotificationRecord mRecordNoGroup2;
82    private NotificationRecord mRecordNoGroupSortA;
83    private RankingHelper mHelper;
84    private final String pkg = "com.android.server.notification";
85    private final int uid = 0;
86    private final String pkg2 = "pkg2";
87    private final int uid2 = 1111111;
88
89    private Context getContext() {
90        return InstrumentationRegistry.getTargetContext();
91    }
92
93    @Before
94    public void setUp() {
95        MockitoAnnotations.initMocks(this);
96        UserHandle user = UserHandle.ALL;
97
98        mHelper = new RankingHelper(getContext(), mPm, handler, mUsageStats,
99                new String[] {ImportanceExtractor.class.getName()});
100
101        mNotiGroupGSortA = new Notification.Builder(getContext())
102                .setContentTitle("A")
103                .setGroup("G")
104                .setSortKey("A")
105                .setWhen(1205)
106                .build();
107        mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
108                "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
109                null, System.currentTimeMillis()), getDefaultChannel());
110
111        mNotiGroupGSortB = new Notification.Builder(getContext())
112                .setContentTitle("B")
113                .setGroup("G")
114                .setSortKey("B")
115                .setWhen(1200)
116                .build();
117        mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
118                "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
119                null, System.currentTimeMillis()), getDefaultChannel());
120
121        mNotiNoGroup = new Notification.Builder(getContext())
122                .setContentTitle("C")
123                .setWhen(1201)
124                .build();
125        mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
126                "package", "package", 1, null, 0, 0, mNotiNoGroup, user,
127                null, System.currentTimeMillis()), getDefaultChannel());
128
129        mNotiNoGroup2 = new Notification.Builder(getContext())
130                .setContentTitle("D")
131                .setWhen(1202)
132                .build();
133        mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
134                "package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
135                null, System.currentTimeMillis()), getDefaultChannel());
136
137        mNotiNoGroupSortA = new Notification.Builder(getContext())
138                .setContentTitle("E")
139                .setWhen(1201)
140                .setSortKey("A")
141                .build();
142        mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
143                "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
144                null, System.currentTimeMillis()), getDefaultChannel());
145
146        final ApplicationInfo legacy = new ApplicationInfo();
147        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
148        final ApplicationInfo upgrade = new ApplicationInfo();
149        upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
150        try {
151            when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
152            when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
153        } catch (PackageManager.NameNotFoundException e) {}
154    }
155
156    private NotificationChannel getDefaultChannel() {
157        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
158                NotificationManager.IMPORTANCE_LOW);
159    }
160
161    private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, String... channelIds)
162            throws Exception {
163        XmlSerializer serializer = new FastXmlSerializer();
164        ByteArrayOutputStream baos = new ByteArrayOutputStream();
165        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
166        serializer.startDocument(null, true);
167        serializer.startTag(null, "ranking");
168        mHelper.writeXml(serializer, false);
169        serializer.endTag(null, "ranking");
170        serializer.endDocument();
171        serializer.flush();
172
173        for (String channelId : channelIds) {
174            mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
175        }
176        return baos;
177    }
178
179    private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
180        assertEquals(expected.getId(), actual.getId());
181        assertEquals(expected.getName(), actual.getName());
182        assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
183        assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
184        assertEquals(expected.getImportance(), actual.getImportance());
185        assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
186        assertEquals(expected.getSound(), actual.getSound());
187        assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
188        assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
189        assertEquals(expected.getGroup(), actual.getGroup());
190    }
191
192    @Test
193    public void testFindAfterRankingWithASplitGroup() throws Exception {
194        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
195        notificationList.add(mRecordGroupGSortA);
196        notificationList.add(mRecordGroupGSortB);
197        notificationList.add(mRecordNoGroup);
198        notificationList.add(mRecordNoGroupSortA);
199        mHelper.sort(notificationList);
200        assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0);
201        assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0);
202        assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0);
203        assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0);
204    }
205
206    @Test
207    public void testSortShouldNotThrowWithPlainNotifications() throws Exception {
208        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
209        notificationList.add(mRecordNoGroup);
210        notificationList.add(mRecordNoGroup2);
211        mHelper.sort(notificationList);
212    }
213
214    @Test
215    public void testSortShouldNotThrowOneSorted() throws Exception {
216        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
217        notificationList.add(mRecordNoGroup);
218        notificationList.add(mRecordNoGroupSortA);
219        mHelper.sort(notificationList);
220    }
221
222    @Test
223    public void testSortShouldNotThrowOneNotification() throws Exception {
224        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
225        notificationList.add(mRecordNoGroup);
226        mHelper.sort(notificationList);
227    }
228
229    @Test
230    public void testSortShouldNotThrowOneSortKey() throws Exception {
231        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
232        notificationList.add(mRecordGroupGSortB);
233        mHelper.sort(notificationList);
234    }
235
236    @Test
237    public void testSortShouldNotThrowOnEmptyList() throws Exception {
238        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
239        mHelper.sort(notificationList);
240    }
241
242    @Test
243    public void testChannelXml() throws Exception {
244        NotificationChannelGroup ncg = new NotificationChannelGroup("1", "2");
245        NotificationChannel channel1 =
246                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
247        NotificationChannel channel2 =
248                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
249        channel2.setSound(new Uri.Builder().scheme("test").build());
250        channel2.setLights(true);
251        channel2.setBypassDnd(true);
252        channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
253        channel2.enableVibration(true);
254        channel2.setGroup(ncg.getId());
255        channel2.setVibrationPattern(new long[] {100, 67, 145, 156});
256
257        mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
258        mHelper.createNotificationChannel(pkg, uid, channel1, true);
259        mHelper.createNotificationChannel(pkg, uid, channel2, false);
260
261        mHelper.setShowBadge(pkg, uid, true);
262        mHelper.setShowBadge(pkg2, uid2, false);
263
264        ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(), channel2.getId(),
265                NotificationChannel.DEFAULT_CHANNEL_ID);
266        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{pkg}, new int[]{uid});
267
268        XmlPullParser parser = Xml.newPullParser();
269        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
270                null);
271        parser.nextTag();
272        mHelper.readXml(parser, false);
273
274        assertFalse(mHelper.canShowBadge(pkg2, uid2));
275        assertTrue(mHelper.canShowBadge(pkg, uid));
276        assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId(), false));
277        compareChannels(channel2,
278                mHelper.getNotificationChannel(pkg, uid, channel2.getId(), false));
279        assertNotNull(mHelper.getNotificationChannel(
280                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false));
281        assertEquals(ncg.getId(),
282                mHelper.getNotificationChannelGroups(pkg, uid, false).getList().get(0).getId());
283        assertEquals(channel2.getGroup(), mHelper.getNotificationChannelGroups(
284                pkg, uid, false).getList().get(0).getChannels().get(0).getGroup());
285    }
286
287    @Test
288    public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
289        NotificationChannel channel1 =
290                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_DEFAULT);
291
292        mHelper.createNotificationChannel(pkg, uid, channel1, true);
293
294        ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(),
295                NotificationChannel.DEFAULT_CHANNEL_ID);
296
297        XmlPullParser parser = Xml.newPullParser();
298        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
299                null);
300        parser.nextTag();
301        mHelper.readXml(parser, false);
302
303        final NotificationChannel updated = mHelper.getNotificationChannel(
304                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
305        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
306        assertFalse(updated.canBypassDnd());
307        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,updated.getLockscreenVisibility());
308        assertEquals(0, updated.getUserLockedFields());
309    }
310
311    @Test
312    public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
313         NotificationChannel channel1 =
314                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN);
315        mHelper.createNotificationChannel(pkg, uid, channel1, true);
316
317        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
318                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
319        defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
320        mHelper.updateNotificationChannel(pkg, uid, defaultChannel);
321
322        ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(),
323                NotificationChannel.DEFAULT_CHANNEL_ID);
324
325        XmlPullParser parser = Xml.newPullParser();
326        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
327                null);
328        parser.nextTag();
329        mHelper.readXml(parser, false);
330
331        assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
332                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
333    }
334
335    @Test
336    public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
337        final String preupgradeXml = "<ranking version=\"1\">\n"
338             + "<package name=\"" + pkg + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
339            + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
340            + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + uid + "\" />\n"
341            + "<package name=\"" + pkg2 + "\" uid=\"" + uid2 + "\" visibility=\""
342            + Notification.VISIBILITY_PRIVATE + "\" />\n"
343            + "</ranking>";
344        XmlPullParser parser = Xml.newPullParser();
345        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
346            null);
347        parser.nextTag();
348        mHelper.readXml(parser, false);
349
350        final NotificationChannel updated1 = mHelper.getNotificationChannel(
351                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
352        assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
353        assertTrue(updated1.canBypassDnd());
354        assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
355        assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
356            | NotificationChannel.USER_LOCKED_PRIORITY
357            | NotificationChannel.USER_LOCKED_VISIBILITY, updated1.getUserLockedFields());
358
359        final NotificationChannel updated2 = mHelper.getNotificationChannel(
360                pkg2, uid2, NotificationChannel.DEFAULT_CHANNEL_ID, false);
361        // clamped
362        assertEquals(NotificationManager.IMPORTANCE_LOW, updated2.getImportance());
363        assertFalse(updated2.canBypassDnd());
364        assertEquals(Notification.VISIBILITY_PRIVATE, updated2.getLockscreenVisibility());
365        assertEquals(NotificationChannel.USER_LOCKED_VISIBILITY, updated2.getUserLockedFields());
366    }
367
368    @Test
369    public void testCreateChannel_blocked() throws Exception {
370        mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_NONE);
371
372        try {
373            mHelper.createNotificationChannel(pkg, uid,
374                    new NotificationChannel(pkg, "", NotificationManager.IMPORTANCE_LOW), true);
375            fail("Channel creation should fail");
376        } catch (IllegalArgumentException e) {
377            // pass
378        }
379    }
380
381    @Test
382    public void testUpdate_userLockedImportance() throws Exception {
383        // all fields locked by user
384        final NotificationChannel channel =
385            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
386        channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
387
388        mHelper.createNotificationChannel(pkg, uid, channel, false);
389
390        // same id, try to update
391        final NotificationChannel channel2 =
392            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
393
394        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
395
396        // no fields should be changed
397        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
398    }
399
400    @Test
401    public void testUpdate_userLockedVisibility() throws Exception {
402        // all fields locked by user
403        final NotificationChannel channel =
404            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
405        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
406        channel.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
407
408        mHelper.createNotificationChannel(pkg, uid, channel, false);
409
410        // same id, try to update
411        final NotificationChannel channel2 =
412            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
413        channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
414
415        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
416
417        // no fields should be changed
418        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
419    }
420
421    @Test
422    public void testUpdate_userLockedVibration() throws Exception {
423        // all fields locked by user
424        final NotificationChannel channel =
425            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
426        channel.setLights(false);
427        channel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
428
429        mHelper.createNotificationChannel(pkg, uid, channel, false);
430
431        // same id, try to update
432        final NotificationChannel channel2 =
433            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
434        channel2.enableVibration(true);
435        channel2.setVibrationPattern(new long[] {100});
436
437        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
438
439        // no fields should be changed
440        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
441    }
442
443    @Test
444    public void testUpdate_userLockedLights() throws Exception {
445        // all fields locked by user
446        final NotificationChannel channel =
447            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
448        channel.setLights(false);
449        channel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
450
451        mHelper.createNotificationChannel(pkg, uid, channel, false);
452
453        // same id, try to update
454        final NotificationChannel channel2 =
455            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
456        channel2.setLights(true);
457
458        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
459
460        // no fields should be changed
461        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
462    }
463
464    @Test
465    public void testUpdate_userLockedPriority() throws Exception {
466        // all fields locked by user
467        final NotificationChannel channel =
468            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
469        channel.setBypassDnd(true);
470        channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
471
472        mHelper.createNotificationChannel(pkg, uid, channel, false);
473
474        // same id, try to update all fields
475        final NotificationChannel channel2 =
476            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
477        channel2.setBypassDnd(false);
478
479        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
480
481        // no fields should be changed
482        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
483    }
484
485    @Test
486    public void testUpdate_userLockedRingtone() throws Exception {
487        // all fields locked by user
488        final NotificationChannel channel =
489            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
490        channel.setSound(new Uri.Builder().scheme("test").build());
491        channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
492
493        mHelper.createNotificationChannel(pkg, uid, channel, false);
494
495        // same id, try to update all fields
496        final NotificationChannel channel2 =
497            new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
498        channel2.setSound(new Uri.Builder().scheme("test2").build());
499
500        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
501
502        // no fields should be changed
503        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
504    }
505
506    @Test
507    public void testUpdate_userLockedBadge() throws Exception {
508        final NotificationChannel channel =
509                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
510        channel.setShowBadge(true);
511        channel.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
512
513        mHelper.createNotificationChannel(pkg, uid, channel, false);
514
515        final NotificationChannel channel2 =
516                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
517        channel2.setShowBadge(false);
518
519        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
520
521        // no fields should be changed
522        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
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", NotificationManager.IMPORTANCE_LOW);
530        channel.setSound(new Uri.Builder().scheme("test").build());
531        channel.setLights(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());
541        channel2.setLights(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 testGetChannelWithFallback() throws Exception {
553        NotificationChannel channel =
554                mHelper.getNotificationChannelWithFallback(pkg, uid, "garbage", false);
555        assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID, channel.getId());
556    }
557
558    @Test
559    public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
560        final NotificationChannel channel =
561                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
562        channel.setSound(new Uri.Builder().scheme("test").build());
563        channel.setLights(true);
564        channel.setBypassDnd(true);
565        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
566        channel.setShowBadge(true);
567        int lockMask = 0;
568        for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
569            lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
570        }
571        channel.lockFields(lockMask);
572
573        mHelper.createNotificationChannel(pkg, uid, channel, true);
574
575        NotificationChannel savedChannel =
576                mHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
577
578        assertEquals(channel.getName(), savedChannel.getName());
579        assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
580        assertFalse(savedChannel.canBypassDnd());
581        assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
582        assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
583    }
584
585    @Test
586    public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
587        final NotificationChannel channel =
588                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
589        channel.setSound(new Uri.Builder().scheme("test").build());
590        channel.setLights(true);
591        channel.setBypassDnd(true);
592        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
593        channel.setShowBadge(true);
594        int lockMask = 0;
595        for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
596            lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
597        }
598        channel.lockFields(lockMask);
599
600        mHelper.createNotificationChannel(pkg, uid, channel, true);
601
602        NotificationChannel savedChannel =
603                mHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
604
605        assertEquals(channel.getName(), savedChannel.getName());
606        assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
607        assertFalse(savedChannel.canBypassDnd());
608        assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
609        assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
610    }
611
612    @Test
613    public void testGetDeletedChannel() throws Exception {
614        NotificationChannel channel =
615                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
616        channel.setSound(new Uri.Builder().scheme("test").build());
617        channel.setLights(true);
618        channel.setBypassDnd(true);
619        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
620        channel.enableVibration(true);
621        channel.setVibrationPattern(new long[] {100, 67, 145, 156});
622
623        mHelper.createNotificationChannel(pkg, uid, channel, true);
624        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
625
626        // Does not return deleted channel
627        NotificationChannel response =
628                mHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
629        assertNull(response);
630
631        // Returns deleted channel
632        response = mHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
633        compareChannels(channel, response);
634        assertTrue(response.isDeleted());
635    }
636
637    @Test
638    public void testGetDeletedChannels() throws Exception {
639        Map<String, NotificationChannel> channelMap = new HashMap<>();
640        NotificationChannel channel =
641                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
642        channel.setSound(new Uri.Builder().scheme("test").build());
643        channel.setLights(true);
644        channel.setBypassDnd(true);
645        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
646        channel.enableVibration(true);
647        channel.setVibrationPattern(new long[] {100, 67, 145, 156});
648        channelMap.put(channel.getId(), channel);
649        NotificationChannel channel2 =
650                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
651        channelMap.put(channel2.getId(), channel2);
652        mHelper.createNotificationChannel(pkg, uid, channel, true);
653        mHelper.createNotificationChannel(pkg, uid, channel2, true);
654
655        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
656
657        // Returns only non-deleted channels
658        List<NotificationChannel> channels =
659                mHelper.getNotificationChannels(pkg, uid, false).getList();
660        assertEquals(2, channels.size());   // Default channel + non-deleted channel
661        for (NotificationChannel nc : channels) {
662            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
663                compareChannels(channel2, nc);
664            }
665        }
666
667        // Returns deleted channels too
668        channels =  mHelper.getNotificationChannels(pkg, uid, true).getList();
669        assertEquals(3, channels.size());               // Includes default channel
670        for (NotificationChannel nc : channels) {
671            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
672                compareChannels(channelMap.get(nc.getId()), nc);
673            }
674        }
675    }
676
677    @Test
678    public void testUpdateDeletedChannels() throws Exception {
679        NotificationChannel channel =
680                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
681        mHelper.createNotificationChannel(pkg, uid, channel, true);
682
683        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
684
685        channel.setSound(new Uri.Builder().scheme("test").build());
686        try {
687            mHelper.updateNotificationChannel(pkg, uid, channel);
688            fail("Updated deleted channel");
689        } catch (IllegalArgumentException e) {
690            // :)
691        }
692
693        try {
694            mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel);
695            fail("Updated deleted channel");
696        } catch (IllegalArgumentException e) {
697            // :)
698        }
699    }
700
701    @Test
702    public void testCreateDeletedChannel() throws Exception {
703        long[] vibration = new long[] {100, 67, 145, 156};
704        NotificationChannel channel =
705                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
706        channel.setVibrationPattern(vibration);
707
708        mHelper.createNotificationChannel(pkg, uid, channel, true);
709        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
710
711        NotificationChannel newChannel = new NotificationChannel(
712                channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
713        newChannel.setVibrationPattern(new long[] {100});
714
715        mHelper.createNotificationChannel(pkg, uid, newChannel, true);
716
717        // No long deleted, using old settings
718        compareChannels(channel,
719                mHelper.getNotificationChannel(pkg, uid, newChannel.getId(), false));
720    }
721
722    @Test
723    public void testCreateChannel_alreadyExists() throws Exception {
724        long[] vibration = new long[] {100, 67, 145, 156};
725        NotificationChannel channel =
726                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
727        channel.setVibrationPattern(vibration);
728
729        mHelper.createNotificationChannel(pkg, uid, channel, true);
730
731        NotificationChannel newChannel = new NotificationChannel(
732                channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
733        newChannel.setVibrationPattern(new long[] {100});
734
735        mHelper.createNotificationChannel(pkg, uid, newChannel, true);
736
737        // Old settings not overridden
738        compareChannels(channel,
739                mHelper.getNotificationChannel(pkg, uid, newChannel.getId(), false));
740    }
741
742    @Test
743    public void testPermanentlyDeleteChannels() throws Exception {
744        NotificationChannel channel1 =
745                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
746        NotificationChannel channel2 =
747                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
748
749        mHelper.createNotificationChannel(pkg, uid, channel1, true);
750        mHelper.createNotificationChannel(pkg, uid, channel2, false);
751
752        mHelper.permanentlyDeleteNotificationChannels(pkg, uid);
753
754        // Only default channel remains
755        assertEquals(1, mHelper.getNotificationChannels(pkg, uid, true).getList().size());
756    }
757
758    @Test
759    public void testOnPackageChanged_packageRemoval() throws Exception {
760        // Deleted
761        NotificationChannel channel1 =
762                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
763        mHelper.createNotificationChannel(pkg, uid, channel1, true);
764
765        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
766
767        assertEquals(0, mHelper.getNotificationChannels(pkg, uid, true).getList().size());
768
769        // Not deleted
770        mHelper.createNotificationChannel(pkg, uid, channel1, true);
771
772        mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
773        assertEquals(2, mHelper.getNotificationChannels(pkg, uid, false).getList().size());
774    }
775
776    @Test
777    public void testOnPackageChanged_packageRemoval_importance() throws Exception {
778        mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_HIGH);
779
780        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
781
782        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(pkg, uid));
783    }
784
785    @Test
786    public void testOnPackageChanged_packageRemoval_groups() throws Exception {
787        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
788        mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
789        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
790        mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true);
791
792        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
793
794        assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size());
795    }
796
797    @Test
798    public void testRecordDefaults() throws Exception {
799        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(pkg, uid));
800        assertEquals(true, mHelper.canShowBadge(pkg, uid));
801        assertEquals(1, mHelper.getNotificationChannels(pkg, uid, false).getList().size());
802    }
803
804    @Test
805    public void testCreateGroup() throws Exception {
806        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
807        mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
808        assertEquals(ncg, mHelper.getNotificationChannelGroups(pkg, uid, false).getList().get(0));
809    }
810
811    @Test
812    public void testCannotCreateChannel_badGroup() throws Exception {
813        NotificationChannel channel1 =
814                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
815        channel1.setGroup("garbage");
816        try {
817            mHelper.createNotificationChannel(pkg, uid, channel1, true);
818            fail("Created a channel with a bad group");
819        } catch (IllegalArgumentException e) {}
820    }
821
822    @Test
823    public void testCannotCreateChannel_goodGroup() throws Exception {
824        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
825        mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
826        NotificationChannel channel1 =
827                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
828        channel1.setGroup(ncg.getId());
829        mHelper.createNotificationChannel(pkg, uid, channel1, true);
830
831        assertEquals(ncg.getId(),
832                mHelper.getNotificationChannel(pkg, uid, channel1.getId(), false).getGroup());
833    }
834
835    @Test
836    public void testGetChannelGroups() throws Exception {
837        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
838        mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
839        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
840        mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true);
841
842        NotificationChannel channel1 =
843                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
844        channel1.setGroup(ncg.getId());
845        mHelper.createNotificationChannel(pkg, uid, channel1, true);
846        NotificationChannel channel1a =
847                new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
848        channel1a.setGroup(ncg.getId());
849        mHelper.createNotificationChannel(pkg, uid, channel1a, true);
850
851        NotificationChannel channel2 =
852                new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
853        channel2.setGroup(ncg2.getId());
854        mHelper.createNotificationChannel(pkg, uid, channel2, true);
855
856        NotificationChannel channel3 =
857                new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
858        mHelper.createNotificationChannel(pkg, uid, channel3, true);
859
860        List<NotificationChannelGroup> actual =
861                mHelper.getNotificationChannelGroups(pkg, uid, true).getList();
862        assertEquals(3, actual.size());
863        for (NotificationChannelGroup group: actual) {
864            if (group.getId() == null) {
865                assertEquals(2, group.getChannels().size()); // misc channel too
866                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
867                || channel3.getId().equals(group.getChannels().get(1).getId()));
868            } else if (group.getId().equals(ncg.getId())) {
869                assertEquals(2, group.getChannels().size());
870                if (group.getChannels().get(0).getId().equals(channel1.getId())) {
871                    assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId()));
872                } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) {
873                    assertTrue(group.getChannels().get(1).getId().equals(channel1.getId()));
874                } else {
875                    fail("expected channel not found");
876                }
877            } else if (group.getId().equals(ncg2.getId())) {
878                assertEquals(1, group.getChannels().size());
879                assertEquals(channel2.getId(), group.getChannels().get(0).getId());
880            }
881        }
882    }
883}
884