/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher2; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.util.Pair; import java.util.LinkedList; import java.util.ListIterator; /** * Queue of things to run on a looper thread. Items posted with {@link #post} will not * be actually enqued on the handler until after the last one has run, to keep from * starving the thread. * * This class is fifo. */ public class DeferredHandler { private LinkedList> mQueue = new LinkedList>(); private MessageQueue mMessageQueue = Looper.myQueue(); private Impl mHandler = new Impl(); private class Impl extends Handler implements MessageQueue.IdleHandler { public void handleMessage(Message msg) { Pair p; Runnable r; synchronized (mQueue) { if (mQueue.size() == 0) { return; } p = mQueue.removeFirst(); r = p.first; } r.run(); synchronized (mQueue) { scheduleNextLocked(); } } public boolean queueIdle() { handleMessage(null); return false; } } private class IdleRunnable implements Runnable { Runnable mRunnable; IdleRunnable(Runnable r) { mRunnable = r; } public void run() { mRunnable.run(); } } public DeferredHandler() { } /** Schedule runnable to run after everything that's on the queue right now. */ public void post(Runnable runnable) { post(runnable, 0); } public void post(Runnable runnable, int type) { synchronized (mQueue) { mQueue.add(new Pair(runnable, type)); if (mQueue.size() == 1) { scheduleNextLocked(); } } } /** Schedule runnable to run when the queue goes idle. */ public void postIdle(final Runnable runnable) { postIdle(runnable, 0); } public void postIdle(final Runnable runnable, int type) { post(new IdleRunnable(runnable), type); } public void cancelRunnable(Runnable runnable) { synchronized (mQueue) { while (mQueue.remove(runnable)) { } } } public void cancelAllRunnablesOfType(int type) { synchronized (mQueue) { ListIterator> iter = mQueue.listIterator(); Pair p; while (iter.hasNext()) { p = iter.next(); if (p.second == type) { iter.remove(); } } } } public void cancel() { synchronized (mQueue) { mQueue.clear(); } } /** Runs all queued Runnables from the calling thread. */ public void flush() { LinkedList> queue = new LinkedList>(); synchronized (mQueue) { queue.addAll(mQueue); mQueue.clear(); } for (Pair p : queue) { p.first.run(); } } void scheduleNextLocked() { if (mQueue.size() > 0) { Pair p = mQueue.getFirst(); Runnable peek = p.first; if (peek instanceof IdleRunnable) { mMessageQueue.addIdleHandler(mHandler); } else { mHandler.sendEmptyMessage(1); } } } }