1 /*
2  * Copyright (C) 2015 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.device;
18 
19 import com.android.camera.async.Lifetime;
20 import com.android.camera.async.SafeCloseable;
21 import com.google.common.util.concurrent.ListenableFuture;
22 import com.google.common.util.concurrent.SettableFuture;
23 
24 import java.util.concurrent.atomic.AtomicBoolean;
25 
26 import javax.annotation.concurrent.ThreadSafe;
27 
28 /**
29  * ThreadSafe class to deal with the combined future and lifetime
30  * for a single device request.
31  */
32 @ThreadSafe
33 public class SingleDeviceRequest<TDevice> implements SafeCloseable {
34     private final SettableFuture<TDevice> mFuture;
35     private final Lifetime mLifetime;
36     private final AtomicBoolean mIsClosed;
37 
SingleDeviceRequest(Lifetime lifetime)38     public SingleDeviceRequest(Lifetime lifetime) {
39         mLifetime = lifetime;
40         mFuture = SettableFuture.create();
41         mIsClosed = new AtomicBoolean(false);
42     }
43 
44     /**
45      * Return the future instance for this request.
46      */
getFuture()47     public ListenableFuture<TDevice> getFuture() {
48         return mFuture;
49     }
50 
51     /**
52      * Return the lifetime instance for this request.
53      */
getLifetime()54     public Lifetime getLifetime() {
55         return mLifetime;
56     }
57 
58     /**
59      * If the future has not been set, set the value.
60      */
set(TDevice device)61     public boolean set(TDevice device) {
62         if (!mIsClosed.get()) {
63             return mFuture.set(device);
64         } else {
65             return false;
66         }
67     }
68 
isClosed()69     public boolean isClosed() {
70         return mIsClosed.get();
71     }
72 
closeWithException(Throwable throwable)73     public void closeWithException(Throwable throwable) {
74         if (!mIsClosed.getAndSet(true)) {
75             mFuture.setException(throwable);
76             mLifetime.close();
77         }
78     }
79 
80     @Override
close()81     public void close() {
82         if (!mIsClosed.getAndSet(true)) {
83             mFuture.cancel(true /* mayInterruptIfRunning */);
84             mLifetime.close();
85         }
86     }
87 }
88