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.async; 18 19 import com.google.common.util.concurrent.AsyncFunction; 20 import com.google.common.util.concurrent.ForwardingListenableFuture; 21 import com.google.common.util.concurrent.Futures; 22 import com.google.common.util.concurrent.ListenableFuture; 23 import com.google.common.util.concurrent.MoreExecutors; 24 25 import java.util.List; 26 27 import javax.annotation.Nullable; 28 29 /** 30 * TODO Replace with Guava's com.google.common.util.concurrent.Futures once we 31 * can build with v. 15+ 32 */ 33 public class Futures2 { 34 /** 35 * 2 parameter async function for joined async results. 36 */ 37 public interface AsyncFunction2<T1, T2, TResult> { apply(T1 value1, T2 value2)38 ListenableFuture<TResult> apply(T1 value1, T2 value2) throws Exception; 39 } 40 41 /** 42 * 3 parameter async function for joined async results. 43 */ 44 public interface AsyncFunction3<T1, T2, T3, TResult> { apply(T1 value1, T2 value2, T3 value3)45 ListenableFuture<TResult> apply(T1 value1, T2 value2, T3 value3) throws Exception; 46 } 47 48 /** 49 * 2 parameter function for joining multiple results into a single value. 50 */ 51 public interface Function2<T1, T2, TResult> { apply(T1 value1, T2 value2)52 TResult apply(T1 value1, T2 value2); 53 } 54 55 /** 56 * 3 parameter function for joining multiple results into a single value. 57 */ 58 public interface Function3<T1, T2, T3, TResult> { apply(T1 value1, T2 value2, T3 value3)59 TResult apply(T1 value1, T2 value2, T3 value3); 60 } 61 Futures2()62 private Futures2() { 63 } 64 65 /** 66 * Creates a new ListenableFuture whose result is set from the supplied 67 * future when it completes. Cancelling the supplied future will also cancel 68 * the returned future, but cancelling the returned future will have no 69 * effect on the supplied future. 70 */ nonCancellationPropagating( final ListenableFuture<T> future)71 public static <T> ListenableFuture<T> nonCancellationPropagating( 72 final ListenableFuture<T> future) { 73 return new ForwardingListenableFuture.SimpleForwardingListenableFuture<T>(future) { 74 @Override 75 public boolean cancel(boolean mayInterruptIfNecessary) { 76 return false; 77 } 78 }; 79 } 80 81 /** 82 * Create a new joined future from two existing futures and a joining function 83 * that combines the resulting outputs of the previous functions into a single 84 * result. The resulting future will fail if any of the dependent futures also 85 * fail. 86 */ 87 public static <T1, T2, TResult> ListenableFuture<TResult> joinAll( 88 final ListenableFuture<T1> f1, 89 final ListenableFuture<T2> f2, 90 final AsyncFunction2<T1, T2, TResult> fn) { 91 ListenableFuture<?>[] futures = new ListenableFuture<?>[2]; 92 93 futures[0] = f1; 94 futures[1] = f2; 95 96 // Futures.allAsList is used instead of Futures.successfulAsList because 97 // allAsList will propagate the failures instead of null values to the 98 // parameters of the supplied function. 99 ListenableFuture<List<Object>> result = Futures.<Object>allAsList(futures); 100 return Futures.transformAsync(result, new AsyncFunction<List<Object>, TResult>() { 101 @Override 102 public ListenableFuture<TResult> apply(@Nullable List<Object> list) throws Exception { 103 T1 value1 = (T1) list.get(0); 104 T2 value2 = (T2) list.get(1); 105 106 return fn.apply(value1, value2); 107 } 108 }, MoreExecutors.directExecutor()); 109 } 110 111 /** 112 * Create a new joined future from two existing futures and an async function 113 * that combines the resulting outputs of the previous functions into a single 114 * result. The resulting future will fail if any of the dependent futures also 115 * fail. 116 */ 117 public static <T1, T2, TResult> ListenableFuture<TResult> joinAll( 118 final ListenableFuture<T1> f1, 119 final ListenableFuture<T2> f2, 120 final Function2<T1, T2, TResult> fn) { 121 return joinAll(f1, f2, new ImmediateAsyncFunction2<>(fn)); 122 } 123 124 /** 125 * Create a new joined future from three existing futures and a joining function 126 * that combines the resulting outputs of the previous functions into a single 127 * result. The resulting future will fail if any of the dependent futures also 128 * fail. 129 */ 130 public static <T1, T2, T3, TResult> ListenableFuture<TResult> joinAll( 131 final ListenableFuture<T1> f1, 132 final ListenableFuture<T2> f2, 133 final ListenableFuture<T3> f3, 134 final AsyncFunction3<T1, T2, T3, TResult> fn) { 135 ListenableFuture<?>[] futures = new ListenableFuture<?>[3]; 136 137 futures[0] = f1; 138 futures[1] = f2; 139 futures[2] = f3; 140 141 // Futures.allAsList is used instead of Futures.successfulAsList because 142 // allAsList will propagate the failures instead of null values to the 143 // parameters of the supplied function. 144 ListenableFuture<List<Object>> result = Futures.<Object>allAsList(futures); 145 return Futures.transformAsync(result, new AsyncFunction<List<Object>, TResult>() { 146 @Override 147 public ListenableFuture<TResult> apply(@Nullable List<Object> list) throws Exception { 148 T1 value1 = (T1) list.get(0); 149 T2 value2 = (T2) list.get(1); 150 T3 value3 = (T3) list.get(2); 151 152 return fn.apply(value1, value2, value3); 153 } 154 }, MoreExecutors.directExecutor()); 155 } 156 157 /** 158 * Create a new joined future from three existing futures and an async function 159 * that combines the resulting outputs of the previous functions into a single 160 * result. The resulting future will fail if any of the dependent futures also 161 * fail. 162 */ 163 public static <T1, T2, T3, TResult> ListenableFuture<TResult> joinAll( 164 final ListenableFuture<T1> f1, 165 final ListenableFuture<T2> f2, 166 final ListenableFuture<T3> f3, 167 final Function3<T1, T2, T3, TResult> fn) { 168 return joinAll(f1, f2, f3, new ImmediateAsyncFunction3<>(fn)); 169 } 170 171 /** 172 * Wrapper class for turning a Function2 into an AsyncFunction2 by returning 173 * an immediate future when the function is applied. 174 */ 175 private static final class ImmediateAsyncFunction2<T1, T2, TResult> implements 176 AsyncFunction2<T1, T2, TResult> { 177 private final Function2<T1, T2, TResult> mFn; 178 179 public ImmediateAsyncFunction2(Function2<T1, T2, TResult> fn) { 180 mFn = fn; 181 } 182 183 @Override 184 public ListenableFuture<TResult> apply(T1 value1, T2 value2) throws Exception { 185 return Futures.immediateFuture(mFn.apply(value1, value2)); 186 } 187 } 188 189 /** 190 * Wrapper class for turning a Function3 into an AsyncFunction3 by returning 191 * an immediate future when the function is applied. 192 */ 193 private static final class ImmediateAsyncFunction3<T1, T2, T3, TResult> implements 194 AsyncFunction3<T1, T2, T3, TResult> { 195 private final Function3<T1, T2, T3, TResult> mFn; 196 197 public ImmediateAsyncFunction3(Function3<T1, T2, T3, TResult> fn) { 198 mFn = fn; 199 } 200 201 @Override 202 public ListenableFuture<TResult> apply(T1 value1, T2 value2, T3 value3) throws Exception { 203 return Futures.immediateFuture(mFn.apply(value1, value2, value3)); 204 } 205 } 206 } 207