16b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki/*
26b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * Copyright (C) 2011 The Android Open Source Project
36b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki *
46b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
56b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * you may not use this file except in compliance with the License.
66b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * You may obtain a copy of the License at
76b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki *
86b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
96b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki *
106b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * Unless required by applicable law or agreed to in writing, software
116b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
126b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * See the License for the specific language governing permissions and
146b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * limitations under the License.
156b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki */
166b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
176b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onukipackage com.android.emailcommon.utility;
186b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
196b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onukiimport com.google.common.annotations.VisibleForTesting;
206b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
216b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onukiimport android.os.Handler;
226b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
236b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onukiimport java.util.ArrayList;
246b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onukiimport java.util.LinkedList;
256b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
266b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki/**
276b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * Class that helps post {@link Runnable}s to a {@link Handler}, and cancel pending ones
286b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki * at once.
296b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki */
306b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onukipublic class DelayedOperations {
316b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    private final Handler mHandler;
326b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
336b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    @VisibleForTesting
346b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    final LinkedList<QueuedOperation> mPendingOperations = new LinkedList<QueuedOperation>();
356b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
366b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    private class QueuedOperation implements Runnable {
376b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        private final Runnable mActualRannable;
386b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
396b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        public QueuedOperation(Runnable actualRannable) {
406b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            mActualRannable = actualRannable;
416b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        }
426b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
436b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        @Override
446b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        public void run() {
456b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            mPendingOperations.remove(this);
466b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            mActualRannable.run();
476b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        }
486b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
496b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        public void cancel() {
506b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            mPendingOperations.remove(this);
516b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            cancelRunnable(this);
526b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        }
536b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
546b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
556b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    public DelayedOperations(Handler handler) {
566b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        mHandler = handler;
576b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
586b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
596b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    /**
606b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     * Post a {@link Runnable} to the handler.  Equivalent to {@link Handler#post(Runnable)}.
616b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     */
626b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    public void post(Runnable r) {
636b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        final QueuedOperation qo = new QueuedOperation(r);
646b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        mPendingOperations.add(qo);
656b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        postRunnable(qo);
666b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
676b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
686b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    /**
696b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     * Cancel a runnable that's been posted with {@link #post(Runnable)}.
706b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     *
716b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     * Equivalent to {@link Handler#removeCallbacks(Runnable)}.
726b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     */
736b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    public void removeCallbacks(Runnable r) {
746b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        QueuedOperation found = null;
756b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        for (QueuedOperation qo : mPendingOperations) {
766b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            if (qo.mActualRannable == r) {
776b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki                found = qo;
786b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki                break;
796b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            }
806b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        }
816b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        if (found != null) {
826b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            found.cancel();
836b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        }
846b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
856b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
866b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    /**
876b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     * Cancel all pending {@link Runnable}s.
886b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki     */
896b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    public void removeCallbacks() {
906b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        // To avoid ConcurrentModificationException
916b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        final ArrayList<QueuedOperation> temp = new ArrayList<QueuedOperation>(mPendingOperations);
926b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        for (QueuedOperation qo : temp) {
936b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki            qo.cancel();
946b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        }
956b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
966b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
976b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    /** Overridden by test, as Handler is not mockable. */
986b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    void postRunnable(Runnable r) {
996b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        mHandler.post(r);
1006b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
1016b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki
1026b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    /** Overridden by test, as Handler is not mockable. */
1036b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    void cancelRunnable(Runnable r) {
1046b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki        mHandler.removeCallbacks(r);
1056b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki    }
1066b968c1dce3ba78680d968e04fc6f59bbbb22073Makoto Onuki}
107