1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.P; 4 5 import android.os.SystemClock; 6 import java.time.DateTimeException; 7 import java.util.concurrent.TimeUnit; 8 import org.robolectric.RuntimeEnvironment; 9 import org.robolectric.annotation.HiddenApi; 10 import org.robolectric.annotation.Implementation; 11 import org.robolectric.annotation.Implements; 12 import org.robolectric.annotation.Resetter; 13 14 /** 15 * A shadow SystemClock for {@link LooperMode.Mode.LEGACY} 16 * 17 * <p>In LEGACY LooperMode, Robolectric's concept of current time is base on the current time of the 18 * UI Scheduler for consistency with previous implementations. This is not ideal, since both 19 * schedulers (background and foreground), can see different values for the current time. 20 */ 21 @Implements( 22 value = SystemClock.class, 23 shadowPicker = ShadowSystemClock.Picker.class, 24 // turn off shadowOf generation 25 isInAndroidSdk = false) 26 public class ShadowLegacySystemClock extends ShadowSystemClock { 27 private static long bootedAt = 0; 28 private static long nanoTime = 0; 29 private static final int MILLIS_PER_NANO = 1000000; 30 now()31 static long now() { 32 return RuntimeEnvironment.getMasterScheduler().getCurrentTime(); 33 } 34 35 @Implementation sleep(long millis)36 protected static void sleep(long millis) { 37 nanoTime = millis * MILLIS_PER_NANO; 38 RuntimeEnvironment.getMasterScheduler().advanceBy(millis, TimeUnit.MILLISECONDS); 39 } 40 41 @Implementation setCurrentTimeMillis(long millis)42 protected static boolean setCurrentTimeMillis(long millis) { 43 if (now() > millis) { 44 return false; 45 } 46 nanoTime = millis * MILLIS_PER_NANO; 47 RuntimeEnvironment.getMasterScheduler().advanceTo(millis); 48 return true; 49 } 50 51 @Implementation uptimeMillis()52 protected static long uptimeMillis() { 53 return now() - bootedAt; 54 } 55 56 @Implementation elapsedRealtime()57 protected static long elapsedRealtime() { 58 return uptimeMillis(); 59 } 60 61 @Implementation elapsedRealtimeNanos()62 protected static long elapsedRealtimeNanos() { 63 return elapsedRealtime() * MILLIS_PER_NANO; 64 } 65 66 @Implementation currentThreadTimeMillis()67 protected static long currentThreadTimeMillis() { 68 return uptimeMillis(); 69 } 70 71 @HiddenApi 72 @Implementation currentThreadTimeMicro()73 public static long currentThreadTimeMicro() { 74 return uptimeMillis() * 1000; 75 } 76 77 @HiddenApi 78 @Implementation currentTimeMicro()79 public static long currentTimeMicro() { 80 return now() * 1000; 81 } 82 83 /** 84 * Implements {@link System#currentTimeMillis} through ShadowWrangler. 85 * 86 * @return Current time in millis. 87 */ 88 @SuppressWarnings("unused") currentTimeMillis()89 public static long currentTimeMillis() { 90 return nanoTime / MILLIS_PER_NANO; 91 } 92 93 /** 94 * Implements {@link System#nanoTime} through ShadowWrangler. 95 * 96 * @return Current time with nanos. 97 */ 98 @SuppressWarnings("unused") nanoTime()99 public static long nanoTime() { 100 return nanoTime; 101 } 102 setNanoTime(long nanoTime)103 public static void setNanoTime(long nanoTime) { 104 ShadowLegacySystemClock.nanoTime = nanoTime; 105 } 106 107 @Implementation(minSdk = P) 108 @HiddenApi currentNetworkTimeMillis()109 protected static long currentNetworkTimeMillis() { 110 if (networkTimeAvailable) { 111 return currentTimeMillis(); 112 } else { 113 throw new DateTimeException("Network time not available"); 114 } 115 } 116 117 @Resetter reset()118 public static void reset() { 119 ShadowSystemClock.reset(); 120 } 121 } 122