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