1 package com.android.server.notification; 2 3 import static org.junit.Assert.assertEquals; 4 import static org.junit.Assert.assertFalse; 5 import static org.junit.Assert.assertTrue; 6 import static org.mockito.Mockito.spy; 7 8 import android.content.Intent; 9 import android.net.Uri; 10 import android.service.notification.Condition; 11 import android.service.notification.ScheduleCalendar; 12 import android.service.notification.ZenModeConfig; 13 import android.support.test.filters.SmallTest; 14 import android.support.test.runner.AndroidJUnit4; 15 import android.testing.AndroidTestingRunner; 16 import android.testing.TestableLooper.RunWithLooper; 17 18 import com.android.server.UiServiceTestCase; 19 20 import org.junit.Before; 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.mockito.MockitoAnnotations; 24 25 import java.util.Calendar; 26 import java.util.GregorianCalendar; 27 28 @RunWith(AndroidTestingRunner.class) 29 @SmallTest 30 @RunWithLooper 31 public class ScheduleConditionProviderTest extends UiServiceTestCase { 32 33 ScheduleConditionProvider mService; 34 35 @Before 36 public void setUp() throws Exception { 37 MockitoAnnotations.initMocks(this); 38 39 Intent startIntent = 40 new Intent("com.android.server.notification.ScheduleConditionProvider"); 41 startIntent.setPackage("android"); 42 ScheduleConditionProvider service = new ScheduleConditionProvider(); 43 service.attach( 44 getContext(), 45 null, // ActivityThread not actually used in Service 46 ScheduleConditionProvider.class.getName(), 47 null, // token not needed when not talking with the activity manager 48 null, 49 null // mocked services don't talk with the activity manager 50 ); 51 service.onCreate(); 52 service.onBind(startIntent); 53 mService = spy(service); 54 } 55 56 @Test 57 public void testIsValidConditionId_incomplete() throws Exception { 58 Uri badConditionId = Uri.EMPTY; 59 assertFalse(mService.isValidConditionId(badConditionId)); 60 assertEquals(Condition.STATE_ERROR, 61 mService.evaluateSubscriptionLocked(badConditionId, null, 0, 1000).state); 62 } 63 64 @Test 65 public void testIsValidConditionId() throws Exception { 66 ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo(); 67 info.days = new int[] {1, 2, 4}; 68 info.startHour = 8; 69 info.startMinute = 56; 70 info.nextAlarm = 1000; 71 info.exitAtAlarm = true; 72 info.endHour = 12; 73 info.endMinute = 9; 74 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 75 assertTrue(mService.isValidConditionId(conditionId)); 76 } 77 78 @Test 79 public void testEvaluateSubscription_noAlarmExit_InSchedule() { 80 Calendar now = getNow(); 81 82 // Schedule - 1 hour long; starts now 83 ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo(); 84 info.days = new int[] {Calendar.FRIDAY}; 85 info.startHour = now.get(Calendar.HOUR_OF_DAY); 86 info.startMinute = now.get(Calendar.MINUTE); 87 info.nextAlarm = 0; 88 info.exitAtAlarm = false; 89 info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1; 90 info.endMinute = info.startMinute; 91 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 92 ScheduleCalendar cal = new ScheduleCalendar(); 93 cal.setSchedule(info); 94 assertTrue(cal.isInSchedule(now.getTimeInMillis())); 95 96 Condition condition = mService.evaluateSubscriptionLocked( 97 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000); 98 99 assertEquals(Condition.STATE_TRUE, condition.state); 100 } 101 102 @Test 103 public void testEvaluateSubscription_noAlarmExit_InScheduleSnoozed() { 104 Calendar now = getNow(); 105 106 // Schedule - 1 hour long; starts now 107 ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo(); 108 info.days = new int[] {Calendar.FRIDAY}; 109 info.startHour = now.get(Calendar.HOUR_OF_DAY); 110 info.startMinute = now.get(Calendar.MINUTE); 111 info.nextAlarm = 0; 112 info.exitAtAlarm = false; 113 info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1; 114 info.endMinute = info.startMinute; 115 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 116 ScheduleCalendar cal = new ScheduleCalendar(); 117 cal.setSchedule(info); 118 assertTrue(cal.isInSchedule(now.getTimeInMillis())); 119 120 mService.addSnoozed(conditionId); 121 122 Condition condition = mService.evaluateSubscriptionLocked( 123 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000); 124 125 assertEquals(Condition.STATE_FALSE, condition.state); 126 } 127 128 @Test 129 public void testEvaluateSubscription_noAlarmExit_beforeSchedule() { 130 Calendar now = new GregorianCalendar(); 131 now.set(Calendar.HOUR_OF_DAY, 14); 132 now.set(Calendar.MINUTE, 15); 133 now.set(Calendar.SECOND, 59); 134 now.set(Calendar.MILLISECOND, 0); 135 now.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); 136 137 // Schedule - 1 hour long; starts in 1 second 138 ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo(); 139 info.days = new int[] {Calendar.FRIDAY}; 140 info.startHour = now.get(Calendar.HOUR_OF_DAY); 141 info.startMinute = now.get(Calendar.MINUTE) + 1; 142 info.nextAlarm = 0; 143 info.exitAtAlarm = false; 144 info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1; 145 info.endMinute = info.startMinute; 146 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 147 ScheduleCalendar cal = new ScheduleCalendar(); 148 cal.setSchedule(info); 149 150 Condition condition = mService.evaluateSubscriptionLocked( 151 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000); 152 153 assertEquals(Condition.STATE_FALSE, condition.state); 154 } 155 156 @Test 157 public void testEvaluateSubscription_noAlarmExit_endSchedule() { 158 Calendar now = getNow(); 159 160 // Schedule - 1 hour long; ends now 161 ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo(); 162 info.days = new int[] {Calendar.FRIDAY}; 163 info.startHour = now.get(Calendar.HOUR_OF_DAY) - 1; 164 info.startMinute = now.get(Calendar.MINUTE); 165 info.nextAlarm = 0; 166 info.exitAtAlarm = false; 167 info.endHour = now.get(Calendar.HOUR_OF_DAY); 168 info.endMinute = now.get(Calendar.MINUTE); 169 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 170 ScheduleCalendar cal = new ScheduleCalendar(); 171 cal.setSchedule(info); 172 173 Condition condition = mService.evaluateSubscriptionLocked( 174 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000); 175 176 assertEquals(Condition.STATE_FALSE, condition.state); 177 } 178 179 @Test 180 public void testEvaluateSubscription_alarmSetBeforeInSchedule() { 181 Calendar now = getNow(); 182 183 // Schedule - 1 hour long; starts now, ends with alarm 184 ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now); 185 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 186 ScheduleCalendar cal = new ScheduleCalendar(); 187 cal.setSchedule(info); 188 189 // an hour before start, update with an alarm that will fire during the schedule 190 mService.evaluateSubscriptionLocked( 191 conditionId, cal, now.getTimeInMillis() - 1000, now.getTimeInMillis() + 1000); 192 193 // at start, should be in dnd 194 Condition condition = mService.evaluateSubscriptionLocked( 195 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000); 196 assertEquals(Condition.STATE_TRUE, condition.state); 197 198 // at alarm fire time, should exit dnd 199 assertTrue(cal.isInSchedule(now.getTimeInMillis() + 1000)); 200 assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(), 201 cal.shouldExitForAlarm(now.getTimeInMillis() + 1000)); 202 condition = mService.evaluateSubscriptionLocked( 203 conditionId, cal, now.getTimeInMillis() + 1000, 0); 204 assertEquals(Condition.STATE_FALSE, condition.state); 205 } 206 207 @Test 208 public void testEvaluateSubscription_alarmSetInSchedule() { 209 Calendar now = getNow(); 210 211 // Schedule - 1 hour long; starts now, ends with alarm 212 ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now); 213 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 214 ScheduleCalendar cal = new ScheduleCalendar(); 215 cal.setSchedule(info); 216 217 // at start, should be in dnd 218 Condition condition = mService.evaluateSubscriptionLocked( 219 conditionId, cal, now.getTimeInMillis(), 0); 220 assertEquals(Condition.STATE_TRUE, condition.state); 221 222 // in schedule, update with alarm time, should be in dnd 223 condition = mService.evaluateSubscriptionLocked( 224 conditionId, cal, now.getTimeInMillis() + 500, now.getTimeInMillis() + 1000); 225 assertEquals(Condition.STATE_TRUE, condition.state); 226 227 // at alarm fire time, should exit dnd 228 assertTrue(cal.isInSchedule(now.getTimeInMillis() + 1000)); 229 assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(), 230 cal.shouldExitForAlarm(now.getTimeInMillis() + 1000)); 231 condition = mService.evaluateSubscriptionLocked( 232 conditionId, cal, now.getTimeInMillis() + 1000, 0); 233 assertEquals(Condition.STATE_FALSE, condition.state); 234 } 235 236 @Test 237 public void testEvaluateSubscription_earlierAlarmSet() { 238 Calendar now = getNow(); 239 240 // Schedule - 1 hour long; starts now, ends with alarm 241 ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now); 242 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 243 ScheduleCalendar cal = new ScheduleCalendar(); 244 cal.setSchedule(info); 245 246 // at start, should be in dnd, alarm in 2000 ms 247 Condition condition = mService.evaluateSubscriptionLocked( 248 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 2000); 249 assertEquals(Condition.STATE_TRUE, condition.state); 250 251 // in schedule, update with earlier alarm time, should be in dnd 252 condition = mService.evaluateSubscriptionLocked( 253 conditionId, cal, now.getTimeInMillis() + 500, now.getTimeInMillis() + 1000); 254 assertEquals(Condition.STATE_TRUE, condition.state); 255 256 // at earliest alarm fire time, should exit dnd 257 assertTrue(cal.isInSchedule(now.getTimeInMillis() + 1000)); 258 assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(), 259 cal.shouldExitForAlarm(now.getTimeInMillis() + 1000)); 260 condition = mService.evaluateSubscriptionLocked( 261 conditionId, cal, now.getTimeInMillis() + 1000, 0); 262 assertEquals(Condition.STATE_FALSE, condition.state); 263 } 264 265 @Test 266 public void testEvaluateSubscription_laterAlarmSet() { 267 Calendar now = getNow(); 268 269 // Schedule - 1 hour long; starts now, ends with alarm 270 ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now); 271 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 272 ScheduleCalendar cal = new ScheduleCalendar(); 273 cal.setSchedule(info); 274 275 // at start, should be in dnd, alarm in 500 ms 276 Condition condition = mService.evaluateSubscriptionLocked( 277 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 500); 278 assertEquals(Condition.STATE_TRUE, condition.state); 279 280 // in schedule, update with later alarm time, should be in dnd 281 condition = mService.evaluateSubscriptionLocked( 282 conditionId, cal, now.getTimeInMillis() + 250, now.getTimeInMillis() + 1000); 283 assertEquals(Condition.STATE_TRUE, condition.state); 284 285 // at earliest alarm fire time, should exit dnd 286 assertTrue(cal.isInSchedule(now.getTimeInMillis() + 500)); 287 assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(), 288 cal.shouldExitForAlarm(now.getTimeInMillis() + 500)); 289 condition = mService.evaluateSubscriptionLocked( 290 conditionId, cal, now.getTimeInMillis() + 500, 0); 291 assertEquals(Condition.STATE_FALSE, condition.state); 292 } 293 294 @Test 295 public void testEvaluateSubscription_alarmCanceled() { 296 Calendar now = getNow(); 297 298 // Schedule - 1 hour long; starts now, ends with alarm 299 ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now); 300 Uri conditionId = ZenModeConfig.toScheduleConditionId(info); 301 ScheduleCalendar cal = new ScheduleCalendar(); 302 cal.setSchedule(info); 303 304 // at start, should be in dnd, alarm in 500 ms 305 Condition condition = mService.evaluateSubscriptionLocked( 306 conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 500); 307 assertEquals(Condition.STATE_TRUE, condition.state); 308 309 // in schedule, cancel alarm 310 condition = mService.evaluateSubscriptionLocked( 311 conditionId, cal, now.getTimeInMillis() + 250, 0); 312 assertEquals(Condition.STATE_TRUE, condition.state); 313 314 // at previous alarm time, should not exit DND 315 assertTrue(cal.isInSchedule(now.getTimeInMillis() + 500)); 316 assertFalse(cal.shouldExitForAlarm(now.getTimeInMillis() + 500)); 317 condition = mService.evaluateSubscriptionLocked( 318 conditionId, cal, now.getTimeInMillis() + 500, 0); 319 assertEquals(Condition.STATE_TRUE, condition.state); 320 321 // end of schedule, exit DND 322 now.add(Calendar.HOUR_OF_DAY, 1); 323 condition = mService.evaluateSubscriptionLocked(conditionId, cal, now.getTimeInMillis(), 0); 324 assertEquals(Condition.STATE_FALSE, condition.state); 325 } 326 327 private Calendar getNow() { 328 Calendar now = new GregorianCalendar(); 329 now.set(Calendar.HOUR_OF_DAY, 14); 330 now.set(Calendar.MINUTE, 16); 331 now.set(Calendar.SECOND, 0); 332 now.set(Calendar.MILLISECOND, 0); 333 now.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); 334 return now; 335 } 336 337 private ZenModeConfig.ScheduleInfo getScheduleEndsInHour(Calendar now) { 338 ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo(); 339 info.days = new int[] {Calendar.FRIDAY}; 340 info.startHour = now.get(Calendar.HOUR_OF_DAY); 341 info.startMinute = now.get(Calendar.MINUTE); 342 info.exitAtAlarm = true; 343 info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1; 344 info.endMinute = now.get(Calendar.MINUTE); 345 return info; 346 } 347 } 348