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 17 package com.android.launcher3; 18 19 import android.os.Handler; 20 import android.os.Looper; 21 import android.os.Message; 22 import android.os.MessageQueue; 23 import android.util.Pair; 24 25 import java.util.LinkedList; 26 import 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 */ 35 public 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