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