blob: ba724468e6aa2bee5b3e6e0ef7362330c394a075 [file] [log] [blame]
Marcus Hagerotta89f5232016-12-07 10:04:00 -08001// Copyright 2016 Google Inc. All Rights Reserved.
2package com.android.contacts.util.concurrent;
3
4import android.os.Handler;
5
Colin Crossa7987012019-04-11 14:32:53 -07006import com.google.common.util.concurrent.AsyncFunction;
Marcus Hagerotta89f5232016-12-07 10:04:00 -08007import com.google.common.util.concurrent.Futures;
8import com.google.common.util.concurrent.ListenableFuture;
Colin Crossa7987012019-04-11 14:32:53 -07009import com.google.common.util.concurrent.MoreExecutors;
Marcus Hagerotta89f5232016-12-07 10:04:00 -080010
11import java.util.concurrent.CancellationException;
12import java.util.concurrent.ScheduledExecutorService;
13import java.util.concurrent.TimeUnit;
14import java.util.concurrent.TimeoutException;
15import java.util.concurrent.atomic.AtomicBoolean;
16
17/**
18 * Has utility methods for operating on ListenableFutures
19 */
20public class FuturesUtil {
21
22 /**
23 * See
24 * {@link FuturesUtil#withTimeout(ListenableFuture, long, TimeUnit, ScheduledExecutorService)}
25 */
26 public static <V> ListenableFuture<V> withTimeout(final ListenableFuture<V> future, long time,
27 TimeUnit unit, Handler handler) {
28 return withTimeout(future, time, unit, ContactsExecutors.newHandlerExecutor(handler));
29 }
30
31 /**
32 * Returns a future that completes with the result from the input future unless the specified
33 * time elapses before it finishes in which case the result will contain a TimeoutException and
34 * the input future will be canceled.
35 *
36 * <p>Guava has Futures.withTimeout but it isn't available until v19.0 and we depend on v14.0
37 * right now. Replace usages of this method if we upgrade our dependency.</p>
38 */
39 public static <V> ListenableFuture<V> withTimeout(final ListenableFuture<V> future, long time,
40 TimeUnit unit, ScheduledExecutorService executor) {
41 final AtomicBoolean didTimeout = new AtomicBoolean(false);
42 executor.schedule(new Runnable() {
43 @Override
44 public void run() {
45 didTimeout.set(!future.isDone() && !future.isCancelled());
46 future.cancel(true);
47 }
48 }, time, unit);
49
Colin Crossa7987012019-04-11 14:32:53 -070050 return Futures.catchingAsync(future, Throwable.class, new AsyncFunction<Throwable, V>() {
Marcus Hagerotta89f5232016-12-07 10:04:00 -080051 @Override
Colin Crossa7987012019-04-11 14:32:53 -070052 public ListenableFuture<V> apply(Throwable t) throws Exception {
Marcus Hagerotta89f5232016-12-07 10:04:00 -080053 if ((t instanceof CancellationException) && didTimeout.get()) {
54 return Futures.immediateFailedFuture(new TimeoutException("Timeout expired"));
55 }
56 return Futures.immediateFailedFuture(t);
57 }
Colin Crossa7987012019-04-11 14:32:53 -070058 }, MoreExecutors.directExecutor());
Marcus Hagerotta89f5232016-12-07 10:04:00 -080059 }
60}