1a2043a8fff01f3e2d9a5e30dd1cf5fb6a5342f4dTyler Schultzpackage com.xtremelabs.robolectric.util;
2f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
3f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillipsimport java.util.ArrayList;
4f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillipsimport java.util.Collections;
5f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillipsimport java.util.List;
6e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwireimport java.util.ListIterator;
7f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
8f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillipspublic class Scheduler {
9f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    private List<PostedRunnable> postedRunnables = new ArrayList<PostedRunnable>();
10f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    private long currentTime = 0;
11b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz    private boolean paused = false;
12b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz
13ac0c93f1c8ad77266671707889f56bea3770cd6fPhil Plante & Ryan Richard    public long getCurrentTime() {
14ac0c93f1c8ad77266671707889f56bea3770cd6fPhil Plante & Ryan Richard        return currentTime;
15ac0c93f1c8ad77266671707889f56bea3770cd6fPhil Plante & Ryan Richard    }
16b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz
17b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz    public void pause() {
18b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz        paused = true;
19b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz    }
20b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz
21b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz    public void unPause() {
22b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz        paused = false;
23b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz        advanceToLastPostedRunnable();
24b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz    }
25f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
26a4f7d50f8e6f12d541421383544fe16c185e4bbcPhil Goodwin & Tyler Schultz    public boolean isPaused() {
27a4f7d50f8e6f12d541421383544fe16c185e4bbcPhil Goodwin & Tyler Schultz        return paused;
28a4f7d50f8e6f12d541421383544fe16c185e4bbcPhil Goodwin & Tyler Schultz    }
29a4f7d50f8e6f12d541421383544fe16c185e4bbcPhil Goodwin & Tyler Schultz
30f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    public void postDelayed(Runnable runnable, long delayMillis) {
31b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz        if (paused || delayMillis > 0) {
32b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz            postedRunnables.add(new PostedRunnable(runnable, currentTime + delayMillis));
33b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz            Collections.sort(postedRunnables);
34b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz        } else {
35b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz            runnable.run();
36b54505e42361f87b8ba24a785ae257f7d15feb2fPhil Goodwin & Tyler Schultz        }
37f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    }
38f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
39f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    public void post(Runnable runnable) {
40f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        postDelayed(runnable, 0);
41f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    }
42f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
43478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky    public void postAtFrontOfQueue(Runnable runnable) {
44478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky        if (paused) {
45478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky            postedRunnables.add(0, new PostedRunnable(runnable, currentTime));
46478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky        } else {
47478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky            runnable.run();
48478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky        }
49478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky    }
50478a40ed43134ef1568a19ab5233a5736a21c57bGlenn Jahnke & Lenny Turetsky
51e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire    public void remove(Runnable runnable) {
52e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire        ListIterator<PostedRunnable> iterator = postedRunnables.listIterator();
53e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire        while (iterator.hasNext()) {
54e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire            PostedRunnable next = iterator.next();
55e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire            if (next.runnable == runnable) {
56e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire                iterator.remove();
57e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire            }
58e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire        }
59e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire    }
60e2c2daa717063899e30b0cafd4d81e60a36d6b0fpivotal-jiwire
61f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    public boolean advanceToLastPostedRunnable() {
62f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        if (enqueuedTaskCount() < 1) {
63f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz            return false;
64f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        }
659c19f7ef7122cfa9e03ed4314da4ad2a115c7e71Christian Williams & Ryan Richard
66f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        return advanceTo(postedRunnables.get(postedRunnables.size() - 1).scheduledTime);
67f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    }
68f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz
69f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    public boolean advanceToNextPostedRunnable() {
70f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        if (enqueuedTaskCount() < 1) {
71f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz            return false;
72f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        }
73f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz
74f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        return advanceTo(postedRunnables.get(0).scheduledTime);
75f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    }
76f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
77f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    public boolean advanceBy(long intervalMs) {
78f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        long endingTime = currentTime + intervalMs;
79f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        return advanceTo(endingTime);
80f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    }
81f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
82f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    public boolean advanceTo(long endingTime) {
83f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        if (endingTime - currentTime < 0 || enqueuedTaskCount() < 1) {
84f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz            return false;
85f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        }
86f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
87f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        int runCount = 0;
88f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        while (nextTaskIsScheduledBefore(endingTime)) {
89f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz            runOneTask();
90f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz            ++runCount;
91f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        }
92f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        currentTime = endingTime;
93f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
94f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        return runCount > 0;
95f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    }
969c19f7ef7122cfa9e03ed4314da4ad2a115c7e71Christian Williams & Ryan Richard
97f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    public boolean runOneTask() {
98f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        if (enqueuedTaskCount() < 1) {
99f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz            return false;
100f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        }
101f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz
102f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        PostedRunnable postedRunnable = postedRunnables.remove(0);
103f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        currentTime = postedRunnable.scheduledTime;
104f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        postedRunnable.run();
105f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        return true;
106f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    }
107f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
108ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard    public boolean runTasks(int howMany) {
109ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard        if (enqueuedTaskCount() < howMany) {
110ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard            return false;
111ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard        }
112ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard
113ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard        while (howMany > 0) {
114ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard            PostedRunnable postedRunnable = postedRunnables.remove(0);
115ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard            currentTime = postedRunnable.scheduledTime;
116ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard            postedRunnable.run();
117ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard            howMany--;
118ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard        }
119ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard        return true;
120ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard    }
121ac15c9cd601029fa6af0045cec61a748d55f54c9Lowell Kirsh & Ryan Richard
122f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    public int enqueuedTaskCount() {
123f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        return postedRunnables.size();
124f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    }
125f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
126006d40b0d212332682a30c80eb733a006455a4e7Phil Goodwin & Tyler Schultz    public boolean areAnyRunnable() {
127006d40b0d212332682a30c80eb733a006455a4e7Phil Goodwin & Tyler Schultz        return nextTaskIsScheduledBefore(currentTime);
128006d40b0d212332682a30c80eb733a006455a4e7Phil Goodwin & Tyler Schultz    }
129006d40b0d212332682a30c80eb733a006455a4e7Phil Goodwin & Tyler Schultz
130abde7367c1c6a322c18803941e9118b1daea35fbChristian Williams    public void reset() {
131abde7367c1c6a322c18803941e9118b1daea35fbChristian Williams        postedRunnables.clear();
132a4f7d50f8e6f12d541421383544fe16c185e4bbcPhil Goodwin & Tyler Schultz        paused = false;
133abde7367c1c6a322c18803941e9118b1daea35fbChristian Williams    }
134abde7367c1c6a322c18803941e9118b1daea35fbChristian Williams
135183675aba2229b620cc04156d5dbc5d95703b09eGlenn Jahnke & Phil Plante    public int size() {
136183675aba2229b620cc04156d5dbc5d95703b09eGlenn Jahnke & Phil Plante        return postedRunnables.size();
137183675aba2229b620cc04156d5dbc5d95703b09eGlenn Jahnke & Phil Plante    }
138183675aba2229b620cc04156d5dbc5d95703b09eGlenn Jahnke & Phil Plante
139f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    class PostedRunnable implements Comparable<PostedRunnable> {
140f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        Runnable runnable;
141f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        long scheduledTime;
142f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
143f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        PostedRunnable(Runnable runnable, long scheduledTime) {
144f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips            this.runnable = runnable;
145f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips            this.scheduledTime = scheduledTime;
146f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        }
147f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
148f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        @Override
149f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        public int compareTo(PostedRunnable postedRunnable) {
150f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips            return (int) (scheduledTime - postedRunnable.scheduledTime);
151f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        }
152f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips
153f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        public void run() {
154f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips            runnable.run();
155f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips        }
156f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips    }
157f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz
158f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    private boolean nextTaskIsScheduledBefore(long endingTime) {
159f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz        return enqueuedTaskCount() > 0 && postedRunnables.get(0).scheduledTime <= endingTime;
160f7c3a47b5eb49f49f450eb18822d51dc496fceefPhil Goodwin & Tyler Schultz    }
161f8d3ea0e4553f6f391543eccb99485f9603c5804Christian Williams & Jay Phillips}
162