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.launcher3;
18
19import android.os.Handler;
20import android.os.Looper;
21import android.os.Message;
22import android.os.MessageQueue;
23import android.util.Pair;
24
25import java.util.LinkedList;
26import java.util.ListIterator;
27
28/**
29 * Queue of things to run on a looper thread.  Items posted with {@link #post} will not
30 * be actually enqued on the handler until after the last one has run, to keep from
31 * starving the thread.
32 *
33 * This class is fifo.
34 */
35public class DeferredHandler {
36    private LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
37    private MessageQueue mMessageQueue = Looper.myQueue();
38    private Impl mHandler = new Impl();
39
40    private class Impl extends Handler implements MessageQueue.IdleHandler {
41        public void handleMessage(Message msg) {
42            Pair<Runnable, Integer> p;
43            Runnable r;
44            synchronized (mQueue) {
45                if (mQueue.size() == 0) {
46                    return;
47                }
48                p = mQueue.removeFirst();
49                r = p.first;
50            }
51            r.run();
52            synchronized (mQueue) {
53                scheduleNextLocked();
54            }
55        }
56
57        public boolean queueIdle() {
58            handleMessage(null);
59            return false;
60        }
61    }
62
63    private class IdleRunnable implements Runnable {
64        Runnable mRunnable;
65
66        IdleRunnable(Runnable r) {
67            mRunnable = r;
68        }
69
70        public void run() {
71            mRunnable.run();
72        }
73    }
74
75    public DeferredHandler() {
76    }
77
78    /** Schedule runnable to run after everything that's on the queue right now. */
79    public void post(Runnable runnable) {
80        post(runnable, 0);
81    }
82    public void post(Runnable runnable, int type) {
83        synchronized (mQueue) {
84            mQueue.add(new Pair<Runnable, Integer>(runnable, type));
85            if (mQueue.size() == 1) {
86                scheduleNextLocked();
87            }
88        }
89    }
90
91    /** Schedule runnable to run when the queue goes idle. */
92    public void postIdle(final Runnable runnable) {
93        postIdle(runnable, 0);
94    }
95    public void postIdle(final Runnable runnable, int type) {
96        post(new IdleRunnable(runnable), type);
97    }
98
99    public void cancelRunnable(Runnable runnable) {
100        synchronized (mQueue) {
101            while (mQueue.remove(runnable)) { }
102        }
103    }
104    public void cancelAllRunnablesOfType(int type) {
105        synchronized (mQueue) {
106            ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator();
107            Pair<Runnable, Integer> p;
108            while (iter.hasNext()) {
109                p = iter.next();
110                if (p.second == type) {
111                    iter.remove();
112                }
113            }
114        }
115    }
116
117    public void cancel() {
118        synchronized (mQueue) {
119            mQueue.clear();
120        }
121    }
122
123    /** Runs all queued Runnables from the calling thread. */
124    public void flush() {
125        LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>();
126        synchronized (mQueue) {
127            queue.addAll(mQueue);
128            mQueue.clear();
129        }
130        for (Pair<Runnable, Integer> p : queue) {
131            p.first.run();
132        }
133    }
134
135    void scheduleNextLocked() {
136        if (mQueue.size() > 0) {
137            Pair<Runnable, Integer> p = mQueue.getFirst();
138            Runnable peek = p.first;
139            if (peek instanceof IdleRunnable) {
140                mMessageQueue.addIdleHandler(mHandler);
141            } else {
142                mHandler.sendEmptyMessage(1);
143            }
144        }
145    }
146}
147
148