aboutsummaryrefslogtreecommitdiff
path: root/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowLooper.java
diff options
context:
space:
mode:
Diffstat (limited to 'v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowLooper.java')
-rw-r--r--v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowLooper.java193
1 files changed, 193 insertions, 0 deletions
diff --git a/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowLooper.java b/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowLooper.java
new file mode 100644
index 000000000..99126e2f3
--- /dev/null
+++ b/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowLooper.java
@@ -0,0 +1,193 @@
+package com.xtremelabs.robolectric.shadows;
+
+import android.os.Looper;
+import com.xtremelabs.robolectric.Robolectric;
+import com.xtremelabs.robolectric.internal.Implementation;
+import com.xtremelabs.robolectric.internal.Implements;
+import com.xtremelabs.robolectric.util.Scheduler;
+
+import static com.xtremelabs.robolectric.Robolectric.shadowOf;
+
+/**
+ * Shadow for {@code Looper} that enqueues posted {@link Runnable}s to be run (on this thread) later. {@code Runnable}s
+ * that are scheduled to run immediately can be triggered by calling {@link #idle()}
+ * todo: provide better support for advancing the clock and running queued tasks
+ */
+
+@SuppressWarnings({"UnusedDeclaration"})
+@Implements(Looper.class)
+public class ShadowLooper {
+ private static ThreadLocal<Looper> looperForThread = makeThreadLocalLoopers();
+ private Scheduler scheduler = new Scheduler();
+ private Thread myThread = Thread.currentThread();
+
+ boolean quit;
+
+ private static synchronized ThreadLocal<Looper> makeThreadLocalLoopers() {
+ return new ThreadLocal<Looper>() {
+ @Override
+ protected Looper initialValue() {
+ return Robolectric.Reflection.newInstanceOf(Looper.class);
+ }
+ };
+ }
+
+ public static void resetThreadLoopers() {
+ looperForThread = makeThreadLocalLoopers();
+ }
+
+ @Implementation
+ public static Looper getMainLooper() {
+ return Robolectric.getShadowApplication().getMainLooper();
+ }
+
+ @Implementation
+ public static void loop() {
+ final ShadowLooper looper = shadowOf(myLooper());
+ if (looper != shadowOf(getMainLooper())) {
+ while (!looper.quit) {
+ try {
+ synchronized (looper) {
+ looper.wait();
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+ }
+ }
+
+ @Implementation
+ public static synchronized Looper myLooper() {
+ return looperForThread.get();
+ }
+
+ @Implementation
+ public void quit() {
+ if (this == shadowOf(getMainLooper())) throw new RuntimeException("Main thread not allowed to quit");
+ synchronized (this) {
+ quit = true;
+ scheduler.reset();
+ notify();
+ }
+ }
+
+ @Implementation
+ public Thread getThread() {
+ return myThread;
+ }
+
+ public boolean hasQuit() {
+ return quit;
+ }
+
+ public static void pauseLooper(Looper looper) {
+ shadowOf(looper).pause();
+ }
+
+ public static void unPauseLooper(Looper looper) {
+ shadowOf(looper).unPause();
+ }
+
+ public static void pauseMainLooper() {
+ pauseLooper(Looper.getMainLooper());
+ }
+
+ public static void unPauseMainLooper() {
+ unPauseLooper(Looper.getMainLooper());
+ }
+
+ public static void idleMainLooper(long interval) {
+ shadowOf(Looper.getMainLooper()).idle(interval);
+ }
+
+ /**
+ * Causes {@link Runnable}s that have been scheduled to run immediately to actually run. Does not advance the
+ * scheduler's clock;
+ */
+ public void idle() {
+ scheduler.advanceBy(0);
+ }
+
+ /**
+ * Causes {@link Runnable}s that have been scheduled to run within the next {@code intervalMillis} milliseconds to
+ * run while advancing the scheduler's clock.
+ *
+ * @param intervalMillis milliseconds to advance
+ */
+ public void idle(long intervalMillis) {
+ scheduler.advanceBy(intervalMillis);
+ }
+
+ /**
+ * Causes all of the {@link Runnable}s that have been scheduled to run while advancing the scheduler's clock to the
+ * start time of the last scheduled {@link Runnable}.
+ */
+ public void runToEndOfTasks() {
+ scheduler.advanceToLastPostedRunnable();
+ }
+
+ /**
+ * Causes the next {@link Runnable}(s) that have been scheduled to run while advancing the scheduler's clock to its
+ * start time. If more than one {@link Runnable} is scheduled to run at this time then they will all be run.
+ */
+ public void runToNextTask() {
+ scheduler.advanceToNextPostedRunnable();
+ }
+
+ /**
+ * Causes only one of the next {@link Runnable}s that have been scheduled to run while advancing the scheduler's
+ * clock to its start time. Only one {@link Runnable} will run even if more than one has ben scheduled to run at the
+ * same time.
+ */
+ public void runOneTask() {
+ scheduler.runOneTask();
+ }
+
+ /**
+ * Enqueue a task to be run later.
+ *
+ * @param runnable the task to be run
+ * @param delayMillis how many milliseconds into the (virtual) future to run it
+ */
+ public boolean post(Runnable runnable, long delayMillis) {
+ if (!quit) {
+ scheduler.postDelayed(runnable, delayMillis);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean postAtFrontOfQueue(Runnable runnable) {
+ if (!quit) {
+ scheduler.postAtFrontOfQueue(runnable);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void pause() {
+ scheduler.pause();
+ }
+
+ public void unPause() {
+ scheduler.unPause();
+ }
+
+ /**
+ * Causes all enqueued tasks to be discarded
+ */
+ public void reset() {
+ scheduler.reset();
+ }
+
+ /**
+ * Returns the {@link com.xtremelabs.robolectric.util.Scheduler} that is being used to manage the enqueued tasks.
+ *
+ * @return the {@link com.xtremelabs.robolectric.util.Scheduler} that is being used to manage the enqueued tasks.
+ */
+ public Scheduler getScheduler() {
+ return scheduler;
+ }
+}