3131import com .google .common .collect .ComparisonChain ;
3232import com .google .common .collect .ImmutableSet ;
3333import com .google .common .collect .Ordering ;
34+ import com .google .errorprone .annotations .CanIgnoreReturnValue ;
3435import java .util .ArrayList ;
3536import java .util .Collections ;
3637import java .util .HashSet ;
5556@ UnstableApi
5657public class FakeClock implements Clock {
5758
59+ /** A builder for {@link FakeClock} instances. */
60+ public static final class Builder {
61+ private long bootTimeMs ;
62+ private long initialTimeMs ;
63+ private boolean isAutoAdvancing ;
64+ private long maxAutoAdvancingTimeDiffMs ;
65+
66+ /** Creates a new builder for {@link FakeClock} instances. */
67+ public Builder () {
68+ bootTimeMs = 0 ;
69+ initialTimeMs = 0 ;
70+ isAutoAdvancing = false ;
71+ maxAutoAdvancingTimeDiffMs = DEFAULT_MAX_AUTO_ADVANCING_TIME_DIFF_MS ;
72+ }
73+
74+ /**
75+ * Sets the time the system was booted since the Unix Epoch, in milliseconds.
76+ *
77+ * <p>The default value is 0.
78+ *
79+ * @param bootTimeMs The time the system was booted since the Unix Epoch, in milliseconds.
80+ * @return This builder.
81+ */
82+ @ CanIgnoreReturnValue
83+ public Builder setBootTimeMs (long bootTimeMs ) {
84+ this .bootTimeMs = bootTimeMs ;
85+ return this ;
86+ }
87+
88+ /**
89+ * Sets the initial elapsed time since the boot time, in milliseconds.
90+ *
91+ * <p>The default value is 0.
92+ *
93+ * @param initialTimeMs The initial elapsed time since the boot time, in milliseconds.
94+ * @return This builder.
95+ */
96+ @ CanIgnoreReturnValue
97+ public Builder setInitialTimeMs (long initialTimeMs ) {
98+ this .initialTimeMs = initialTimeMs ;
99+ return this ;
100+ }
101+
102+ /**
103+ * Sets whether the clock should automatically advance the time to the time of the next message
104+ * that is due to be sent.
105+ *
106+ * <p>The default value is false.
107+ *
108+ * @param isAutoAdvancing Whether the clock should automatically advance the time.
109+ * @return This builder.
110+ */
111+ @ CanIgnoreReturnValue
112+ public Builder setIsAutoAdvancing (boolean isAutoAdvancing ) {
113+ this .isAutoAdvancing = isAutoAdvancing ;
114+ return this ;
115+ }
116+
117+ /**
118+ * Sets the maximum time difference between two messages that the fake clock will automatically
119+ * advance.
120+ *
121+ * <p>The default value is {@link #DEFAULT_MAX_AUTO_ADVANCING_TIME_DIFF_MS}.
122+ *
123+ * @param maxAutoAdvancingTimeDiffMs The maximum time difference in milliseconds.
124+ * @return This builder.
125+ */
126+ @ CanIgnoreReturnValue
127+ public Builder setMaxAutoAdvancingTimeDiffMs (long maxAutoAdvancingTimeDiffMs ) {
128+ this .maxAutoAdvancingTimeDiffMs = maxAutoAdvancingTimeDiffMs ;
129+ return this ;
130+ }
131+
132+ /**
133+ * Builds a {@link FakeClock} instance.
134+ *
135+ * @return The built {@link FakeClock} instance.
136+ */
137+ public FakeClock build () {
138+ return new FakeClock (/* builder= */ this );
139+ }
140+ }
141+
142+ /**
143+ * The default maximum time difference between two messages that the fake clock will automatically
144+ * advance.
145+ */
146+ public static final long DEFAULT_MAX_AUTO_ADVANCING_TIME_DIFF_MS = 1000 ;
147+
58148 private static final ImmutableSet <String > UI_INTERACTION_TEST_CLASSES =
59149 ImmutableSet .of (
60150 "org.robolectric.android.internal.LocalControlledLooper" ,
@@ -69,6 +159,7 @@ public class FakeClock implements Clock {
69159 private final boolean isRobolectric ;
70160 private final boolean isAutoAdvancing ;
71161 private final Handler mainHandler ;
162+ private final long maxAutoAdvancingTimeDiffMs ;
72163
73164 @ GuardedBy ("this" )
74165 private final List <HandlerMessage > handlerMessages ;
@@ -129,15 +220,24 @@ public FakeClock(long initialTimeMs, boolean isAutoAdvancing) {
129220 * next message that is due to be sent.
130221 */
131222 public FakeClock (long bootTimeMs , long initialTimeMs , boolean isAutoAdvancing ) {
132- this .bootTimeMs = bootTimeMs ;
133- this .timeSinceBootMs = initialTimeMs ;
134- this .isAutoAdvancing = isAutoAdvancing ;
223+ this (
224+ new Builder ()
225+ .setBootTimeMs (bootTimeMs )
226+ .setInitialTimeMs (initialTimeMs )
227+ .setIsAutoAdvancing (isAutoAdvancing ));
228+ }
229+
230+ private FakeClock (Builder builder ) {
231+ this .bootTimeMs = builder .bootTimeMs ;
232+ this .timeSinceBootMs = builder .initialTimeMs ;
233+ this .isAutoAdvancing = builder .isAutoAdvancing ;
234+ this .maxAutoAdvancingTimeDiffMs = builder .maxAutoAdvancingTimeDiffMs ;
135235 this .handlerMessages = new ArrayList <>();
136236 this .busyLoopers = new HashSet <>();
137237 this .mainHandler = new Handler (Looper .getMainLooper ());
138238 this .isRobolectric = "robolectric" .equals (Build .FINGERPRINT );
139239 if (isRobolectric ) {
140- SystemClock .setCurrentTimeMillis (initialTimeMs );
240+ SystemClock .setCurrentTimeMillis (builder . initialTimeMs );
141241 }
142242 }
143243
@@ -271,8 +371,9 @@ private synchronized void maybeTriggerMessage() {
271371 return ;
272372 }
273373 if (message .timeMs > timeSinceBootMs ) {
274- if (isAutoAdvancing ) {
275- advanceTimeInternal (message .timeMs - timeSinceBootMs );
374+ long timeDiff = message .timeMs - timeSinceBootMs ;
375+ if (isAutoAdvancing && timeDiff <= maxAutoAdvancingTimeDiffMs ) {
376+ advanceTimeInternal (timeDiff );
276377 } else {
277378 return ;
278379 }
0 commit comments