blob: 260555f7125606af23ca2ed4d4cbfdfc8eb9e2f0 [file] [log] [blame]
Maurice Lam132710e2017-03-03 19:13:42 -08001/*
2 * Copyright (C) 2017 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
Rohan Shah20790b82018-07-02 17:21:04 -070014 * limitations under the License
Maurice Lam132710e2017-03-03 19:13:42 -080015 */
16
Ned Burnsf81c4c42019-01-07 14:10:43 -050017package com.android.systemui.statusbar.notification.collection;
Maurice Lam132710e2017-03-03 19:13:42 -080018
Julia Reynoldsfc640012018-02-21 12:25:27 -050019import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
20import static android.app.AppOpsManager.OP_CAMERA;
Julia Reynolds25926af2018-05-01 17:05:33 -040021import static android.app.Notification.CATEGORY_ALARM;
22import static android.app.Notification.CATEGORY_CALL;
23import static android.app.Notification.CATEGORY_EVENT;
24import static android.app.Notification.CATEGORY_MESSAGE;
25import static android.app.Notification.CATEGORY_REMINDER;
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -050026import static android.app.NotificationManager.IMPORTANCE_LOW;
27import static android.app.NotificationManager.IMPORTANCE_MIN;
28
29import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
30import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040031import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK;
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -050032import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
Julia Reynoldsfc640012018-02-21 12:25:27 -050033
34import static junit.framework.Assert.assertEquals;
35
Maurice Lam132710e2017-03-03 19:13:42 -080036import static org.junit.Assert.assertFalse;
37import static org.junit.Assert.assertTrue;
Julia Reynoldsfc640012018-02-21 12:25:27 -050038import static org.mockito.ArgumentMatchers.any;
Maurice Lam132710e2017-03-03 19:13:42 -080039import static org.mockito.Matchers.eq;
40import static org.mockito.Mockito.mock;
41import static org.mockito.Mockito.when;
42
43import android.Manifest;
44import android.app.Notification;
Selim Cinek608a57a2017-04-28 16:50:41 -070045import android.app.NotificationChannel;
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -050046import android.app.NotificationManager;
Tony Mak628cb932018-06-19 18:30:41 +010047import android.app.PendingIntent;
Beverlye98937a2018-11-15 10:18:57 -050048import android.app.Person;
Tony Mak628cb932018-06-19 18:30:41 +010049import android.content.Intent;
Maurice Lam132710e2017-03-03 19:13:42 -080050import android.content.pm.IPackageManager;
51import android.content.pm.PackageManager;
Tony Mak628cb932018-06-19 18:30:41 +010052import android.graphics.drawable.Icon;
Julia Reynolds5bbb6da2018-03-28 10:48:37 -040053import android.media.session.MediaSession;
Maurice Lam132710e2017-03-03 19:13:42 -080054import android.os.Bundle;
Yohei Yukawa72769462019-01-20 09:28:08 -080055import android.os.Process;
Selim Cinek608a57a2017-04-28 16:50:41 -070056import android.service.notification.NotificationListenerService;
Tony Mak628cb932018-06-19 18:30:41 +010057import android.service.notification.NotificationListenerService.Ranking;
58import android.service.notification.SnoozeCriterion;
Maurice Lam132710e2017-03-03 19:13:42 -080059import android.service.notification.StatusBarNotification;
Jason Monk6dceace2018-05-15 20:24:07 -040060import android.testing.AndroidTestingRunner;
Jason Monka716bac2018-12-05 15:48:21 -050061import android.testing.TestableLooper;
Jason Monk6dceace2018-05-15 20:24:07 -040062import android.testing.TestableLooper.RunWithLooper;
Julia Reynoldsfc640012018-02-21 12:25:27 -050063import android.util.ArraySet;
Maurice Lam132710e2017-03-03 19:13:42 -080064
Jason Monk297c04e2018-08-23 17:16:59 -040065import com.android.systemui.Dependency;
Julia Reynoldsfc640012018-02-21 12:25:27 -050066import com.android.systemui.ForegroundServiceController;
Jason Monk297c04e2018-08-23 17:16:59 -040067import com.android.systemui.InitController;
Maurice Lam132710e2017-03-03 19:13:42 -080068import com.android.systemui.SysuiTestCase;
Selim Cinekc3fec682019-06-06 18:11:07 -070069import com.android.systemui.plugins.statusbar.StatusBarStateController;
Rohan Shah20790b82018-07-02 17:21:04 -070070import com.android.systemui.statusbar.NotificationTestHelper;
Ned Burnsf81c4c42019-01-07 14:10:43 -050071import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
Rohan Shah20790b82018-07-02 17:21:04 -070072import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Selim Cinek608a57a2017-04-28 16:50:41 -070073import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk297c04e2018-08-23 17:16:59 -040074import com.android.systemui.statusbar.phone.ShadeController;
Maurice Lam132710e2017-03-03 19:13:42 -080075
76import org.junit.Before;
77import org.junit.Test;
78import org.junit.runner.RunWith;
Julia Reynoldsfc640012018-02-21 12:25:27 -050079import org.mockito.Mock;
80import org.mockito.MockitoAnnotations;
Maurice Lam132710e2017-03-03 19:13:42 -080081
Dieter Hsu36e1ebc2018-06-06 15:41:46 +080082import java.util.ArrayList;
Gustav Sennton1463d832018-11-06 16:12:48 +000083import java.util.Collections;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040084import java.util.HashMap;
Gustav Sennton1463d832018-11-06 16:12:48 +000085import java.util.List;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040086import java.util.Map;
87
88import androidx.test.filters.SmallTest;
Dieter Hsu36e1ebc2018-06-06 15:41:46 +080089
Maurice Lam132710e2017-03-03 19:13:42 -080090@SmallTest
Jason Monk6dceace2018-05-15 20:24:07 -040091@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050092@RunWithLooper
Maurice Lam132710e2017-03-03 19:13:42 -080093public class NotificationDataTest extends SysuiTestCase {
94
95 private static final int UID_NORMAL = 123;
96 private static final int UID_ALLOW_DURING_SETUP = 456;
Tony Mak628cb932018-06-19 18:30:41 +010097 private static final NotificationChannel NOTIFICATION_CHANNEL =
98 new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
Maurice Lam132710e2017-03-03 19:13:42 -080099
100 private final StatusBarNotification mMockStatusBarNotification =
101 mock(StatusBarNotification.class);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500102 @Mock
103 ForegroundServiceController mFsc;
104 @Mock
Jason Monk297c04e2018-08-23 17:16:59 -0400105 NotificationData.KeyguardEnvironment mEnvironment;
Maurice Lam132710e2017-03-03 19:13:42 -0800106
107 private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500108 private TestableNotificationData mNotificationData;
Selim Cinek608a57a2017-04-28 16:50:41 -0700109 private ExpandableNotificationRow mRow;
Maurice Lam132710e2017-03-03 19:13:42 -0800110
111 @Before
112 public void setUp() throws Exception {
Jason Monka716bac2018-12-05 15:48:21 -0500113 com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
Julia Reynoldsfc640012018-02-21 12:25:27 -0500114 MockitoAnnotations.initMocks(this);
Maurice Lam132710e2017-03-03 19:13:42 -0800115 when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500116 when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
Maurice Lam132710e2017-03-03 19:13:42 -0800117
118 when(mMockPackageManager.checkUidPermission(
119 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
120 eq(UID_NORMAL)))
121 .thenReturn(PackageManager.PERMISSION_DENIED);
122 when(mMockPackageManager.checkUidPermission(
123 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
124 eq(UID_ALLOW_DURING_SETUP)))
125 .thenReturn(PackageManager.PERMISSION_GRANTED);
Selim Cinek608a57a2017-04-28 16:50:41 -0700126
Julia Reynoldsfc640012018-02-21 12:25:27 -0500127 mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
Jason Monk297c04e2018-08-23 17:16:59 -0400128 mDependency.injectTestDependency(NotificationGroupManager.class,
Selim Cinekc3fec682019-06-06 18:11:07 -0700129 new NotificationGroupManager(mock(StatusBarStateController.class)));
Jason Monk297c04e2018-08-23 17:16:59 -0400130 mDependency.injectMockDependency(ShadeController.class);
131 mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500132 when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
133 when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
Jason Monk297c04e2018-08-23 17:16:59 -0400134 mNotificationData = new TestableNotificationData();
Selim Cinek608a57a2017-04-28 16:50:41 -0700135 mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
136 mRow = new NotificationTestHelper(getContext()).createRow();
Tony Mak7d4b3a52018-11-27 17:29:36 +0000137 Dependency.get(InitController.class).executePostInitTasks();
Maurice Lam132710e2017-03-03 19:13:42 -0800138 }
139
140 @Test
Selim Cinek608a57a2017-04-28 16:50:41 -0700141 public void testChannelSetWhenAdded() {
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400142 Bundle override = new Bundle();
143 override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
144 mNotificationData.rankingOverrides.put(mRow.getEntry().key, override);
Selim Cinek608a57a2017-04-28 16:50:41 -0700145 mNotificationData.add(mRow.getEntry());
Tony Mak628cb932018-06-19 18:30:41 +0100146 assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
Selim Cinek608a57a2017-04-28 16:50:41 -0700147 }
148
Julia Reynoldsfc640012018-02-21 12:25:27 -0500149 @Test
150 public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
151 mNotificationData.add(mRow.getEntry());
152 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
153 mNotificationData.add(row2.getEntry());
154 ExpandableNotificationRow diffPkg =
Yohei Yukawa72769462019-01-20 09:28:08 -0800155 new NotificationTestHelper(getContext()).createRow("pkg", 4000,
156 Process.myUserHandle());
Julia Reynoldsfc640012018-02-21 12:25:27 -0500157 mNotificationData.add(diffPkg.getEntry());
158
159 ArraySet<Integer> expectedOps = new ArraySet<>();
160 expectedOps.add(OP_CAMERA);
161 expectedOps.add(OP_ACCEPT_HANDOVER);
162
163 for (int op : expectedOps) {
164 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400165 NotificationTestHelper.PKG, mRow.getEntry().key, true);
166 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
167 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500168 }
169 for (int op : expectedOps) {
170 assertTrue(mRow.getEntry().key + " doesn't have op " + op,
171 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
172 assertTrue(row2.getEntry().key + " doesn't have op " + op,
173 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
174 assertFalse(diffPkg.getEntry().key + " has op " + op,
175 mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
176 }
177 }
178
179 @Test
180 public void testAppOpsRemoval() throws Exception {
181 mNotificationData.add(mRow.getEntry());
182 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
183 mNotificationData.add(row2.getEntry());
184
185 ArraySet<Integer> expectedOps = new ArraySet<>();
186 expectedOps.add(OP_CAMERA);
187 expectedOps.add(OP_ACCEPT_HANDOVER);
188
189 for (int op : expectedOps) {
190 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400191 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500192 }
193
194 expectedOps.remove(OP_ACCEPT_HANDOVER);
195 mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400196 NotificationTestHelper.PKG, row2.getEntry().key, false);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500197
198 assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
199 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
200 assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
201 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
202 assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
203 mNotificationData.get(mRow.getEntry().key)
204 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
205 assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
206 mNotificationData.get(row2.getEntry().key)
207 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
208 }
209
210 @Test
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800211 public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
212 throws Exception {
213 mNotificationData.add(mRow.getEntry());
214 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
215 mNotificationData.add(row2.getEntry());
216
217 when(mEnvironment.isNotificationForCurrentProfiles(
218 mRow.getEntry().notification)).thenReturn(false);
219 when(mEnvironment.isNotificationForCurrentProfiles(
220 row2.getEntry().notification)).thenReturn(true);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500221 ArrayList<NotificationEntry> result =
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800222 mNotificationData.getNotificationsForCurrentUser();
223
Jason Monk297c04e2018-08-23 17:16:59 -0400224 assertEquals(result.size(), 1);
225 junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800226 }
227
228 @Test
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400229 public void testIsExemptFromDndVisualSuppression_foreground() {
230 initStatusBarNotification(false);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500231
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400232 Notification n = mMockStatusBarNotification.getNotification();
233 n.flags = Notification.FLAG_FOREGROUND_SERVICE;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500234 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500235 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400236 Bundle override = new Bundle();
237 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
238 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400239
Gus Prevasec9e1f02018-12-18 15:28:12 -0500240 assertTrue(entry.isExemptFromDndVisualSuppression());
241 assertFalse(entry.shouldSuppressAmbient());
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400242 }
243
244 @Test
245 public void testIsExemptFromDndVisualSuppression_media() {
246 initStatusBarNotification(false);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400247 Notification n = mMockStatusBarNotification.getNotification();
248 Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
249 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
250 n = nb.build();
251 when(mMockStatusBarNotification.getNotification()).thenReturn(n);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500252 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500253 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400254 Bundle override = new Bundle();
255 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
256 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400257
Gus Prevasec9e1f02018-12-18 15:28:12 -0500258 assertTrue(entry.isExemptFromDndVisualSuppression());
259 assertFalse(entry.shouldSuppressAmbient());
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400260 }
261
262 @Test
263 public void testIsExemptFromDndVisualSuppression_system() {
264 initStatusBarNotification(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500265 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400266 entry.mIsSystemNotification = true;
Gus Prevasec9e1f02018-12-18 15:28:12 -0500267 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400268 Bundle override = new Bundle();
269 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
270 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400271
Gus Prevasec9e1f02018-12-18 15:28:12 -0500272 assertTrue(entry.isExemptFromDndVisualSuppression());
273 assertFalse(entry.shouldSuppressAmbient());
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400274 }
275
Julia Reynolds25926af2018-05-01 17:05:33 -0400276 @Test
277 public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
278 initStatusBarNotification(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500279 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Julia Reynolds25926af2018-05-01 17:05:33 -0400280 entry.mIsSystemNotification = true;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400281 Bundle override = new Bundle();
282 override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
283 mNotificationData.rankingOverrides.put(entry.key, override);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500284 mNotificationData.add(entry);
285
Julia Reynolds25926af2018-05-01 17:05:33 -0400286 when(mMockStatusBarNotification.getNotification()).thenReturn(
287 new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build());
288
Gus Prevasec9e1f02018-12-18 15:28:12 -0500289 assertFalse(entry.isExemptFromDndVisualSuppression());
290 assertTrue(entry.shouldSuppressAmbient());
Julia Reynolds25926af2018-05-01 17:05:33 -0400291
292 when(mMockStatusBarNotification.getNotification()).thenReturn(
293 new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build());
294
Gus Prevasec9e1f02018-12-18 15:28:12 -0500295 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400296
297 when(mMockStatusBarNotification.getNotification()).thenReturn(
298 new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build());
299
Gus Prevasec9e1f02018-12-18 15:28:12 -0500300 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400301
302 when(mMockStatusBarNotification.getNotification()).thenReturn(
303 new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build());
304
Gus Prevasec9e1f02018-12-18 15:28:12 -0500305 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400306
307 when(mMockStatusBarNotification.getNotification()).thenReturn(
308 new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build());
309
Gus Prevasec9e1f02018-12-18 15:28:12 -0500310 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400311 }
312
Tony Mak628cb932018-06-19 18:30:41 +0100313 @Test
314 public void testCreateNotificationDataEntry_RankingUpdate() {
315 Ranking ranking = mock(Ranking.class);
Gustav Sennton1463d832018-11-06 16:12:48 +0000316 initStatusBarNotification(false);
Tony Mak628cb932018-06-19 18:30:41 +0100317
Gustav Sennton1463d832018-11-06 16:12:48 +0000318 List<Notification.Action> appGeneratedSmartActions =
319 Collections.singletonList(createContextualAction("appGeneratedAction"));
320 mMockStatusBarNotification.getNotification().actions =
321 appGeneratedSmartActions.toArray(new Notification.Action[0]);
322
323 List<Notification.Action> systemGeneratedSmartActions =
324 Collections.singletonList(createAction("systemGeneratedAction"));
325 when(ranking.getSmartActions()).thenReturn(systemGeneratedSmartActions);
Tony Mak628cb932018-06-19 18:30:41 +0100326
327 when(ranking.getChannel()).thenReturn(NOTIFICATION_CHANNEL);
328
329 when(ranking.getUserSentiment()).thenReturn(Ranking.USER_SENTIMENT_NEGATIVE);
330
331 SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
332 ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
333 snoozeCriterions.add(snoozeCriterion);
334 when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
335
Ned Burnsf81c4c42019-01-07 14:10:43 -0500336 NotificationEntry entry =
337 new NotificationEntry(mMockStatusBarNotification, ranking);
Tony Mak628cb932018-06-19 18:30:41 +0100338
Gustav Sennton1463d832018-11-06 16:12:48 +0000339 assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
Tony Mak628cb932018-06-19 18:30:41 +0100340 assertEquals(NOTIFICATION_CHANNEL, entry.channel);
341 assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment);
342 assertEquals(snoozeCriterions, entry.snoozeCriteria);
343 }
344
Beverlye98937a2018-11-15 10:18:57 -0500345 @Test
346 public void notificationDataEntry_testIsLastMessageFromReply() {
347 Person.Builder person = new Person.Builder()
348 .setName("name")
349 .setKey("abc")
350 .setUri("uri")
351 .setBot(true);
352
353 // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
354 Bundle bundle = new Bundle();
355 bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
356 Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
357 "text", 0, person.build()).toBundle() };
358 bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
359
360 Notification notification = new Notification.Builder(mContext, "test")
361 .addExtras(bundle)
362 .build();
363 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
364 notification, mContext.getUser(), "", 0);
365
Ned Burnsf81c4c42019-01-07 14:10:43 -0500366 NotificationEntry entry = new NotificationEntry(sbn);
Beverlye98937a2018-11-15 10:18:57 -0500367 entry.setHasSentReply();
368
369 assertTrue(entry.isLastMessageFromReply());
370 }
371
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500372 @Test
373 public void personHighPriority() {
374 Person person = new Person.Builder()
375 .setName("name")
376 .setKey("abc")
377 .setUri("uri")
378 .setBot(true)
379 .build();
380
381 Notification notification = new Notification.Builder(mContext, "test")
382 .addPerson(person)
383 .build();
384
385 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
386 notification, mContext.getUser(), "", 0);
387
388 assertTrue(mNotificationData.isHighPriority(sbn));
389 }
390
391 @Test
392 public void messagingStyleHighPriority() {
393
394 Notification notification = new Notification.Builder(mContext, "test")
395 .setStyle(new Notification.MessagingStyle(""))
396 .build();
397
398 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
399 notification, mContext.getUser(), "", 0);
400
401 assertTrue(mNotificationData.isHighPriority(sbn));
402 }
403
404 @Test
405 public void minForegroundNotHighPriority() {
406 Notification notification = mock(Notification.class);
407 when(notification.isForegroundService()).thenReturn(true);
408
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500409 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
410 notification, mContext.getUser(), "", 0);
411
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400412 Bundle override = new Bundle();
413 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
414 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
415
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500416 assertFalse(mNotificationData.isHighPriority(sbn));
417 }
418
419 @Test
420 public void lowForegroundHighPriority() {
421 Notification notification = mock(Notification.class);
422 when(notification.isForegroundService()).thenReturn(true);
423
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400424 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
425 notification, mContext.getUser(), "", 0);
426
427 Bundle override = new Bundle();
428 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
429 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
430
431 assertTrue(mNotificationData.isHighPriority(sbn));
432 }
433
434 @Test
435 public void userChangeTrumpsHighPriorityCharacteristics() {
436 Person person = new Person.Builder()
437 .setName("name")
438 .setKey("abc")
439 .setUri("uri")
440 .setBot(true)
441 .build();
442
443 Notification notification = new Notification.Builder(mContext, "test")
444 .addPerson(person)
445 .setStyle(new Notification.MessagingStyle(""))
446 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
447 .build();
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500448
449 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
450 notification, mContext.getUser(), "", 0);
451
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400452 NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
453 channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
454
455 Bundle override = new Bundle();
456 override.putParcelable(OVERRIDE_CHANNEL, channel);
457 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
458
459 assertFalse(mNotificationData.isHighPriority(sbn));
460 }
461
462 @Test
463 public void testSort_highPriorityTrumpsNMSRank() {
464 // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
465 // front
466 Notification aN = new Notification.Builder(mContext, "test")
467 .setStyle(new Notification.MessagingStyle(""))
468 .build();
469 StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
470 aN, mContext.getUser(), "", 0);
471 NotificationEntry a = new NotificationEntry(aSbn);
472 a.setRow(mock(ExpandableNotificationRow.class));
473 a.setIsHighPriority(false);
474
475 Bundle override = new Bundle();
476 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
477 override.putInt(OVERRIDE_RANK, 1);
478 mNotificationData.rankingOverrides.put(a.key, override);
479
480 Notification bN = new Notification.Builder(mContext, "test")
481 .setStyle(new Notification.MessagingStyle(""))
482 .build();
483 StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
484 bN, mContext.getUser(), "", 0);
485 NotificationEntry b = new NotificationEntry(bSbn);
486 b.setIsHighPriority(true);
487 b.setRow(mock(ExpandableNotificationRow.class));
488
489 Bundle bOverride = new Bundle();
490 bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
491 bOverride.putInt(OVERRIDE_RANK, 2);
492 mNotificationData.rankingOverrides.put(b.key, bOverride);
493
494 assertEquals(1, mNotificationData.mRankingComparator.compare(a, b));
495 }
496
497 @Test
498 public void testSort_samePriorityUsesNMSRank() {
499 // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
500 // front
501 Notification aN = new Notification.Builder(mContext, "test")
502 .setStyle(new Notification.MessagingStyle(""))
503 .build();
504 StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
505 aN, mContext.getUser(), "", 0);
506 NotificationEntry a = new NotificationEntry(aSbn);
507 a.setRow(mock(ExpandableNotificationRow.class));
508 a.setIsHighPriority(false);
509
510 Bundle override = new Bundle();
511 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
512 override.putInt(OVERRIDE_RANK, 1);
513 mNotificationData.rankingOverrides.put(a.key, override);
514
515 Notification bN = new Notification.Builder(mContext, "test")
516 .setStyle(new Notification.MessagingStyle(""))
517 .build();
518 StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
519 bN, mContext.getUser(), "", 0);
520 NotificationEntry b = new NotificationEntry(bSbn);
521 b.setRow(mock(ExpandableNotificationRow.class));
522 b.setIsHighPriority(false);
523
524 Bundle bOverride = new Bundle();
525 bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
526 bOverride.putInt(OVERRIDE_RANK, 2);
527 mNotificationData.rankingOverrides.put(b.key, bOverride);
528
529 assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500530 }
531
Maurice Lam132710e2017-03-03 19:13:42 -0800532 private void initStatusBarNotification(boolean allowDuringSetup) {
533 Bundle bundle = new Bundle();
534 bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
535 Notification notification = new Notification.Builder(mContext, "test")
536 .addExtras(bundle)
537 .build();
538 when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
539 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700540
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500541 public static class TestableNotificationData extends NotificationData {
Jason Monk297c04e2018-08-23 17:16:59 -0400542 public TestableNotificationData() {
543 super();
Selim Cinek608a57a2017-04-28 16:50:41 -0700544 }
545
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500546 public static final String OVERRIDE_RANK = "r";
547 public static final String OVERRIDE_DND = "dnd";
548 public static final String OVERRIDE_VIS_OVERRIDE = "vo";
549 public static final String OVERRIDE_VIS_EFFECTS = "ve";
550 public static final String OVERRIDE_IMPORTANCE = "i";
551 public static final String OVERRIDE_IMP_EXP = "ie";
552 public static final String OVERRIDE_GROUP = "g";
553 public static final String OVERRIDE_CHANNEL = "c";
554 public static final String OVERRIDE_PEOPLE = "p";
555 public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
556 public static final String OVERRIDE_BADGE = "b";
557 public static final String OVERRIDE_USER_SENTIMENT = "us";
558 public static final String OVERRIDE_HIDDEN = "h";
559 public static final String OVERRIDE_LAST_ALERTED = "la";
560 public static final String OVERRIDE_NOISY = "n";
561 public static final String OVERRIDE_SMART_ACTIONS = "sa";
562 public static final String OVERRIDE_SMART_REPLIES = "sr";
563 public static final String OVERRIDE_BUBBLE = "cb";
564
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400565 public Map<String, Bundle> rankingOverrides = new HashMap<>();
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500566
Selim Cinek608a57a2017-04-28 16:50:41 -0700567 @Override
Tony Mak628cb932018-06-19 18:30:41 +0100568 protected boolean getRanking(String key, Ranking outRanking) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900569 super.getRanking(key, outRanking);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500570
571 ArrayList<String> currentAdditionalPeople = new ArrayList<>();
572 if (outRanking.getAdditionalPeople() != null) {
573 currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
Beverly5a20a5e2018-03-06 15:02:44 -0500574 }
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500575
576 ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
577 if (outRanking.getSnoozeCriteria() != null) {
578 currentSnooze.addAll(outRanking.getSnoozeCriteria());
579 }
580
581 ArrayList<Notification.Action> currentActions = new ArrayList<>();
582 if (outRanking.getSmartActions() != null) {
583 currentActions.addAll(outRanking.getSmartActions());
584 }
585
586 ArrayList<CharSequence> currentReplies = new ArrayList<>();
587 if (outRanking.getSmartReplies() != null) {
588 currentReplies.addAll(outRanking.getSmartReplies());
589 }
590
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400591 if (rankingOverrides.get(key) != null) {
592 Bundle overrides = rankingOverrides.get(key);
593 outRanking.populate(key,
594 overrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
595 overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()),
596 overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()),
597 overrides.getInt(OVERRIDE_VIS_EFFECTS,
598 outRanking.getSuppressedVisualEffects()),
599 overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
600 overrides.getCharSequence(OVERRIDE_IMP_EXP,
601 outRanking.getImportanceExplanation()),
602 overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
603 overrides.containsKey(OVERRIDE_CHANNEL)
604 ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL)
605 : outRanking.getChannel(),
606 overrides.containsKey(OVERRIDE_PEOPLE)
607 ? overrides.getStringArrayList(OVERRIDE_PEOPLE)
608 : currentAdditionalPeople,
609 overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
610 ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
611 : currentSnooze,
612 overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
613 overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
614 overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
615 overrides.getLong(OVERRIDE_LAST_ALERTED,
616 outRanking.getLastAudiblyAlertedMillis()),
617 overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
618 overrides.containsKey(OVERRIDE_SMART_ACTIONS)
619 ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
620 : currentActions,
621 overrides.containsKey(OVERRIDE_SMART_REPLIES)
622 ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
623 : currentReplies,
624 overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()));
625 }
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900626 return true;
627 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700628 }
Tony Mak628cb932018-06-19 18:30:41 +0100629
Gustav Sennton1463d832018-11-06 16:12:48 +0000630 private Notification.Action createContextualAction(String title) {
Tony Mak628cb932018-06-19 18:30:41 +0100631 return new Notification.Action.Builder(
632 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
Gustav Sennton1463d832018-11-06 16:12:48 +0000633 title,
634 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
Gustav Sennton005d7a02019-01-04 13:41:32 +0000635 .setContextual(true)
Gustav Sennton1463d832018-11-06 16:12:48 +0000636 .build();
637 }
638
639 private Notification.Action createAction(String title) {
640 return new Notification.Action.Builder(
641 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
642 title,
Tony Mak628cb932018-06-19 18:30:41 +0100643 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
644 }
Maurice Lam132710e2017-03-03 19:13:42 -0800645}