blob: 8a7edf746340b727fc84a93cacfe6488acced19b [file] [log] [blame]
Neil Fuller4773b9d2018-06-08 18:44:49 +01001/*
2 * Copyright (C) 2018 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.server.timedetector;
18
Neil Fuller4980bbc2018-06-12 21:06:20 +010019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNotNull;
22import static org.junit.Assert.assertNull;
23import static org.junit.Assert.assertTrue;
24import static org.junit.Assert.fail;
Neil Fuller4773b9d2018-06-08 18:44:49 +010025
Neil Fuller3aedd492019-11-23 11:33:57 +000026import android.app.timedetector.ManualTimeSuggestion;
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010027import android.app.timedetector.PhoneTimeSuggestion;
Neil Fuller4980bbc2018-06-12 21:06:20 +010028import android.content.Intent;
29import android.icu.util.Calendar;
30import android.icu.util.GregorianCalendar;
31import android.icu.util.TimeZone;
Neil Fuller4773b9d2018-06-08 18:44:49 +010032import android.util.TimestampedValue;
33
Brett Chabot8091d9e2019-02-26 14:52:33 -080034import androidx.test.runner.AndroidJUnit4;
35
Neil Fuller4773b9d2018-06-08 18:44:49 +010036import org.junit.Before;
37import org.junit.Test;
38import org.junit.runner.RunWith;
39
Neil Fuller3aedd492019-11-23 11:33:57 +000040import java.time.Duration;
41
Neil Fuller4773b9d2018-06-08 18:44:49 +010042@RunWith(AndroidJUnit4.class)
Neil Fuller40cf2952019-11-28 09:47:30 +000043public class SimpleTimeDetectorStrategyTest {
Neil Fuller4773b9d2018-06-08 18:44:49 +010044
Neil Fuller4980bbc2018-06-12 21:06:20 +010045 private static final Scenario SCENARIO_1 = new Scenario.Builder()
46 .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
47 .setInitialDeviceRealtimeMillis(123456789L)
48 .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
49 .build();
Neil Fuller4773b9d2018-06-08 18:44:49 +010050
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010051 private static final int ARBITRARY_PHONE_ID = 123456;
52
Neil Fuller3aedd492019-11-23 11:33:57 +000053 private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis();
54
Neil Fuller4980bbc2018-06-12 21:06:20 +010055 private Script mScript;
Neil Fuller4773b9d2018-06-08 18:44:49 +010056
57 @Before
58 public void setUp() {
Neil Fuller4980bbc2018-06-12 21:06:20 +010059 mScript = new Script();
Neil Fuller4773b9d2018-06-08 18:44:49 +010060 }
61
62 @Test
Neil Fuller3aedd492019-11-23 11:33:57 +000063 public void testSuggestPhoneTime_autoTimeEnabled() {
Neil Fuller4980bbc2018-06-12 21:06:20 +010064 Scenario scenario = SCENARIO_1;
65 mScript.pokeFakeClocks(scenario)
66 .pokeTimeDetectionEnabled(true);
Neil Fuller4773b9d2018-06-08 18:44:49 +010067
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010068 PhoneTimeSuggestion timeSuggestion =
69 scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
Neil Fuller4980bbc2018-06-12 21:06:20 +010070 final int clockIncrement = 1000;
71 long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
Neil Fuller4773b9d2018-06-08 18:44:49 +010072
Neil Fuller4980bbc2018-06-12 21:06:20 +010073 mScript.simulateTimePassing(clockIncrement)
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010074 .simulatePhoneTimeSuggestion(timeSuggestion)
Neil Fuller3aedd492019-11-23 11:33:57 +000075 .verifySystemClockWasSetAndResetCallTracking(
76 expectSystemClockMillis, true /* expectNetworkBroadcast */);
Neil Fuller4980bbc2018-06-12 21:06:20 +010077 }
78
79 @Test
Neil Fuller568fd892019-11-20 14:39:06 +000080 public void testSuggestPhoneTime_emptySuggestionIgnored() {
81 Scenario scenario = SCENARIO_1;
82 mScript.pokeFakeClocks(scenario)
83 .pokeTimeDetectionEnabled(true);
84
85 PhoneTimeSuggestion timeSuggestion = createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, null);
86
87 mScript.simulatePhoneTimeSuggestion(timeSuggestion)
88 .verifySystemClockWasNotSetAndResetCallTracking();
89 }
90
91 @Test
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010092 public void testSuggestPhoneTime_systemClockThreshold() {
Neil Fuller4980bbc2018-06-12 21:06:20 +010093 Scenario scenario = SCENARIO_1;
94 final int systemClockUpdateThresholdMillis = 1000;
95 mScript.pokeFakeClocks(scenario)
96 .pokeThresholds(systemClockUpdateThresholdMillis)
97 .pokeTimeDetectionEnabled(true);
98
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010099 PhoneTimeSuggestion timeSuggestion1 =
100 scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
101 TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
Neil Fuller4980bbc2018-06-12 21:06:20 +0100102
103 final int clockIncrement = 100;
104 // Increment the the device clocks to simulate the passage of time.
105 mScript.simulateTimePassing(clockIncrement);
106
107 long expectSystemClockMillis1 =
108 TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
109
110 // Send the first time signal. It should be used.
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100111 mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
Neil Fuller3aedd492019-11-23 11:33:57 +0000112 .verifySystemClockWasSetAndResetCallTracking(
113 expectSystemClockMillis1, true /* expectNetworkBroadcast */);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100114
115 // Now send another time signal, but one that is too similar to the last one and should be
116 // ignored.
117 int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
118 TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
119 mScript.peekElapsedRealtimeMillis(),
120 mScript.peekSystemClockMillis() + underThresholdMillis);
Neil Fuller568fd892019-11-20 14:39:06 +0000121 PhoneTimeSuggestion timeSuggestion2 =
122 createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100123 mScript.simulateTimePassing(clockIncrement)
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100124 .simulatePhoneTimeSuggestion(timeSuggestion2)
Neil Fuller4980bbc2018-06-12 21:06:20 +0100125 .verifySystemClockWasNotSetAndResetCallTracking();
126
127 // Now send another time signal, but one that is on the threshold and so should be used.
128 TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
129 mScript.peekElapsedRealtimeMillis(),
130 mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
131
Neil Fuller568fd892019-11-20 14:39:06 +0000132 PhoneTimeSuggestion timeSuggestion3 =
133 createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100134 mScript.simulateTimePassing(clockIncrement);
135
136 long expectSystemClockMillis3 =
137 TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
138
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100139 mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
Neil Fuller3aedd492019-11-23 11:33:57 +0000140 .verifySystemClockWasSetAndResetCallTracking(
141 expectSystemClockMillis3, true /* expectNetworkBroadcast */);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100142 }
143
144 @Test
Neil Fuller3aedd492019-11-23 11:33:57 +0000145 public void testSuggestPhoneTime_autoTimeDisabled() {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100146 Scenario scenario = SCENARIO_1;
147 mScript.pokeFakeClocks(scenario)
148 .pokeTimeDetectionEnabled(false);
149
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100150 PhoneTimeSuggestion timeSuggestion =
151 scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
152 mScript.simulatePhoneTimeSuggestion(timeSuggestion)
Neil Fuller4980bbc2018-06-12 21:06:20 +0100153 .verifySystemClockWasNotSetAndResetCallTracking();
154 }
155
156 @Test
Neil Fuller3aedd492019-11-23 11:33:57 +0000157 public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100158 Scenario scenario = SCENARIO_1;
159 final int systemClockUpdateThreshold = 2000;
160 mScript.pokeFakeClocks(scenario)
161 .pokeThresholds(systemClockUpdateThreshold)
162 .pokeTimeDetectionEnabled(true);
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100163 PhoneTimeSuggestion timeSuggestion1 =
164 scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
165 TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
Neil Fuller4980bbc2018-06-12 21:06:20 +0100166
167 // Initialize the strategy / device with a time set from NITZ.
168 mScript.simulateTimePassing(100);
169 long expectedSystemClockMillis1 =
170 TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100171 mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
Neil Fuller3aedd492019-11-23 11:33:57 +0000172 .verifySystemClockWasSetAndResetCallTracking(
173 expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100174
175 // The UTC time increment should be larger than the system clock update threshold so we
176 // know it shouldn't be ignored for other reasons.
177 long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold);
178
179 // Now supply a new signal that has an obviously bogus reference time : older than the last
180 // one.
181 long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
182 TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
183 referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
Neil Fuller568fd892019-11-20 14:39:06 +0000184 PhoneTimeSuggestion timeSuggestion2 =
185 createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100186 mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
Neil Fuller4980bbc2018-06-12 21:06:20 +0100187 .verifySystemClockWasNotSetAndResetCallTracking();
188
189 // Now supply a new signal that has an obviously bogus reference time : substantially in the
190 // future.
191 long referenceTimeInFutureMillis =
192 utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
193 TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
194 referenceTimeInFutureMillis, validUtcTimeMillis);
Neil Fuller568fd892019-11-20 14:39:06 +0000195 PhoneTimeSuggestion timeSuggestion3 =
196 createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100197 mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
Neil Fuller4980bbc2018-06-12 21:06:20 +0100198 .verifySystemClockWasNotSetAndResetCallTracking();
199
200 // Just to prove validUtcTimeMillis is valid.
201 long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
202 TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
203 validReferenceTimeMillis, validUtcTimeMillis);
204 long expectedSystemClockMillis4 =
205 TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
Neil Fuller568fd892019-11-20 14:39:06 +0000206 PhoneTimeSuggestion timeSuggestion4 =
207 createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100208 mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
Neil Fuller3aedd492019-11-23 11:33:57 +0000209 .verifySystemClockWasSetAndResetCallTracking(
210 expectedSystemClockMillis4, true /* expectNetworkBroadcast */);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100211 }
212
213 @Test
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100214 public void testSuggestPhoneTime_timeDetectionToggled() {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100215 Scenario scenario = SCENARIO_1;
216 final int clockIncrementMillis = 100;
217 final int systemClockUpdateThreshold = 2000;
218 mScript.pokeFakeClocks(scenario)
219 .pokeThresholds(systemClockUpdateThreshold)
220 .pokeTimeDetectionEnabled(false);
221
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100222 PhoneTimeSuggestion timeSuggestion1 =
223 scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
224 TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
Neil Fuller4980bbc2018-06-12 21:06:20 +0100225
226 // Simulate time passing.
227 mScript.simulateTimePassing(clockIncrementMillis);
228
229 // Simulate the time signal being received. It should not be used because auto time
230 // detection is off but it should be recorded.
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100231 mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
Neil Fuller4980bbc2018-06-12 21:06:20 +0100232 .verifySystemClockWasNotSetAndResetCallTracking();
233
234 // Simulate more time passing.
235 mScript.simulateTimePassing(clockIncrementMillis);
236
237 long expectedSystemClockMillis1 =
238 TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
239
240 // Turn on auto time detection.
241 mScript.simulateAutoTimeDetectionToggle()
Neil Fuller3aedd492019-11-23 11:33:57 +0000242 .verifySystemClockWasSetAndResetCallTracking(
243 expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100244
245 // Turn off auto time detection.
246 mScript.simulateAutoTimeDetectionToggle()
247 .verifySystemClockWasNotSetAndResetCallTracking();
248
249 // Receive another valid time signal.
250 // It should be on the threshold and accounting for the clock increments.
251 TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
252 mScript.peekElapsedRealtimeMillis(),
253 mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
Neil Fuller568fd892019-11-20 14:39:06 +0000254 PhoneTimeSuggestion timeSuggestion2 =
255 createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100256
257 // Simulate more time passing.
258 mScript.simulateTimePassing(clockIncrementMillis);
259
260 long expectedSystemClockMillis2 =
261 TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis());
262
263 // The new time, though valid, should not be set in the system clock because auto time is
264 // disabled.
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100265 mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
Neil Fuller4980bbc2018-06-12 21:06:20 +0100266 .verifySystemClockWasNotSetAndResetCallTracking();
267
268 // Turn on auto time detection.
269 mScript.simulateAutoTimeDetectionToggle()
Neil Fuller3aedd492019-11-23 11:33:57 +0000270 .verifySystemClockWasSetAndResetCallTracking(
271 expectedSystemClockMillis2, true /* expectNetworkBroadcast */);
272 }
273
274 @Test
275 public void testSuggestManualTime_autoTimeDisabled() {
276 Scenario scenario = SCENARIO_1;
277 mScript.pokeFakeClocks(scenario)
278 .pokeTimeDetectionEnabled(false);
279
280 ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
281 final int clockIncrement = 1000;
282 long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
283
284 mScript.simulateTimePassing(clockIncrement)
285 .simulateManualTimeSuggestion(timeSuggestion)
286 .verifySystemClockWasSetAndResetCallTracking(
287 expectSystemClockMillis, false /* expectNetworkBroadcast */);
288 }
289
290 @Test
291 public void testSuggestManualTime_retainsAutoSignal() {
292 Scenario scenario = SCENARIO_1;
293
294 // Configure the start state.
295 mScript.pokeFakeClocks(scenario)
296 .pokeTimeDetectionEnabled(true);
297
298 // Simulate a phone suggestion.
299 PhoneTimeSuggestion phoneTimeSuggestion =
300 scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
301 long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue();
302 final int clockIncrement = 1000;
303
304 // Simulate the passage of time.
305 mScript.simulateTimePassing(clockIncrement);
306 expectedAutoClockMillis += clockIncrement;
307
308 mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
309 .verifySystemClockWasSetAndResetCallTracking(
310 expectedAutoClockMillis, true /* expectNetworkBroadcast */);
311
312 // Simulate the passage of time.
313 mScript.simulateTimePassing(clockIncrement);
314 expectedAutoClockMillis += clockIncrement;
315
316 // Switch to manual.
317 mScript.simulateAutoTimeDetectionToggle()
318 .verifySystemClockWasNotSetAndResetCallTracking();
319
320 // Simulate the passage of time.
321 mScript.simulateTimePassing(clockIncrement);
322 expectedAutoClockMillis += clockIncrement;
323
324
325 // Simulate a manual suggestion 1 day different from the auto suggestion.
326 long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS;
327 long expectedManualClockMillis = manualTimeMillis;
328 ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis);
329 mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
330 .verifySystemClockWasSetAndResetCallTracking(
331 expectedManualClockMillis, false /* expectNetworkBroadcast */);
332
333 // Simulate the passage of time.
334 mScript.simulateTimePassing(clockIncrement);
335 expectedAutoClockMillis += clockIncrement;
336
337 // Switch back to auto.
338 mScript.simulateAutoTimeDetectionToggle();
339
340 mScript.verifySystemClockWasSetAndResetCallTracking(
341 expectedAutoClockMillis, true /* expectNetworkBroadcast */);
342
343 // Switch back to manual - nothing should happen to the clock.
344 mScript.simulateAutoTimeDetectionToggle()
345 .verifySystemClockWasNotSetAndResetCallTracking();
346 }
347
348 /**
349 * Manual suggestions should be ignored if auto time is enabled.
350 */
351 @Test
352 public void testSuggestManualTime_autoTimeEnabled() {
353 Scenario scenario = SCENARIO_1;
354 mScript.pokeFakeClocks(scenario)
355 .pokeTimeDetectionEnabled(true);
356
357 ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
358 final int clockIncrement = 1000;
359
360 mScript.simulateTimePassing(clockIncrement)
361 .simulateManualTimeSuggestion(timeSuggestion)
362 .verifySystemClockWasNotSetAndResetCallTracking();
Neil Fuller4773b9d2018-06-08 18:44:49 +0100363 }
364
Neil Fuller4980bbc2018-06-12 21:06:20 +0100365 /**
366 * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
367 * like the real thing should, it also asserts preconditions.
368 */
369 private static class FakeCallback implements TimeDetectorStrategy.Callback {
370 private boolean mTimeDetectionEnabled;
371 private boolean mWakeLockAcquired;
372 private long mElapsedRealtimeMillis;
373 private long mSystemClockMillis;
374 private int mSystemClockUpdateThresholdMillis = 2000;
375
376 // Tracking operations.
377 private boolean mSystemClockWasSet;
378 private Intent mBroadcastSent;
379
380 @Override
381 public int systemClockUpdateThresholdMillis() {
382 return mSystemClockUpdateThresholdMillis;
383 }
384
385 @Override
Neil Fuller3aedd492019-11-23 11:33:57 +0000386 public boolean isAutoTimeDetectionEnabled() {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100387 return mTimeDetectionEnabled;
388 }
389
390 @Override
391 public void acquireWakeLock() {
392 if (mWakeLockAcquired) {
393 fail("Wake lock already acquired");
394 }
395 mWakeLockAcquired = true;
396 }
397
398 @Override
399 public long elapsedRealtimeMillis() {
400 assertWakeLockAcquired();
401 return mElapsedRealtimeMillis;
402 }
403
404 @Override
405 public long systemClockMillis() {
406 assertWakeLockAcquired();
407 return mSystemClockMillis;
408 }
409
410 @Override
411 public void setSystemClock(long newTimeMillis) {
412 assertWakeLockAcquired();
413 mSystemClockWasSet = true;
414 mSystemClockMillis = newTimeMillis;
415 }
416
417 @Override
418 public void releaseWakeLock() {
419 assertWakeLockAcquired();
420 mWakeLockAcquired = false;
421 }
422
423 @Override
424 public void sendStickyBroadcast(Intent intent) {
425 assertNotNull(intent);
426 mBroadcastSent = intent;
427 }
428
429 // Methods below are for managing the fake's behavior.
430
431 public void pokeSystemClockUpdateThreshold(int thresholdMillis) {
432 mSystemClockUpdateThresholdMillis = thresholdMillis;
433 }
434
435 public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
436 mElapsedRealtimeMillis = elapsedRealtimeMillis;
437 }
438
439 public void pokeSystemClockMillis(long systemClockMillis) {
440 mSystemClockMillis = systemClockMillis;
441 }
442
Neil Fuller40cf2952019-11-28 09:47:30 +0000443 public void pokeAutoTimeDetectionEnabled(boolean enabled) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100444 mTimeDetectionEnabled = enabled;
445 }
446
447 public long peekElapsedRealtimeMillis() {
448 return mElapsedRealtimeMillis;
449 }
450
451 public long peekSystemClockMillis() {
452 return mSystemClockMillis;
453 }
454
455 public void simulateTimePassing(int incrementMillis) {
456 mElapsedRealtimeMillis += incrementMillis;
457 mSystemClockMillis += incrementMillis;
458 }
459
Neil Fuller40cf2952019-11-28 09:47:30 +0000460 public void simulateAutoTimeZoneDetectionToggle() {
461 mTimeDetectionEnabled = !mTimeDetectionEnabled;
462 }
463
Neil Fuller4980bbc2018-06-12 21:06:20 +0100464 public void verifySystemClockNotSet() {
465 assertFalse(mSystemClockWasSet);
466 }
467
468 public void verifySystemClockWasSet(long expectSystemClockMillis) {
469 assertTrue(mSystemClockWasSet);
470 assertEquals(expectSystemClockMillis, mSystemClockMillis);
471 }
472
473 public void verifyIntentWasBroadcast() {
474 assertTrue(mBroadcastSent != null);
475 }
476
477 public void verifyIntentWasNotBroadcast() {
478 assertNull(mBroadcastSent);
479 }
480
481 public void resetCallTracking() {
482 mSystemClockWasSet = false;
483 mBroadcastSent = null;
484 }
485
486 private void assertWakeLockAcquired() {
487 assertTrue("The operation must be performed only after acquiring the wakelock",
488 mWakeLockAcquired);
489 }
490 }
491
492 /**
493 * A fluent helper class for tests.
494 */
495 private class Script {
496
497 private final FakeCallback mFakeCallback;
498 private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
499
Neil Fuller40cf2952019-11-28 09:47:30 +0000500 Script() {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100501 mFakeCallback = new FakeCallback();
502 mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
503 mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
504
505 }
506
507 Script pokeTimeDetectionEnabled(boolean enabled) {
Neil Fuller40cf2952019-11-28 09:47:30 +0000508 mFakeCallback.pokeAutoTimeDetectionEnabled(enabled);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100509 return this;
510 }
511
512 Script pokeFakeClocks(Scenario scenario) {
513 mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis());
514 mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis());
515 return this;
516 }
517
518 Script pokeThresholds(int systemClockUpdateThreshold) {
519 mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold);
520 return this;
521 }
522
523 long peekElapsedRealtimeMillis() {
524 return mFakeCallback.peekElapsedRealtimeMillis();
525 }
526
527 long peekSystemClockMillis() {
528 return mFakeCallback.peekSystemClockMillis();
529 }
530
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100531 Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
532 mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100533 return this;
534 }
535
Neil Fuller3aedd492019-11-23 11:33:57 +0000536 Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) {
537 mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion);
538 return this;
539 }
540
Neil Fuller4980bbc2018-06-12 21:06:20 +0100541 Script simulateAutoTimeDetectionToggle() {
Neil Fuller40cf2952019-11-28 09:47:30 +0000542 mFakeCallback.simulateAutoTimeZoneDetectionToggle();
543 mSimpleTimeDetectorStrategy.handleAutoTimeDetectionChanged();
Neil Fuller4980bbc2018-06-12 21:06:20 +0100544 return this;
545 }
546
547 Script simulateTimePassing(int clockIncrement) {
548 mFakeCallback.simulateTimePassing(clockIncrement);
549 return this;
550 }
551
552 Script verifySystemClockWasNotSetAndResetCallTracking() {
553 mFakeCallback.verifySystemClockNotSet();
554 mFakeCallback.verifyIntentWasNotBroadcast();
555 mFakeCallback.resetCallTracking();
556 return this;
557 }
558
Neil Fuller3aedd492019-11-23 11:33:57 +0000559 Script verifySystemClockWasSetAndResetCallTracking(
560 long expectSystemClockMillis, boolean expectNetworkBroadcast) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100561 mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
Neil Fuller3aedd492019-11-23 11:33:57 +0000562 if (expectNetworkBroadcast) {
563 mFakeCallback.verifyIntentWasBroadcast();
564 }
Neil Fuller4980bbc2018-06-12 21:06:20 +0100565 mFakeCallback.resetCallTracking();
566 return this;
567 }
568 }
569
570 /**
571 * A starting scenario used during tests. Describes a fictional "physical" reality.
572 */
573 private static class Scenario {
574
575 private final long mInitialDeviceSystemClockMillis;
576 private final long mInitialDeviceRealtimeMillis;
577 private final long mActualTimeMillis;
578
579 Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) {
580 mInitialDeviceSystemClockMillis = initialDeviceSystemClock;
581 mActualTimeMillis = timeMillis;
582 mInitialDeviceRealtimeMillis = elapsedRealtime;
583 }
584
585 long getInitialRealTimeMillis() {
586 return mInitialDeviceRealtimeMillis;
587 }
588
589 long getInitialSystemClockMillis() {
590 return mInitialDeviceSystemClockMillis;
591 }
592
593 long getActualTimeMillis() {
594 return mActualTimeMillis;
595 }
596
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100597 PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100598 TimestampedValue<Long> time = new TimestampedValue<>(
599 mInitialDeviceRealtimeMillis, mActualTimeMillis);
Neil Fuller568fd892019-11-20 14:39:06 +0000600 return createPhoneTimeSuggestion(phoneId, time);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100601 }
602
Neil Fuller3aedd492019-11-23 11:33:57 +0000603 ManualTimeSuggestion createManualTimeSuggestionForActual() {
604 TimestampedValue<Long> time = new TimestampedValue<>(
605 mInitialDeviceRealtimeMillis, mActualTimeMillis);
606 return new ManualTimeSuggestion(time);
607 }
608
Neil Fuller4980bbc2018-06-12 21:06:20 +0100609 static class Builder {
610
611 private long mInitialDeviceSystemClockMillis;
612 private long mInitialDeviceRealtimeMillis;
613 private long mActualTimeMillis;
614
615 Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day,
616 int hourOfDay, int minute, int second) {
617 mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay,
618 minute, second);
619 return this;
620 }
621
622 Builder setInitialDeviceRealtimeMillis(long realtimeMillis) {
623 mInitialDeviceRealtimeMillis = realtimeMillis;
624 return this;
625 }
626
627 Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
628 int minute, int second) {
629 mActualTimeMillis =
630 createUtcTime(year, monthInYear, day, hourOfDay, minute, second);
631 return this;
632 }
633
634 Scenario build() {
635 return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis,
636 mActualTimeMillis);
637 }
638 }
639 }
640
Neil Fuller568fd892019-11-20 14:39:06 +0000641 private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId,
642 TimestampedValue<Long> utcTime) {
643 PhoneTimeSuggestion timeSuggestion = new PhoneTimeSuggestion(phoneId);
644 timeSuggestion.setUtcTime(utcTime);
645 return timeSuggestion;
646 }
647
Neil Fuller3aedd492019-11-23 11:33:57 +0000648 private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) {
649 TimestampedValue<Long> utcTime =
650 new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis);
651 return new ManualTimeSuggestion(utcTime);
652 }
653
Neil Fuller4980bbc2018-06-12 21:06:20 +0100654 private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
655 int second) {
656 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
657 cal.clear();
658 cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
659 return cal.getTimeInMillis();
Neil Fuller4773b9d2018-06-08 18:44:49 +0100660 }
661}