blob: 6e0ddbf0cc4631d045c59aad149a567471445ce4 [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;
Rohan Shah20790b82018-07-02 17:21:04 -070069import com.android.systemui.statusbar.NotificationTestHelper;
Ned Burnsf81c4c42019-01-07 14:10:43 -050070import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
Rohan Shah20790b82018-07-02 17:21:04 -070071import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Selim Cinek608a57a2017-04-28 16:50:41 -070072import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk297c04e2018-08-23 17:16:59 -040073import com.android.systemui.statusbar.phone.ShadeController;
Maurice Lam132710e2017-03-03 19:13:42 -080074
75import org.junit.Before;
76import org.junit.Test;
77import org.junit.runner.RunWith;
Julia Reynoldsfc640012018-02-21 12:25:27 -050078import org.mockito.Mock;
79import org.mockito.MockitoAnnotations;
Maurice Lam132710e2017-03-03 19:13:42 -080080
Dieter Hsu36e1ebc2018-06-06 15:41:46 +080081import java.util.ArrayList;
Gustav Sennton1463d832018-11-06 16:12:48 +000082import java.util.Collections;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040083import java.util.HashMap;
Gustav Sennton1463d832018-11-06 16:12:48 +000084import java.util.List;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -040085import java.util.Map;
86
87import androidx.test.filters.SmallTest;
Dieter Hsu36e1ebc2018-06-06 15:41:46 +080088
Maurice Lam132710e2017-03-03 19:13:42 -080089@SmallTest
Jason Monk6dceace2018-05-15 20:24:07 -040090@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050091@RunWithLooper
Maurice Lam132710e2017-03-03 19:13:42 -080092public class NotificationDataTest extends SysuiTestCase {
93
94 private static final int UID_NORMAL = 123;
95 private static final int UID_ALLOW_DURING_SETUP = 456;
Tony Mak628cb932018-06-19 18:30:41 +010096 private static final NotificationChannel NOTIFICATION_CHANNEL =
97 new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
Maurice Lam132710e2017-03-03 19:13:42 -080098
99 private final StatusBarNotification mMockStatusBarNotification =
100 mock(StatusBarNotification.class);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500101 @Mock
102 ForegroundServiceController mFsc;
103 @Mock
Jason Monk297c04e2018-08-23 17:16:59 -0400104 NotificationData.KeyguardEnvironment mEnvironment;
Maurice Lam132710e2017-03-03 19:13:42 -0800105
106 private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500107 private TestableNotificationData mNotificationData;
Selim Cinek608a57a2017-04-28 16:50:41 -0700108 private ExpandableNotificationRow mRow;
Maurice Lam132710e2017-03-03 19:13:42 -0800109
110 @Before
111 public void setUp() throws Exception {
Jason Monka716bac2018-12-05 15:48:21 -0500112 com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
Julia Reynoldsfc640012018-02-21 12:25:27 -0500113 MockitoAnnotations.initMocks(this);
Maurice Lam132710e2017-03-03 19:13:42 -0800114 when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500115 when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
Maurice Lam132710e2017-03-03 19:13:42 -0800116
117 when(mMockPackageManager.checkUidPermission(
118 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
119 eq(UID_NORMAL)))
120 .thenReturn(PackageManager.PERMISSION_DENIED);
121 when(mMockPackageManager.checkUidPermission(
122 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
123 eq(UID_ALLOW_DURING_SETUP)))
124 .thenReturn(PackageManager.PERMISSION_GRANTED);
Selim Cinek608a57a2017-04-28 16:50:41 -0700125
Julia Reynoldsfc640012018-02-21 12:25:27 -0500126 mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
Jason Monk297c04e2018-08-23 17:16:59 -0400127 mDependency.injectTestDependency(NotificationGroupManager.class,
128 new NotificationGroupManager());
129 mDependency.injectMockDependency(ShadeController.class);
130 mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500131 when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
132 when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
Jason Monk297c04e2018-08-23 17:16:59 -0400133 mNotificationData = new TestableNotificationData();
Selim Cinek608a57a2017-04-28 16:50:41 -0700134 mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
135 mRow = new NotificationTestHelper(getContext()).createRow();
Tony Mak7d4b3a52018-11-27 17:29:36 +0000136 Dependency.get(InitController.class).executePostInitTasks();
Maurice Lam132710e2017-03-03 19:13:42 -0800137 }
138
139 @Test
Selim Cinek608a57a2017-04-28 16:50:41 -0700140 public void testChannelSetWhenAdded() {
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400141 Bundle override = new Bundle();
142 override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
143 mNotificationData.rankingOverrides.put(mRow.getEntry().key, override);
Selim Cinek608a57a2017-04-28 16:50:41 -0700144 mNotificationData.add(mRow.getEntry());
Tony Mak628cb932018-06-19 18:30:41 +0100145 assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
Selim Cinek608a57a2017-04-28 16:50:41 -0700146 }
147
Julia Reynoldsfc640012018-02-21 12:25:27 -0500148 @Test
149 public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
150 mNotificationData.add(mRow.getEntry());
151 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
152 mNotificationData.add(row2.getEntry());
153 ExpandableNotificationRow diffPkg =
Yohei Yukawa72769462019-01-20 09:28:08 -0800154 new NotificationTestHelper(getContext()).createRow("pkg", 4000,
155 Process.myUserHandle());
Julia Reynoldsfc640012018-02-21 12:25:27 -0500156 mNotificationData.add(diffPkg.getEntry());
157
158 ArraySet<Integer> expectedOps = new ArraySet<>();
159 expectedOps.add(OP_CAMERA);
160 expectedOps.add(OP_ACCEPT_HANDOVER);
161
162 for (int op : expectedOps) {
163 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400164 NotificationTestHelper.PKG, mRow.getEntry().key, true);
165 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
166 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500167 }
168 for (int op : expectedOps) {
169 assertTrue(mRow.getEntry().key + " doesn't have op " + op,
170 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
171 assertTrue(row2.getEntry().key + " doesn't have op " + op,
172 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
173 assertFalse(diffPkg.getEntry().key + " has op " + op,
174 mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
175 }
176 }
177
178 @Test
179 public void testAppOpsRemoval() throws Exception {
180 mNotificationData.add(mRow.getEntry());
181 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
182 mNotificationData.add(row2.getEntry());
183
184 ArraySet<Integer> expectedOps = new ArraySet<>();
185 expectedOps.add(OP_CAMERA);
186 expectedOps.add(OP_ACCEPT_HANDOVER);
187
188 for (int op : expectedOps) {
189 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400190 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500191 }
192
193 expectedOps.remove(OP_ACCEPT_HANDOVER);
194 mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400195 NotificationTestHelper.PKG, row2.getEntry().key, false);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500196
197 assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
198 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
199 assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
200 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
201 assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
202 mNotificationData.get(mRow.getEntry().key)
203 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
204 assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
205 mNotificationData.get(row2.getEntry().key)
206 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
207 }
208
209 @Test
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800210 public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
211 throws Exception {
212 mNotificationData.add(mRow.getEntry());
213 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
214 mNotificationData.add(row2.getEntry());
215
216 when(mEnvironment.isNotificationForCurrentProfiles(
217 mRow.getEntry().notification)).thenReturn(false);
218 when(mEnvironment.isNotificationForCurrentProfiles(
219 row2.getEntry().notification)).thenReturn(true);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500220 ArrayList<NotificationEntry> result =
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800221 mNotificationData.getNotificationsForCurrentUser();
222
Jason Monk297c04e2018-08-23 17:16:59 -0400223 assertEquals(result.size(), 1);
224 junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800225 }
226
227 @Test
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400228 public void testIsExemptFromDndVisualSuppression_foreground() {
229 initStatusBarNotification(false);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500230
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400231 Notification n = mMockStatusBarNotification.getNotification();
232 n.flags = Notification.FLAG_FOREGROUND_SERVICE;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500233 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500234 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400235 Bundle override = new Bundle();
236 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
237 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400238
Gus Prevasec9e1f02018-12-18 15:28:12 -0500239 assertTrue(entry.isExemptFromDndVisualSuppression());
240 assertFalse(entry.shouldSuppressAmbient());
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400241 }
242
243 @Test
244 public void testIsExemptFromDndVisualSuppression_media() {
245 initStatusBarNotification(false);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400246 Notification n = mMockStatusBarNotification.getNotification();
247 Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
248 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
249 n = nb.build();
250 when(mMockStatusBarNotification.getNotification()).thenReturn(n);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500251 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500252 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400253 Bundle override = new Bundle();
254 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
255 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400256
Gus Prevasec9e1f02018-12-18 15:28:12 -0500257 assertTrue(entry.isExemptFromDndVisualSuppression());
258 assertFalse(entry.shouldSuppressAmbient());
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400259 }
260
261 @Test
262 public void testIsExemptFromDndVisualSuppression_system() {
263 initStatusBarNotification(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500264 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400265 entry.mIsSystemNotification = true;
Gus Prevasec9e1f02018-12-18 15:28:12 -0500266 mNotificationData.add(entry);
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400267 Bundle override = new Bundle();
268 override.putInt(OVERRIDE_VIS_EFFECTS, 255);
269 mNotificationData.rankingOverrides.put(entry.key, override);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400270
Gus Prevasec9e1f02018-12-18 15:28:12 -0500271 assertTrue(entry.isExemptFromDndVisualSuppression());
272 assertFalse(entry.shouldSuppressAmbient());
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400273 }
274
Julia Reynolds25926af2018-05-01 17:05:33 -0400275 @Test
276 public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
277 initStatusBarNotification(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500278 NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
Julia Reynolds25926af2018-05-01 17:05:33 -0400279 entry.mIsSystemNotification = true;
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400280 Bundle override = new Bundle();
281 override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
282 mNotificationData.rankingOverrides.put(entry.key, override);
Gus Prevasec9e1f02018-12-18 15:28:12 -0500283 mNotificationData.add(entry);
284
Julia Reynolds25926af2018-05-01 17:05:33 -0400285 when(mMockStatusBarNotification.getNotification()).thenReturn(
286 new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build());
287
Gus Prevasec9e1f02018-12-18 15:28:12 -0500288 assertFalse(entry.isExemptFromDndVisualSuppression());
289 assertTrue(entry.shouldSuppressAmbient());
Julia Reynolds25926af2018-05-01 17:05:33 -0400290
291 when(mMockStatusBarNotification.getNotification()).thenReturn(
292 new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build());
293
Gus Prevasec9e1f02018-12-18 15:28:12 -0500294 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400295
296 when(mMockStatusBarNotification.getNotification()).thenReturn(
297 new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build());
298
Gus Prevasec9e1f02018-12-18 15:28:12 -0500299 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400300
301 when(mMockStatusBarNotification.getNotification()).thenReturn(
302 new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build());
303
Gus Prevasec9e1f02018-12-18 15:28:12 -0500304 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400305
306 when(mMockStatusBarNotification.getNotification()).thenReturn(
307 new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build());
308
Gus Prevasec9e1f02018-12-18 15:28:12 -0500309 assertFalse(entry.isExemptFromDndVisualSuppression());
Julia Reynolds25926af2018-05-01 17:05:33 -0400310 }
311
Tony Mak628cb932018-06-19 18:30:41 +0100312 @Test
313 public void testCreateNotificationDataEntry_RankingUpdate() {
314 Ranking ranking = mock(Ranking.class);
Gustav Sennton1463d832018-11-06 16:12:48 +0000315 initStatusBarNotification(false);
Tony Mak628cb932018-06-19 18:30:41 +0100316
Gustav Sennton1463d832018-11-06 16:12:48 +0000317 List<Notification.Action> appGeneratedSmartActions =
318 Collections.singletonList(createContextualAction("appGeneratedAction"));
319 mMockStatusBarNotification.getNotification().actions =
320 appGeneratedSmartActions.toArray(new Notification.Action[0]);
321
322 List<Notification.Action> systemGeneratedSmartActions =
323 Collections.singletonList(createAction("systemGeneratedAction"));
324 when(ranking.getSmartActions()).thenReturn(systemGeneratedSmartActions);
Tony Mak628cb932018-06-19 18:30:41 +0100325
326 when(ranking.getChannel()).thenReturn(NOTIFICATION_CHANNEL);
327
328 when(ranking.getUserSentiment()).thenReturn(Ranking.USER_SENTIMENT_NEGATIVE);
329
330 SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
331 ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
332 snoozeCriterions.add(snoozeCriterion);
333 when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
334
Ned Burnsf81c4c42019-01-07 14:10:43 -0500335 NotificationEntry entry =
336 new NotificationEntry(mMockStatusBarNotification, ranking);
Tony Mak628cb932018-06-19 18:30:41 +0100337
Gustav Sennton1463d832018-11-06 16:12:48 +0000338 assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
Tony Mak628cb932018-06-19 18:30:41 +0100339 assertEquals(NOTIFICATION_CHANNEL, entry.channel);
340 assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment);
341 assertEquals(snoozeCriterions, entry.snoozeCriteria);
342 }
343
Beverlye98937a2018-11-15 10:18:57 -0500344 @Test
345 public void notificationDataEntry_testIsLastMessageFromReply() {
346 Person.Builder person = new Person.Builder()
347 .setName("name")
348 .setKey("abc")
349 .setUri("uri")
350 .setBot(true);
351
352 // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
353 Bundle bundle = new Bundle();
354 bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
355 Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
356 "text", 0, person.build()).toBundle() };
357 bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
358
359 Notification notification = new Notification.Builder(mContext, "test")
360 .addExtras(bundle)
361 .build();
362 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
363 notification, mContext.getUser(), "", 0);
364
Ned Burnsf81c4c42019-01-07 14:10:43 -0500365 NotificationEntry entry = new NotificationEntry(sbn);
Beverlye98937a2018-11-15 10:18:57 -0500366 entry.setHasSentReply();
367
368 assertTrue(entry.isLastMessageFromReply());
369 }
370
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500371 @Test
372 public void personHighPriority() {
373 Person person = new Person.Builder()
374 .setName("name")
375 .setKey("abc")
376 .setUri("uri")
377 .setBot(true)
378 .build();
379
380 Notification notification = new Notification.Builder(mContext, "test")
381 .addPerson(person)
382 .build();
383
384 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
385 notification, mContext.getUser(), "", 0);
386
387 assertTrue(mNotificationData.isHighPriority(sbn));
388 }
389
390 @Test
391 public void messagingStyleHighPriority() {
392
393 Notification notification = new Notification.Builder(mContext, "test")
394 .setStyle(new Notification.MessagingStyle(""))
395 .build();
396
397 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
398 notification, mContext.getUser(), "", 0);
399
400 assertTrue(mNotificationData.isHighPriority(sbn));
401 }
402
403 @Test
404 public void minForegroundNotHighPriority() {
405 Notification notification = mock(Notification.class);
406 when(notification.isForegroundService()).thenReturn(true);
407
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500408 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
409 notification, mContext.getUser(), "", 0);
410
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400411 Bundle override = new Bundle();
412 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
413 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
414
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500415 assertFalse(mNotificationData.isHighPriority(sbn));
416 }
417
418 @Test
419 public void lowForegroundHighPriority() {
420 Notification notification = mock(Notification.class);
421 when(notification.isForegroundService()).thenReturn(true);
422
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400423 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
424 notification, mContext.getUser(), "", 0);
425
426 Bundle override = new Bundle();
427 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
428 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
429
430 assertTrue(mNotificationData.isHighPriority(sbn));
431 }
432
433 @Test
434 public void userChangeTrumpsHighPriorityCharacteristics() {
435 Person person = new Person.Builder()
436 .setName("name")
437 .setKey("abc")
438 .setUri("uri")
439 .setBot(true)
440 .build();
441
442 Notification notification = new Notification.Builder(mContext, "test")
443 .addPerson(person)
444 .setStyle(new Notification.MessagingStyle(""))
445 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
446 .build();
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500447
448 StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
449 notification, mContext.getUser(), "", 0);
450
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400451 NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
452 channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
453
454 Bundle override = new Bundle();
455 override.putParcelable(OVERRIDE_CHANNEL, channel);
456 mNotificationData.rankingOverrides.put(sbn.getKey(), override);
457
458 assertFalse(mNotificationData.isHighPriority(sbn));
459 }
460
461 @Test
462 public void testSort_highPriorityTrumpsNMSRank() {
463 // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
464 // front
465 Notification aN = new Notification.Builder(mContext, "test")
466 .setStyle(new Notification.MessagingStyle(""))
467 .build();
468 StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
469 aN, mContext.getUser(), "", 0);
470 NotificationEntry a = new NotificationEntry(aSbn);
471 a.setRow(mock(ExpandableNotificationRow.class));
472 a.setIsHighPriority(false);
473
474 Bundle override = new Bundle();
475 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
476 override.putInt(OVERRIDE_RANK, 1);
477 mNotificationData.rankingOverrides.put(a.key, override);
478
479 Notification bN = new Notification.Builder(mContext, "test")
480 .setStyle(new Notification.MessagingStyle(""))
481 .build();
482 StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
483 bN, mContext.getUser(), "", 0);
484 NotificationEntry b = new NotificationEntry(bSbn);
485 b.setIsHighPriority(true);
486 b.setRow(mock(ExpandableNotificationRow.class));
487
488 Bundle bOverride = new Bundle();
489 bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
490 bOverride.putInt(OVERRIDE_RANK, 2);
491 mNotificationData.rankingOverrides.put(b.key, bOverride);
492
493 assertEquals(1, mNotificationData.mRankingComparator.compare(a, b));
494 }
495
496 @Test
497 public void testSort_samePriorityUsesNMSRank() {
498 // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
499 // front
500 Notification aN = new Notification.Builder(mContext, "test")
501 .setStyle(new Notification.MessagingStyle(""))
502 .build();
503 StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
504 aN, mContext.getUser(), "", 0);
505 NotificationEntry a = new NotificationEntry(aSbn);
506 a.setRow(mock(ExpandableNotificationRow.class));
507 a.setIsHighPriority(false);
508
509 Bundle override = new Bundle();
510 override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
511 override.putInt(OVERRIDE_RANK, 1);
512 mNotificationData.rankingOverrides.put(a.key, override);
513
514 Notification bN = new Notification.Builder(mContext, "test")
515 .setStyle(new Notification.MessagingStyle(""))
516 .build();
517 StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
518 bN, mContext.getUser(), "", 0);
519 NotificationEntry b = new NotificationEntry(bSbn);
520 b.setRow(mock(ExpandableNotificationRow.class));
521 b.setIsHighPriority(false);
522
523 Bundle bOverride = new Bundle();
524 bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
525 bOverride.putInt(OVERRIDE_RANK, 2);
526 mNotificationData.rankingOverrides.put(b.key, bOverride);
527
528 assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500529 }
530
Maurice Lam132710e2017-03-03 19:13:42 -0800531 private void initStatusBarNotification(boolean allowDuringSetup) {
532 Bundle bundle = new Bundle();
533 bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
534 Notification notification = new Notification.Builder(mContext, "test")
535 .addExtras(bundle)
536 .build();
537 when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
538 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700539
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500540 public static class TestableNotificationData extends NotificationData {
Jason Monk297c04e2018-08-23 17:16:59 -0400541 public TestableNotificationData() {
542 super();
Selim Cinek608a57a2017-04-28 16:50:41 -0700543 }
544
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500545 public static final String OVERRIDE_RANK = "r";
546 public static final String OVERRIDE_DND = "dnd";
547 public static final String OVERRIDE_VIS_OVERRIDE = "vo";
548 public static final String OVERRIDE_VIS_EFFECTS = "ve";
549 public static final String OVERRIDE_IMPORTANCE = "i";
550 public static final String OVERRIDE_IMP_EXP = "ie";
551 public static final String OVERRIDE_GROUP = "g";
552 public static final String OVERRIDE_CHANNEL = "c";
553 public static final String OVERRIDE_PEOPLE = "p";
554 public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
555 public static final String OVERRIDE_BADGE = "b";
556 public static final String OVERRIDE_USER_SENTIMENT = "us";
557 public static final String OVERRIDE_HIDDEN = "h";
558 public static final String OVERRIDE_LAST_ALERTED = "la";
559 public static final String OVERRIDE_NOISY = "n";
560 public static final String OVERRIDE_SMART_ACTIONS = "sa";
561 public static final String OVERRIDE_SMART_REPLIES = "sr";
562 public static final String OVERRIDE_BUBBLE = "cb";
563
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400564 public Map<String, Bundle> rankingOverrides = new HashMap<>();
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500565
Selim Cinek608a57a2017-04-28 16:50:41 -0700566 @Override
Tony Mak628cb932018-06-19 18:30:41 +0100567 protected boolean getRanking(String key, Ranking outRanking) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900568 super.getRanking(key, outRanking);
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500569
570 ArrayList<String> currentAdditionalPeople = new ArrayList<>();
571 if (outRanking.getAdditionalPeople() != null) {
572 currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
Beverly5a20a5e2018-03-06 15:02:44 -0500573 }
Julia Reynoldsefcd8bd2019-02-06 08:56:15 -0500574
575 ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
576 if (outRanking.getSnoozeCriteria() != null) {
577 currentSnooze.addAll(outRanking.getSnoozeCriteria());
578 }
579
580 ArrayList<Notification.Action> currentActions = new ArrayList<>();
581 if (outRanking.getSmartActions() != null) {
582 currentActions.addAll(outRanking.getSmartActions());
583 }
584
585 ArrayList<CharSequence> currentReplies = new ArrayList<>();
586 if (outRanking.getSmartReplies() != null) {
587 currentReplies.addAll(outRanking.getSmartReplies());
588 }
589
Julia Reynolds2b88ecd2019-05-29 18:09:41 -0400590 if (rankingOverrides.get(key) != null) {
591 Bundle overrides = rankingOverrides.get(key);
592 outRanking.populate(key,
593 overrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
594 overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()),
595 overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()),
596 overrides.getInt(OVERRIDE_VIS_EFFECTS,
597 outRanking.getSuppressedVisualEffects()),
598 overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
599 overrides.getCharSequence(OVERRIDE_IMP_EXP,
600 outRanking.getImportanceExplanation()),
601 overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
602 overrides.containsKey(OVERRIDE_CHANNEL)
603 ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL)
604 : outRanking.getChannel(),
605 overrides.containsKey(OVERRIDE_PEOPLE)
606 ? overrides.getStringArrayList(OVERRIDE_PEOPLE)
607 : currentAdditionalPeople,
608 overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
609 ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
610 : currentSnooze,
611 overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
612 overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
613 overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
614 overrides.getLong(OVERRIDE_LAST_ALERTED,
615 outRanking.getLastAudiblyAlertedMillis()),
616 overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
617 overrides.containsKey(OVERRIDE_SMART_ACTIONS)
618 ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
619 : currentActions,
620 overrides.containsKey(OVERRIDE_SMART_REPLIES)
621 ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
622 : currentReplies,
623 overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()));
624 }
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900625 return true;
626 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700627 }
Tony Mak628cb932018-06-19 18:30:41 +0100628
Gustav Sennton1463d832018-11-06 16:12:48 +0000629 private Notification.Action createContextualAction(String title) {
Tony Mak628cb932018-06-19 18:30:41 +0100630 return new Notification.Action.Builder(
631 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
Gustav Sennton1463d832018-11-06 16:12:48 +0000632 title,
633 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
Gustav Sennton005d7a02019-01-04 13:41:32 +0000634 .setContextual(true)
Gustav Sennton1463d832018-11-06 16:12:48 +0000635 .build();
636 }
637
638 private Notification.Action createAction(String title) {
639 return new Notification.Action.Builder(
640 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
641 title,
Tony Mak628cb932018-06-19 18:30:41 +0100642 PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
643 }
Maurice Lam132710e2017-03-03 19:13:42 -0800644}