/* * 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.launcher3; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import com.android.launcher3.util.Thunk; import java.util.LinkedList; /** * 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 { @Thunk LinkedList mQueue = new LinkedList<>(); private MessageQueue mMessageQueue = Looper.myQueue(); private Impl mHandler = new Impl(); @Thunk class Impl extends Handler implements MessageQueue.IdleHandler { public void handleMessage(Message msg) { Runnable r; synchronized (mQueue) { if (mQueue.size() == 0) { return; } r = mQueue.removeFirst(); } 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) { synchronized (mQueue) { mQueue.add(runnable); if (mQueue.size() == 1) { scheduleNextLocked(); } } } /** Schedule runnable to run when the queue goes idle. */ public void postIdle(final Runnable runnable) { post(new IdleRunnable(runnable)); } public void cancelAll() { 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 (Runnable r : queue) { r.run(); } } void scheduleNextLocked() { if (mQueue.size() > 0) { Runnable peek = mQueue.getFirst(); if (peek instanceof IdleRunnable) { mMessageQueue.addIdleHandler(mHandler); } else { mHandler.sendEmptyMessage(1); } } } }