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.base.Function; 20 import com.google.common.base.Supplier; 21 import com.google.common.collect.ImmutableList; 22 23 import java.util.ArrayList; 24 import java.util.List; 25 import java.util.concurrent.Executor; 26 27 import javax.annotation.CheckReturnValue; 28 import javax.annotation.Nonnull; 29 import javax.annotation.ParametersAreNonnullByDefault; 30 import javax.annotation.concurrent.ThreadSafe; 31 32 /** 33 * Enables combining multiple {@link Observable}s together with a given 34 * function. 35 * <p> 36 * Callbacks added to the resulting observable are notified when any of the 37 * dependencies change. 38 */ 39 @ThreadSafe 40 @ParametersAreNonnullByDefault 41 final class ObservableCombiner<T> implements Observable<T> { 42 private final ImmutableList<Observable<?>> mInputs; 43 private final Supplier<T> mOutput; 44 45 private ObservableCombiner(List<? extends Observable<?>> inputs, 46 Supplier<T> output) { 47 mInputs = ImmutableList.copyOf(inputs); 48 mOutput = output; 49 } 50 51 /** 52 * Transforms a set of input observables with a function. 53 * 54 * @param inputs The input observables. 55 * @param function The function to apply to all of the inputs. 56 * @param <I> The type of all inputs values. 57 * @param <O> The type of the output values. 58 * @return An observable which will reflect the combination of all inputs 59 * with the given function. Changes in the output value will result 60 * in calls to any callbacks registered with the output. 61 */ 62 static <I, O> Observable<O> transform(final List<? extends Observable<I>> inputs, 63 final Function<List<I>, O> function) { 64 return new ObservableCombiner<>(inputs, new Supplier<O>() { 65 @Override 66 public O get() { 67 ArrayList<I> deps = new ArrayList<>(); 68 for (Observable<? extends I> dependency : inputs) { 69 deps.add(dependency.get()); 70 } 71 return function.apply(deps); 72 } 73 }); 74 } 75 76 static <O> Observable<O> transform(final List<? extends Observable<?>> inputs, 77 final Supplier<O> output) { 78 return new ObservableCombiner<>(inputs, output); 79 } 80 81 @Nonnull 82 @Override 83 @CheckReturnValue 84 public SafeCloseable addCallback(Runnable callback, Executor executor) { 85 Lifetime callbackLifetime = new Lifetime(); 86 87 for (Observable<?> input : mInputs) { 88 callbackLifetime.add(input.addCallback(callback, executor)); 89 } 90 91 return callbackLifetime; 92 } 93 94 @Nonnull 95 @Override 96 public T get() { 97 return mOutput.get(); 98 } 99 } 100