NotificationDataTest.java revision 25926af53740667b215457bbde0bda679b400078
1/* 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 14 * limitations under the License. 15 */ 16 17package com.android.systemui.statusbar; 18 19import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER; 20import static android.app.AppOpsManager.OP_CAMERA; 21import 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; 26 27import static junit.framework.Assert.assertEquals; 28 29import static org.junit.Assert.assertFalse; 30import static org.junit.Assert.assertTrue; 31import static org.mockito.ArgumentMatchers.any; 32import static org.mockito.ArgumentMatchers.anyInt; 33import static org.mockito.ArgumentMatchers.anyString; 34import static org.mockito.Matchers.eq; 35import static org.mockito.Mockito.mock; 36import static org.mockito.Mockito.when; 37 38import android.Manifest; 39import android.app.Notification; 40import android.app.NotificationChannel; 41import android.content.pm.IPackageManager; 42import android.content.pm.PackageManager; 43import android.media.session.MediaSession; 44import android.os.Bundle; 45import android.service.notification.NotificationListenerService; 46import android.service.notification.StatusBarNotification; 47import android.support.test.annotation.UiThreadTest; 48import android.support.test.filters.SmallTest; 49import android.support.test.runner.AndroidJUnit4; 50import android.util.ArraySet; 51 52import com.android.systemui.ForegroundServiceController; 53import com.android.systemui.SysuiTestCase; 54import com.android.systemui.statusbar.phone.NotificationGroupManager; 55 56import org.junit.Assert; 57import org.junit.Before; 58import org.junit.Test; 59import org.junit.runner.RunWith; 60import org.mockito.Mock; 61import org.mockito.MockitoAnnotations; 62 63@SmallTest 64@RunWith(AndroidJUnit4.class) 65public class NotificationDataTest extends SysuiTestCase { 66 67 private static final int UID_NORMAL = 123; 68 private static final int UID_ALLOW_DURING_SETUP = 456; 69 private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey"; 70 private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt"; 71 72 private final StatusBarNotification mMockStatusBarNotification = 73 mock(StatusBarNotification.class); 74 @Mock 75 ForegroundServiceController mFsc; 76 @Mock 77 NotificationData.Environment mEnvironment; 78 79 private final IPackageManager mMockPackageManager = mock(IPackageManager.class); 80 private NotificationData mNotificationData; 81 private ExpandableNotificationRow mRow; 82 83 @Before 84 public void setUp() throws Exception { 85 MockitoAnnotations.initMocks(this); 86 when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL); 87 88 when(mMockPackageManager.checkUidPermission( 89 eq(Manifest.permission.NOTIFICATION_DURING_SETUP), 90 eq(UID_NORMAL))) 91 .thenReturn(PackageManager.PERMISSION_DENIED); 92 when(mMockPackageManager.checkUidPermission( 93 eq(Manifest.permission.NOTIFICATION_DURING_SETUP), 94 eq(UID_ALLOW_DURING_SETUP))) 95 .thenReturn(PackageManager.PERMISSION_GRANTED); 96 97 mDependency.injectTestDependency(ForegroundServiceController.class, mFsc); 98 when(mEnvironment.getGroupManager()).thenReturn(new NotificationGroupManager()); 99 when(mEnvironment.isDeviceProvisioned()).thenReturn(true); 100 when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); 101 mNotificationData = new TestableNotificationData(mEnvironment); 102 mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class)); 103 mRow = new NotificationTestHelper(getContext()).createRow(); 104 } 105 106 @Test 107 @UiThreadTest 108 public void testShowNotificationEvenIfUnprovisioned_FalseIfNoExtra() { 109 initStatusBarNotification(false); 110 when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP); 111 112 assertFalse( 113 NotificationData.showNotificationEvenIfUnprovisioned( 114 mMockPackageManager, 115 mMockStatusBarNotification)); 116 } 117 118 @Test 119 @UiThreadTest 120 public void testShowNotificationEvenIfUnprovisioned_FalseIfNoPermission() { 121 initStatusBarNotification(true); 122 123 assertFalse( 124 NotificationData.showNotificationEvenIfUnprovisioned( 125 mMockPackageManager, 126 mMockStatusBarNotification)); 127 } 128 129 @Test 130 @UiThreadTest 131 public void testShowNotificationEvenIfUnprovisioned_TrueIfHasPermissionAndExtra() { 132 initStatusBarNotification(true); 133 when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP); 134 135 assertTrue( 136 NotificationData.showNotificationEvenIfUnprovisioned( 137 mMockPackageManager, 138 mMockStatusBarNotification)); 139 } 140 141 @Test 142 public void testChannelSetWhenAdded() { 143 mNotificationData.add(mRow.getEntry()); 144 Assert.assertTrue(mRow.getEntry().channel != null); 145 } 146 147 148 149 @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 = 155 new NotificationTestHelper(getContext()).createRow("pkg", 4000); 156 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, 164 NotificationTestHelper.PKG, mRow.getEntry().key, true); 165 mNotificationData.updateAppOp(op, NotificationTestHelper.UID, 166 NotificationTestHelper.PKG, row2.getEntry().key, true); 167 } 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, 190 NotificationTestHelper.PKG, row2.getEntry().key, true); 191 } 192 193 expectedOps.remove(OP_ACCEPT_HANDOVER); 194 mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID, 195 NotificationTestHelper.PKG, row2.getEntry().key, false); 196 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 210 public void testSuppressSystemAlertNotification() { 211 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); 212 when(mFsc.isSystemAlertNotification(any())).thenReturn(true); 213 StatusBarNotification sbn = mRow.getEntry().notification; 214 Bundle bundle = new Bundle(); 215 bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {"something"}); 216 sbn.getNotification().extras = bundle; 217 218 assertTrue(mNotificationData.shouldFilterOut(mRow.getEntry())); 219 } 220 221 @Test 222 public void testDoNotSuppressSystemAlertNotification() { 223 StatusBarNotification sbn = mRow.getEntry().notification; 224 Bundle bundle = new Bundle(); 225 bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {"something"}); 226 sbn.getNotification().extras = bundle; 227 228 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true); 229 when(mFsc.isSystemAlertNotification(any())).thenReturn(true); 230 231 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry())); 232 233 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true); 234 when(mFsc.isSystemAlertNotification(any())).thenReturn(false); 235 236 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry())); 237 238 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); 239 when(mFsc.isSystemAlertNotification(any())).thenReturn(false); 240 241 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry())); 242 } 243 244 @Test 245 public void testDoNotSuppressMalformedSystemAlertNotification() { 246 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true); 247 248 // missing extra 249 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry())); 250 251 StatusBarNotification sbn = mRow.getEntry().notification; 252 Bundle bundle = new Bundle(); 253 bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {}); 254 sbn.getNotification().extras = bundle; 255 256 // extra missing values 257 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry())); 258 } 259 260 @Test 261 public void testShouldFilterHiddenNotifications() { 262 initStatusBarNotification(false); 263 // setup 264 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); 265 when(mFsc.isSystemAlertNotification(any())).thenReturn(false); 266 267 // test should filter out hidden notifications: 268 // hidden 269 when(mMockStatusBarNotification.getKey()).thenReturn(TEST_HIDDEN_NOTIFICATION_KEY); 270 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); 271 assertTrue(mNotificationData.shouldFilterOut(entry)); 272 273 // not hidden 274 when(mMockStatusBarNotification.getKey()).thenReturn("not hidden"); 275 entry = new NotificationData.Entry(mMockStatusBarNotification); 276 assertFalse(mNotificationData.shouldFilterOut(entry)); 277 } 278 279 @Test 280 public void testIsExemptFromDndVisualSuppression_foreground() { 281 initStatusBarNotification(false); 282 when(mMockStatusBarNotification.getKey()).thenReturn( 283 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); 284 Notification n = mMockStatusBarNotification.getNotification(); 285 n.flags = Notification.FLAG_FOREGROUND_SERVICE; 286 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); 287 288 assertTrue(mNotificationData.isExemptFromDndVisualSuppression(entry)); 289 assertFalse(mNotificationData.shouldSuppressAmbient(entry)); 290 } 291 292 @Test 293 public void testIsExemptFromDndVisualSuppression_media() { 294 initStatusBarNotification(false); 295 when(mMockStatusBarNotification.getKey()).thenReturn( 296 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); 297 Notification n = mMockStatusBarNotification.getNotification(); 298 Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n); 299 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 300 n = nb.build(); 301 when(mMockStatusBarNotification.getNotification()).thenReturn(n); 302 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); 303 304 assertTrue(mNotificationData.isExemptFromDndVisualSuppression(entry)); 305 assertFalse(mNotificationData.shouldSuppressAmbient(entry)); 306 } 307 308 @Test 309 public void testIsExemptFromDndVisualSuppression_system() { 310 initStatusBarNotification(false); 311 when(mMockStatusBarNotification.getKey()).thenReturn( 312 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); 313 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); 314 entry.mIsSystemNotification = true; 315 316 assertTrue(mNotificationData.isExemptFromDndVisualSuppression(entry)); 317 assertFalse(mNotificationData.shouldSuppressAmbient(entry)); 318 } 319 320 @Test 321 public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() { 322 initStatusBarNotification(false); 323 when(mMockStatusBarNotification.getKey()).thenReturn( 324 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); 325 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); 326 entry.mIsSystemNotification = true; 327 when(mMockStatusBarNotification.getNotification()).thenReturn( 328 new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build()); 329 330 assertFalse(mNotificationData.isExemptFromDndVisualSuppression(entry)); 331 assertTrue(mNotificationData.shouldSuppressAmbient(entry)); 332 333 when(mMockStatusBarNotification.getNotification()).thenReturn( 334 new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build()); 335 336 assertFalse(mNotificationData.isExemptFromDndVisualSuppression(entry)); 337 338 when(mMockStatusBarNotification.getNotification()).thenReturn( 339 new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build()); 340 341 assertFalse(mNotificationData.isExemptFromDndVisualSuppression(entry)); 342 343 when(mMockStatusBarNotification.getNotification()).thenReturn( 344 new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build()); 345 346 assertFalse(mNotificationData.isExemptFromDndVisualSuppression(entry)); 347 348 when(mMockStatusBarNotification.getNotification()).thenReturn( 349 new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build()); 350 351 assertFalse(mNotificationData.isExemptFromDndVisualSuppression(entry)); 352 } 353 354 private void initStatusBarNotification(boolean allowDuringSetup) { 355 Bundle bundle = new Bundle(); 356 bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); 357 Notification notification = new Notification.Builder(mContext, "test") 358 .addExtras(bundle) 359 .build(); 360 when(mMockStatusBarNotification.getNotification()).thenReturn(notification); 361 } 362 363 private class TestableNotificationData extends NotificationData { 364 public TestableNotificationData(Environment environment) { 365 super(environment); 366 } 367 368 @Override 369 public NotificationChannel getChannel(String key) { 370 return new NotificationChannel(null, null, 0); 371 } 372 373 @Override 374 protected boolean getRanking(String key, NotificationListenerService.Ranking outRanking) { 375 super.getRanking(key, outRanking); 376 if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) { 377 outRanking.populate(key, outRanking.getRank(), 378 outRanking.matchesInterruptionFilter(), 379 outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(), 380 outRanking.getImportance(), outRanking.getImportanceExplanation(), 381 outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, 382 outRanking.canShowBadge(), outRanking.getUserSentiment(), true); 383 } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) { 384 outRanking.populate(key, outRanking.getRank(), 385 outRanking.matchesInterruptionFilter(), 386 outRanking.getVisibilityOverride(), 255, 387 outRanking.getImportance(), outRanking.getImportanceExplanation(), 388 outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, 389 outRanking.canShowBadge(), outRanking.getUserSentiment(), true); 390 } else { 391 outRanking.populate(key, outRanking.getRank(), 392 outRanking.matchesInterruptionFilter(), 393 outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(), 394 outRanking.getImportance(), outRanking.getImportanceExplanation(), 395 outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, 396 outRanking.canShowBadge(), outRanking.getUserSentiment(), false); 397 } 398 return true; 399 } 400 } 401} 402