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