1 /*
2  * Copyright (C) 2014 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.camera.async;
18 
19 import java.util.concurrent.Executor;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
23 
24 /**
25  * An executor which executes with a delay, discarding pending executions such
26  * that at most one task is queued at any time.
27  */
28 public class ResettingDelayedExecutor implements Executor, SafeCloseable {
29     private final ScheduledExecutorService mExecutor;
30     private final long mDelay;
31     private final TimeUnit mDelayUnit;
32     /**
33      * Lock for all mutable state: {@link #mLatestRunRequest} and
34      * {@link #mClosed}.
35      */
36     private final Object mLock;
37     private ScheduledFuture<?> mLatestRunRequest;
38     private boolean mClosed;
39 
ResettingDelayedExecutor(ScheduledExecutorService executor, long delay, TimeUnit delayUnit)40     public ResettingDelayedExecutor(ScheduledExecutorService executor, long delay, TimeUnit
41             delayUnit) {
42         mExecutor = executor;
43         mDelay = delay;
44         mDelayUnit = delayUnit;
45         mLock = new Object();
46         mClosed = false;
47     }
48 
49     /**
50      * Resets any pending executions.
51      */
reset()52     public void reset() {
53         synchronized (mLock) {
54             // Cancel any existing, queued task before scheduling another.
55             if (mLatestRunRequest != null) {
56                 mLatestRunRequest.cancel(false /* mayInterruptIfRunning */);
57             }
58         }
59     }
60 
61     @Override
execute(Runnable runnable)62     public void execute(Runnable runnable) {
63         synchronized (mLock) {
64             if (mClosed) {
65                 return;
66             }
67             reset();
68             mLatestRunRequest = mExecutor.schedule(runnable, mDelay, mDelayUnit);
69         }
70     }
71 
72     @Override
close()73     public void close() {
74         synchronized (mLock) {
75             if (mClosed) {
76                 return;
77             }
78             mClosed = true;
79             mExecutor.shutdownNow();
80         }
81     }
82 }
83