/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.camera.async; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.ForwardingListenableFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.List; import javax.annotation.Nullable; /** * TODO Replace with Guava's com.google.common.util.concurrent.Futures once we * can build with v. 15+ */ public class Futures2 { /** * 2 parameter async function for joined async results. */ public interface AsyncFunction2<T1, T2, TResult> { ListenableFuture<TResult> apply(T1 value1, T2 value2) throws Exception; } /** * 3 parameter async function for joined async results. */ public interface AsyncFunction3<T1, T2, T3, TResult> { ListenableFuture<TResult> apply(T1 value1, T2 value2, T3 value3) throws Exception; } /** * 2 parameter function for joining multiple results into a single value. */ public interface Function2<T1, T2, TResult> { TResult apply(T1 value1, T2 value2); } /** * 3 parameter function for joining multiple results into a single value. */ public interface Function3<T1, T2, T3, TResult> { TResult apply(T1 value1, T2 value2, T3 value3); } private Futures2() { } /** * Creates a new ListenableFuture whose result is set from the supplied * future when it completes. Cancelling the supplied future will also cancel * the returned future, but cancelling the returned future will have no * effect on the supplied future. */ public static <T> ListenableFuture<T> nonCancellationPropagating( final ListenableFuture<T> future) { return new ForwardingListenableFuture.SimpleForwardingListenableFuture<T>(future) { @Override public boolean cancel(boolean mayInterruptIfNecessary) { return false; } }; } /** * Create a new joined future from two existing futures and a joining function * that combines the resulting outputs of the previous functions into a single * result. The resulting future will fail if any of the dependent futures also * fail. */ public static <T1, T2, TResult> ListenableFuture<TResult> joinAll( final ListenableFuture<T1> f1, final ListenableFuture<T2> f2, final AsyncFunction2<T1, T2, TResult> fn) { ListenableFuture<?>[] futures = new ListenableFuture<?>[2]; futures[0] = f1; futures[1] = f2; // Futures.allAsList is used instead of Futures.successfulAsList because // allAsList will propagate the failures instead of null values to the // parameters of the supplied function. ListenableFuture<List<Object>> result = Futures.<Object>allAsList(futures); return Futures.transformAsync(result, new AsyncFunction<List<Object>, TResult>() { @Override public ListenableFuture<TResult> apply(@Nullable List<Object> list) throws Exception { T1 value1 = (T1) list.get(0); T2 value2 = (T2) list.get(1); return fn.apply(value1, value2); } }, MoreExecutors.directExecutor()); } /** * Create a new joined future from two existing futures and an async function * that combines the resulting outputs of the previous functions into a single * result. The resulting future will fail if any of the dependent futures also * fail. */ public static <T1, T2, TResult> ListenableFuture<TResult> joinAll( final ListenableFuture<T1> f1, final ListenableFuture<T2> f2, final Function2<T1, T2, TResult> fn) { return joinAll(f1, f2, new ImmediateAsyncFunction2<>(fn)); } /** * Create a new joined future from three existing futures and a joining function * that combines the resulting outputs of the previous functions into a single * result. The resulting future will fail if any of the dependent futures also * fail. */ public static <T1, T2, T3, TResult> ListenableFuture<TResult> joinAll( final ListenableFuture<T1> f1, final ListenableFuture<T2> f2, final ListenableFuture<T3> f3, final AsyncFunction3<T1, T2, T3, TResult> fn) { ListenableFuture<?>[] futures = new ListenableFuture<?>[3]; futures[0] = f1; futures[1] = f2; futures[2] = f3; // Futures.allAsList is used instead of Futures.successfulAsList because // allAsList will propagate the failures instead of null values to the // parameters of the supplied function. ListenableFuture<List<Object>> result = Futures.<Object>allAsList(futures); return Futures.transformAsync(result, new AsyncFunction<List<Object>, TResult>() { @Override public ListenableFuture<TResult> apply(@Nullable List<Object> list) throws Exception { T1 value1 = (T1) list.get(0); T2 value2 = (T2) list.get(1); T3 value3 = (T3) list.get(2); return fn.apply(value1, value2, value3); } }, MoreExecutors.directExecutor()); } /** * Create a new joined future from three existing futures and an async function * that combines the resulting outputs of the previous functions into a single * result. The resulting future will fail if any of the dependent futures also * fail. */ public static <T1, T2, T3, TResult> ListenableFuture<TResult> joinAll( final ListenableFuture<T1> f1, final ListenableFuture<T2> f2, final ListenableFuture<T3> f3, final Function3<T1, T2, T3, TResult> fn) { return joinAll(f1, f2, f3, new ImmediateAsyncFunction3<>(fn)); } /** * Wrapper class for turning a Function2 into an AsyncFunction2 by returning * an immediate future when the function is applied. */ private static final class ImmediateAsyncFunction2<T1, T2, TResult> implements AsyncFunction2<T1, T2, TResult> { private final Function2<T1, T2, TResult> mFn; public ImmediateAsyncFunction2(Function2<T1, T2, TResult> fn) { mFn = fn; } @Override public ListenableFuture<TResult> apply(T1 value1, T2 value2) throws Exception { return Futures.immediateFuture(mFn.apply(value1, value2)); } } /** * Wrapper class for turning a Function3 into an AsyncFunction3 by returning * an immediate future when the function is applied. */ private static final class ImmediateAsyncFunction3<T1, T2, T3, TResult> implements AsyncFunction3<T1, T2, T3, TResult> { private final Function3<T1, T2, T3, TResult> mFn; public ImmediateAsyncFunction3(Function3<T1, T2, T3, TResult> fn) { mFn = fn; } @Override public ListenableFuture<TResult> apply(T1 value1, T2 value2, T3 value3) throws Exception { return Futures.immediateFuture(mFn.apply(value1, value2, value3)); } } }