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