1 // Copyright 2016 Google Inc. All Rights Reserved. 2 package com.android.contacts.util.concurrent; 3 4 import android.os.Handler; 5 6 import com.google.common.util.concurrent.AsyncFunction; 7 import com.google.common.util.concurrent.Futures; 8 import com.google.common.util.concurrent.ListenableFuture; 9 import com.google.common.util.concurrent.MoreExecutors; 10 11 import java.util.concurrent.CancellationException; 12 import java.util.concurrent.ScheduledExecutorService; 13 import java.util.concurrent.TimeUnit; 14 import java.util.concurrent.TimeoutException; 15 import java.util.concurrent.atomic.AtomicBoolean; 16 17 /** 18 * Has utility methods for operating on ListenableFutures 19 */ 20 public class FuturesUtil { 21 22 /** 23 * See 24 * {@link FuturesUtil#withTimeout(ListenableFuture, long, TimeUnit, ScheduledExecutorService)} 25 */ withTimeout(final ListenableFuture<V> future, long time, TimeUnit unit, Handler handler)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 */ withTimeout(final ListenableFuture<V> future, long time, TimeUnit unit, ScheduledExecutorService executor)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 50 return Futures.catchingAsync(future, Throwable.class, new AsyncFunction<Throwable, V>() { 51 @Override 52 public ListenableFuture<V> apply(Throwable t) throws Exception { 53 if ((t instanceof CancellationException) && didTimeout.get()) { 54 return Futures.immediateFailedFuture(new TimeoutException("Timeout expired")); 55 } 56 return Futures.immediateFailedFuture(t); 57 } 58 }, MoreExecutors.directExecutor()); 59 } 60 } 61