1e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall/*
2e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * Copyright (C) 2015 The Android Open Source Project
3e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall *
4e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * Licensed under the Apache License, Version 2.0 (the "License");
5e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * you may not use this file except in compliance with the License.
6e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * You may obtain a copy of the License at
7e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall *
8e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall *      http://www.apache.org/licenses/LICENSE-2.0
9e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall *
10e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * Unless required by applicable law or agreed to in writing, software
11e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * distributed under the License is distributed on an "AS IS" BASIS,
12e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * See the License for the specific language governing permissions and
14e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * limitations under the License.
15e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall */
16e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
17e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallpackage com.android.camera.async;
18e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
19e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport com.google.common.base.Function;
2081308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lallimport com.google.common.base.Supplier;
21e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport com.google.common.collect.ImmutableList;
22e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
23e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport java.util.ArrayList;
24e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport java.util.List;
25e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport java.util.concurrent.Executor;
26e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
27e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport javax.annotation.CheckReturnValue;
28e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport javax.annotation.Nonnull;
29e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport javax.annotation.ParametersAreNonnullByDefault;
30e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport javax.annotation.concurrent.ThreadSafe;
31e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
32e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall/**
33e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * Enables combining multiple {@link Observable}s together with a given
34e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * function.
35e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * <p>
36e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * Callbacks added to the resulting observable are notified when any of the
37e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall * dependencies change.
38e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall */
39e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall@ThreadSafe
40e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall@ParametersAreNonnullByDefault
4181308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lallfinal class ObservableCombiner<T> implements Observable<T> {
4281308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    private final ImmutableList<Observable<?>> mInputs;
4381308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    private final Supplier<T> mOutput;
44e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
4581308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    private ObservableCombiner(List<? extends Observable<?>> inputs,
4681308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall            Supplier<T> output) {
47e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall        mInputs = ImmutableList.copyOf(inputs);
4881308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall        mOutput = output;
49e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    }
50e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
51e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    /**
52e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     * Transforms a set of input observables with a function.
53e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     *
54e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     * @param inputs The input observables.
55e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     * @param function The function to apply to all of the inputs.
56e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     * @param <I> The type of all inputs values.
57e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     * @param <O> The type of the output values.
58e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     * @return An observable which will reflect the combination of all inputs
59e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     *         with the given function. Changes in the output value will result
60e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     *         in calls to any callbacks registered with the output.
61e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall     */
6281308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    static <I, O> Observable<O> transform(final List<? extends Observable<I>> inputs,
6381308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall            final Function<List<I>, O> function) {
6481308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall        return new ObservableCombiner<>(inputs, new Supplier<O>() {
6581308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall            @Override
6681308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall            public O get() {
6781308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall                ArrayList<I> deps = new ArrayList<>();
6881308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall                for (Observable<? extends I> dependency : inputs) {
6981308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall                    deps.add(dependency.get());
7081308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall                }
7181308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall                return function.apply(deps);
7281308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall            }
7381308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall        });
7481308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    }
7581308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall
7681308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    static <O> Observable<O> transform(final List<? extends Observable<?>> inputs,
7781308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall                                       final Supplier<O> output) {
7881308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall        return new ObservableCombiner<>(inputs, output);
79e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    }
80e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
81e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @Nonnull
82e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @Override
83e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @CheckReturnValue
84e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall    public SafeCloseable addCallback(Runnable callback, Executor executor) {
85e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        Lifetime callbackLifetime = new Lifetime();
86e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
8781308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall        for (Observable<?> input : mInputs) {
88e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall            callbackLifetime.add(input.addCallback(callback, executor));
89e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall        }
90e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
91e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        return callbackLifetime;
92e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    }
93e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall
94e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @Nonnull
95e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @Override
9681308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall    public T get() {
9781308a22b0f64c6667f6c23adee9da520415bcb6Puneet Lall        return mOutput.get();
98e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    }
99e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall}
100