1 /* 2 * Copyright (C) 2016 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 package com.android.server.notification; 17 18 import org.junit.Before; 19 import org.junit.Test; 20 import org.junit.runner.RunWith; 21 import org.mockito.ArgumentCaptor; 22 import org.mockito.Mock; 23 import org.mockito.MockitoAnnotations; 24 25 import android.app.AlarmManager; 26 import android.app.Notification; 27 import android.app.NotificationChannel; 28 import android.app.NotificationManager; 29 import android.app.PendingIntent; 30 import android.os.SystemClock; 31 import android.os.UserHandle; 32 import android.service.notification.StatusBarNotification; 33 import android.support.test.runner.AndroidJUnit4; 34 import android.test.suitebuilder.annotation.SmallTest; 35 36 import static junit.framework.Assert.assertEquals; 37 import static junit.framework.Assert.assertFalse; 38 import static junit.framework.Assert.assertTrue; 39 import static org.mockito.Matchers.any; 40 import static org.mockito.Matchers.anyInt; 41 import static org.mockito.Matchers.anyLong; 42 import static org.mockito.Matchers.eq; 43 import static org.mockito.Mockito.never; 44 import static org.mockito.Mockito.times; 45 import static org.mockito.Mockito.verify; 46 import static org.mockito.Mockito.when; 47 48 import com.android.server.UiServiceTestCase; 49 50 51 @SmallTest 52 @RunWith(AndroidJUnit4.class) 53 public class SnoozeHelperTest extends UiServiceTestCase { 54 private static final String TEST_CHANNEL_ID = "test_channel_id"; 55 56 @Mock SnoozeHelper.Callback mCallback; 57 @Mock AlarmManager mAm; 58 @Mock ManagedServices.UserProfiles mUserProfiles; 59 60 private SnoozeHelper mSnoozeHelper; 61 62 @Before 63 public void setUp() { 64 MockitoAnnotations.initMocks(this); 65 66 mSnoozeHelper = new SnoozeHelper(getContext(), mCallback, mUserProfiles); 67 mSnoozeHelper.setAlarmManager(mAm); 68 } 69 70 @Test 71 public void testSnoozeForTime() throws Exception { 72 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 73 mSnoozeHelper.snooze(r, 1000); 74 ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class); 75 verify(mAm, times(1)).setExactAndAllowWhileIdle( 76 anyInt(), captor.capture(), any(PendingIntent.class)); 77 long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime(); 78 assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 25); 79 assertTrue(mSnoozeHelper.isSnoozed( 80 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 81 } 82 83 @Test 84 public void testSnooze() throws Exception { 85 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 86 mSnoozeHelper.snooze(r); 87 verify(mAm, never()).setExactAndAllowWhileIdle( 88 anyInt(), anyLong(), any(PendingIntent.class)); 89 assertTrue(mSnoozeHelper.isSnoozed( 90 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 91 } 92 93 @Test 94 public void testCancelByApp() throws Exception { 95 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 96 NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); 97 mSnoozeHelper.snooze(r, 1000); 98 mSnoozeHelper.snooze(r2 , 1000); 99 assertTrue(mSnoozeHelper.isSnoozed( 100 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 101 assertTrue(mSnoozeHelper.isSnoozed( 102 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 103 104 mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, r.sbn.getPackageName(), "one", 1); 105 // 2 = one for each snooze, above, zero for the cancel. 106 verify(mAm, times(2)).cancel(any(PendingIntent.class)); 107 assertTrue(mSnoozeHelper.isSnoozed( 108 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 109 assertTrue(mSnoozeHelper.isSnoozed( 110 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 111 } 112 113 @Test 114 public void testCancelAllForUser() throws Exception { 115 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 116 NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); 117 NotificationRecord r3 = getNotificationRecord("pkg", 3, "three", UserHandle.ALL); 118 mSnoozeHelper.snooze(r, 1000); 119 mSnoozeHelper.snooze(r2, 1000); 120 mSnoozeHelper.snooze(r3, 1000); 121 assertTrue(mSnoozeHelper.isSnoozed( 122 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 123 assertTrue(mSnoozeHelper.isSnoozed( 124 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 125 assertTrue(mSnoozeHelper.isSnoozed( 126 UserHandle.USER_ALL, r3.sbn.getPackageName(), r3.getKey())); 127 128 mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, false); 129 // 3 = once for each snooze above (3), only. 130 verify(mAm, times(3)).cancel(any(PendingIntent.class)); 131 assertTrue(mSnoozeHelper.isSnoozed( 132 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 133 assertTrue(mSnoozeHelper.isSnoozed( 134 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 135 assertTrue(mSnoozeHelper.isSnoozed( 136 UserHandle.USER_ALL, r3.sbn.getPackageName(), r3.getKey())); 137 } 138 139 @Test 140 public void testCancelAllByApp() throws Exception { 141 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 142 NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); 143 NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM); 144 mSnoozeHelper.snooze(r, 1000); 145 mSnoozeHelper.snooze(r2, 1000); 146 mSnoozeHelper.snooze(r3, 1000); 147 assertTrue(mSnoozeHelper.isSnoozed( 148 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 149 assertTrue(mSnoozeHelper.isSnoozed( 150 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 151 assertTrue(mSnoozeHelper.isSnoozed( 152 UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey())); 153 154 mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, "pkg2"); 155 // 3 = once for each snooze above (3), only. 156 verify(mAm, times(3)).cancel(any(PendingIntent.class)); 157 assertTrue(mSnoozeHelper.isSnoozed( 158 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 159 assertTrue(mSnoozeHelper.isSnoozed( 160 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 161 assertTrue(mSnoozeHelper.isSnoozed( 162 UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey())); 163 } 164 165 @Test 166 public void testCancelDoesNotUnsnooze() throws Exception { 167 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 168 mSnoozeHelper.snooze(r, 1000); 169 assertTrue(mSnoozeHelper.isSnoozed( 170 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 171 172 mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, r.sbn.getPackageName(), "one", 1); 173 174 assertTrue(mSnoozeHelper.isSnoozed( 175 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 176 } 177 178 @Test 179 public void testCancelDoesNotRepost() throws Exception { 180 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 181 NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); 182 mSnoozeHelper.snooze(r, 1000); 183 mSnoozeHelper.snooze(r2 , 1000); 184 assertTrue(mSnoozeHelper.isSnoozed( 185 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); 186 assertTrue(mSnoozeHelper.isSnoozed( 187 UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); 188 189 mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, r.sbn.getPackageName(), "one", 1); 190 191 mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); 192 verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r); 193 } 194 195 @Test 196 public void testRepost() throws Exception { 197 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 198 mSnoozeHelper.snooze(r, 1000); 199 NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL); 200 mSnoozeHelper.snooze(r2, 1000); 201 mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); 202 verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); 203 } 204 205 @Test 206 public void testRepost_noUser() throws Exception { 207 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 208 mSnoozeHelper.snooze(r, 1000); 209 NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL); 210 mSnoozeHelper.snooze(r2, 1000); 211 mSnoozeHelper.repost(r.getKey()); 212 verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); 213 } 214 215 @Test 216 public void testUpdate() throws Exception { 217 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 218 mSnoozeHelper.snooze(r , 1000); 219 r.getNotification().category = "NEW CATEGORY"; 220 221 mSnoozeHelper.update(UserHandle.USER_SYSTEM, r); 222 verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class)); 223 224 mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); 225 verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); 226 } 227 228 @Test 229 public void testGetSnoozedByUser() throws Exception { 230 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 231 NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); 232 NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM); 233 NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT); 234 mSnoozeHelper.snooze(r, 1000); 235 mSnoozeHelper.snooze(r2, 1000); 236 mSnoozeHelper.snooze(r3, 1000); 237 mSnoozeHelper.snooze(r4, 1000); 238 when(mUserProfiles.getCurrentProfileIds()).thenReturn( 239 new int[] {UserHandle.USER_SYSTEM}); 240 assertEquals(3, mSnoozeHelper.getSnoozed().size()); 241 when(mUserProfiles.getCurrentProfileIds()).thenReturn( 242 new int[] {UserHandle.USER_CURRENT}); 243 assertEquals(1, mSnoozeHelper.getSnoozed().size()); 244 } 245 246 @Test 247 public void testGetSnoozedByUser_managedProfiles() throws Exception { 248 when(mUserProfiles.getCurrentProfileIds()).thenReturn( 249 new int[] {UserHandle.USER_SYSTEM, UserHandle.USER_CURRENT}); 250 NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); 251 NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); 252 NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM); 253 NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT); 254 mSnoozeHelper.snooze(r, 1000); 255 mSnoozeHelper.snooze(r2, 1000); 256 mSnoozeHelper.snooze(r3, 1000); 257 mSnoozeHelper.snooze(r4, 1000); 258 assertEquals(4, mSnoozeHelper.getSnoozed().size()); 259 } 260 261 @Test 262 public void repostGroupSummary_onlyFellowGroupChildren() throws Exception { 263 NotificationRecord r = getNotificationRecord( 264 "pkg", 1, "one", UserHandle.SYSTEM, "group1", false); 265 NotificationRecord r2 = getNotificationRecord( 266 "pkg", 2, "two", UserHandle.SYSTEM, "group1", false); 267 mSnoozeHelper.snooze(r, 1000); 268 mSnoozeHelper.snooze(r2, 1000); 269 mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, "group1"); 270 271 verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r); 272 } 273 274 @Test 275 public void repostGroupSummary_repostsSummary() throws Exception { 276 when(mUserProfiles.getCurrentProfileIds()).thenReturn( 277 new int[] {UserHandle.USER_SYSTEM}); 278 NotificationRecord r = getNotificationRecord( 279 "pkg", 1, "one", UserHandle.SYSTEM, "group1", true); 280 NotificationRecord r2 = getNotificationRecord( 281 "pkg", 2, "two", UserHandle.SYSTEM, "group1", false); 282 mSnoozeHelper.snooze(r, 1000); 283 mSnoozeHelper.snooze(r2, 1000); 284 assertEquals(2, mSnoozeHelper.getSnoozed().size()); 285 assertEquals(2, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); 286 287 mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); 288 289 verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); 290 verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r2); 291 292 assertEquals(1, mSnoozeHelper.getSnoozed().size()); 293 assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); 294 } 295 296 private NotificationRecord getNotificationRecord(String pkg, int id, String tag, 297 UserHandle user, String groupKey, boolean groupSummary) { 298 Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID) 299 .setContentTitle("A") 300 .setGroup("G") 301 .setSortKey("A") 302 .setWhen(1205) 303 .setGroup(groupKey) 304 .setGroupSummary(groupSummary) 305 .build(); 306 final NotificationChannel notificationChannel = new NotificationChannel( 307 TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW); 308 return new NotificationRecord(getContext(), new StatusBarNotification( 309 pkg, pkg, id, tag, 0, 0, n, user, null, 310 System.currentTimeMillis()), notificationChannel); 311 } 312 313 private NotificationRecord getNotificationRecord(String pkg, int id, String tag, 314 UserHandle user) { 315 return getNotificationRecord(pkg, id, tag, user, null, false); 316 } 317 } 318