1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.launcher2;
18
19import android.os.Handler;
20import android.os.Looper;
21import android.os.Message;
22import android.os.MessageQueue;
23import android.util.Pair;
24import java.util.LinkedList;
25import java.util.ListIterator;
26
27/**
28 * Queue of things to run on a looper thread.  Items posted with {@link #post} will not
29 * be actually enqued on the handler until after the last one has run, to keep from
30 * starving the thread.
31 *
32 * This class is fifo.
33 */
34public class DeferredHandler {
35    private LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
36    private MessageQueue mMessageQueue = Looper.myQueue();
37    private Impl mHandler = new Impl();
38
39    private class Impl extends Handler implements MessageQueue.IdleHandler {
40        public void handleMessage(Message msg) {
41            Pair<Runnable, Integer> p;
42            Runnable r;
43            synchronized (mQueue) {
44                if (mQueue.size() == 0) {
45                    return;
46                }
47                p = mQueue.removeFirst();
48                r = p.first;
49            }
50            r.run();
51            synchronized (mQueue) {
52                scheduleNextLocked();
53            }
54        }
55
56        public boolean queueIdle() {
57            handleMessage(null);
58            return false;
59        }
60    }
61
62    private class IdleRunnable implements Runnable {
63        Runnable mRunnable;
64
65        IdleRunnable(Runnable r) {
66            mRunnable = r;
67        }
68
69        public void run() {
70            mRunnable.run();
71        }
72    }
73
74    public DeferredHandler() {
75    }
76
77    /** Schedule runnable to run after everything that's on the queue right now. */
78    public void post(Runnable runnable) {
79        post(runnable, 0);
80    }
81    public void post(Runnable runnable, int type) {
82        synchronized (mQueue) {
83            mQueue.add(new Pair<Runnable, Integer>(runnable, type));
84            if (mQueue.size() == 1) {
85                scheduleNextLocked();
86            }
87        }
88    }
89
90    /** Schedule runnable to run when the queue goes idle. */
91    public void postIdle(final Runnable runnable) {
92        postIdle(runnable, 0);
93    }
94    public void postIdle(final Runnable runnable, int type) {
95        post(new IdleRunnable(runnable), type);
96    }
97
98    public void cancelRunnable(Runnable runnable) {
99        synchronized (mQueue) {
100            while (mQueue.remove(runnable)) { }
101        }
102    }
103    public void cancelAllRunnablesOfType(int type) {
104        synchronized (mQueue) {
105            ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator();
106            Pair<Runnable, Integer> p;
107            while (iter.hasNext()) {
108                p = iter.next();
109                if (p.second == type) {
110                    iter.remove();
111                }
112            }
113        }
114    }
115
116    public void cancel() {
117        synchronized (mQueue) {
118            mQueue.clear();
119        }
120    }
121
122    /** Runs all queued Runnables from the calling thread. */
123    public void flush() {
124        LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>();
125        synchronized (mQueue) {
126            queue.addAll(mQueue);
127            mQueue.clear();
128        }
129        for (Pair<Runnable, Integer> p : queue) {
130            p.first.run();
131        }
132    }
133
134    void scheduleNextLocked() {
135        if (mQueue.size() > 0) {
136            Pair<Runnable, Integer> p = mQueue.getFirst();
137            Runnable peek = p.first;
138            if (peek instanceof IdleRunnable) {
139                mMessageQueue.addIdleHandler(mHandler);
140            } else {
141                mHandler.sendEmptyMessage(1);
142            }
143        }
144    }
145}
146
147