1package com.xtremelabs.robolectric.util; 2 3import java.util.ArrayList; 4import java.util.Collections; 5import java.util.List; 6import java.util.ListIterator; 7 8public class Scheduler { 9 private List<PostedRunnable> postedRunnables = new ArrayList<PostedRunnable>(); 10 private long currentTime = 0; 11 private boolean paused = false; 12 13 public long getCurrentTime() { 14 return currentTime; 15 } 16 17 public void pause() { 18 paused = true; 19 } 20 21 public void unPause() { 22 paused = false; 23 advanceToLastPostedRunnable(); 24 } 25 26 public boolean isPaused() { 27 return paused; 28 } 29 30 public void postDelayed(Runnable runnable, long delayMillis) { 31 if (paused || delayMillis > 0) { 32 postedRunnables.add(new PostedRunnable(runnable, currentTime + delayMillis)); 33 Collections.sort(postedRunnables); 34 } else { 35 runnable.run(); 36 } 37 } 38 39 public void post(Runnable runnable) { 40 postDelayed(runnable, 0); 41 } 42 43 public void postAtFrontOfQueue(Runnable runnable) { 44 if (paused) { 45 postedRunnables.add(0, new PostedRunnable(runnable, currentTime)); 46 } else { 47 runnable.run(); 48 } 49 } 50 51 public void remove(Runnable runnable) { 52 ListIterator<PostedRunnable> iterator = postedRunnables.listIterator(); 53 while (iterator.hasNext()) { 54 PostedRunnable next = iterator.next(); 55 if (next.runnable == runnable) { 56 iterator.remove(); 57 } 58 } 59 } 60 61 public boolean advanceToLastPostedRunnable() { 62 if (enqueuedTaskCount() < 1) { 63 return false; 64 } 65 66 return advanceTo(postedRunnables.get(postedRunnables.size() - 1).scheduledTime); 67 } 68 69 public boolean advanceToNextPostedRunnable() { 70 if (enqueuedTaskCount() < 1) { 71 return false; 72 } 73 74 return advanceTo(postedRunnables.get(0).scheduledTime); 75 } 76 77 public boolean advanceBy(long intervalMs) { 78 long endingTime = currentTime + intervalMs; 79 return advanceTo(endingTime); 80 } 81 82 public boolean advanceTo(long endingTime) { 83 if (endingTime - currentTime < 0 || enqueuedTaskCount() < 1) { 84 return false; 85 } 86 87 int runCount = 0; 88 while (nextTaskIsScheduledBefore(endingTime)) { 89 runOneTask(); 90 ++runCount; 91 } 92 currentTime = endingTime; 93 94 return runCount > 0; 95 } 96 97 public boolean runOneTask() { 98 if (enqueuedTaskCount() < 1) { 99 return false; 100 } 101 102 PostedRunnable postedRunnable = postedRunnables.remove(0); 103 currentTime = postedRunnable.scheduledTime; 104 postedRunnable.run(); 105 return true; 106 } 107 108 public boolean runTasks(int howMany) { 109 if (enqueuedTaskCount() < howMany) { 110 return false; 111 } 112 113 while (howMany > 0) { 114 PostedRunnable postedRunnable = postedRunnables.remove(0); 115 currentTime = postedRunnable.scheduledTime; 116 postedRunnable.run(); 117 howMany--; 118 } 119 return true; 120 } 121 122 public int enqueuedTaskCount() { 123 return postedRunnables.size(); 124 } 125 126 public boolean areAnyRunnable() { 127 return nextTaskIsScheduledBefore(currentTime); 128 } 129 130 public void reset() { 131 postedRunnables.clear(); 132 paused = false; 133 } 134 135 public int size() { 136 return postedRunnables.size(); 137 } 138 139 class PostedRunnable implements Comparable<PostedRunnable> { 140 Runnable runnable; 141 long scheduledTime; 142 143 PostedRunnable(Runnable runnable, long scheduledTime) { 144 this.runnable = runnable; 145 this.scheduledTime = scheduledTime; 146 } 147 148 @Override 149 public int compareTo(PostedRunnable postedRunnable) { 150 return (int) (scheduledTime - postedRunnable.scheduledTime); 151 } 152 153 public void run() { 154 runnable.run(); 155 } 156 } 157 158 private boolean nextTaskIsScheduledBefore(long endingTime) { 159 return enqueuedTaskCount() > 0 && postedRunnables.get(0).scheduledTime <= endingTime; 160 } 161} 162