FluentFuture.java

/*
 * Copyright 2019 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 androidx.camera.core.impl.utils.futures;


import androidx.annotation.RestrictTo;
import androidx.arch.core.util.Function;
import androidx.concurrent.ListenableFuture;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Primary logic is copy from concurrent-futures package in Guava to AndroidX namespace since we
 * would need ListenableFuture related implementation but not want to include whole Guava library.
 *
 * TODO: b/130187641 Update ImageCapture and remove FluentFuture.
 *
 *  A {@link ListenableFuture} that supports fluent chains of operations. For example:
 *
 *  <pre>{@code
 *  ListenableFuture<Boolean> adminIsLoggedIn =
 *      FluentFuture.from(usersDatabase.getAdminUser())
 *          .transform(User::getId, directExecutor())
 *          .transform(ActivityService::isLoggedIn, threadPool)
 *          .catching(RpcException.class, e -> false, directExecutor());
 *  }</pre>
 *  @hide
 *  @param <V>
 *  @deprecated Temporarily to use this class to keep code in the same behavior, will remove after
 *  ImageCapture update.
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Deprecated
public abstract class FluentFuture<V> extends AbstractFuture<V> {

    /**
     * Converts the given {@code ListenableFuture} to an equivalent {@code FluentFuture}.
     *
     * <p>If the given {@code ListenableFuture} is already a {@code FluentFuture}, it is returned
     * directly. If not, it is wrapped in a {@code FluentFuture} that delegates all calls to the
     * original {@code ListenableFuture}.
     *
     * @param future
     * @param <V>
     * @return directly if input a FluentFuture or wrapped by ForwardingFluentFuture.
     */
    public static <V> FluentFuture<V> from(ListenableFuture<V> future) {
        return future instanceof FluentFuture
                ? (FluentFuture<V>) future
                : new ForwardingFluentFuture<V>(future);
    }

    /**
     * Returns a new {@code Future} whose result is asynchronously derived from the result of this
     * {@code Future}. If the input {@code Future} fails, the returned {@code Future} fails with the
     * same exception (and the function is not invoked).
     *
     * @param function A function to transform the result of this mFuture to the result of the
     *                 output mFuture
     * @param executor Executor to run the function in.
     * @return A mFuture that holds result of the function (if the input succeeded) or the original
     *     input's failure (if not)
     */
    public final <T> FluentFuture<T> transformAsync(
            AsyncFunction<? super V, T> function, Executor executor) {
        return (FluentFuture<T>) Futures.transformAsync(this, function, executor);
    }

    /**
     * Returns a new {@code Future} whose result is derived from the result of this {@code Future}.
     * If this input {@code Future} fails, the returned {@code Future} fails with the same exception
     * (and the function is not invoked).
     *
     * @param function A Function to transform the results of this mFuture to the results of the
     *     returned mFuture.
     * @param executor Executor to run the function in.
     * @return A mFuture that holds result of the transformation.
     */
    public final <T> FluentFuture<T> transform(Function<? super V, T> function, Executor executor) {
        return (FluentFuture<T>) Futures.transform(this, function, executor);
    }

    /**
     * Registers separate success and failure callbacks to be run when this {@code Future}'s
     * computation is {@linkplain java.util.concurrent.Future#isDone() complete} or, if the
     * computation is already complete, immediately.
     *
     * @param callback The callback to invoke when this {@code Future} is completed.
     * @param executor The mExecutor to run {@code callback} when the mFuture completes.
     */
    public final void addCallback(FutureCallback<? super V> callback, Executor executor) {
        Futures.addCallback(this, callback, executor);
    }

    /**
     * A less abstract subclass of AbstractFuture. This can be used to optimize setFuture by
     * ensuring that {@link #get} calls exactly the implementation of {@link AbstractFuture#get}.
     */
    abstract static class TrustedFuture<V> extends FluentFuture<V>
            implements AbstractFuture.Trusted<V> {
        @Override
        public final V get() throws InterruptedException, ExecutionException {
            return super.get();
        }

        @Override
        public final V get(long timeout, TimeUnit unit)
                throws InterruptedException, ExecutionException, TimeoutException {
            return super.get(timeout, unit);
        }

        @Override
        public final boolean isDone() {
            return super.isDone();
        }

        @Override
        public final boolean isCancelled() {
            return super.isCancelled();
        }

        @Override
        public final void addListener(Runnable listener, Executor executor) {
            super.addListener(listener, executor);
        }

        @Override
        public final boolean cancel(boolean mayInterruptIfRunning) {
            return super.cancel(mayInterruptIfRunning);
        }
    }
}