19c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall/*
29c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * Copyright (C) 2014 The Android Open Source Project
39c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall *
49c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * Licensed under the Apache License, Version 2.0 (the "License");
59c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * you may not use this file except in compliance with the License.
69c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * You may obtain a copy of the License at
79c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall *
89c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall *      http://www.apache.org/licenses/LICENSE-2.0
99c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall *
109c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * Unless required by applicable law or agreed to in writing, software
119c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * distributed under the License is distributed on an "AS IS" BASIS,
129c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * See the License for the specific language governing permissions and
149c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * limitations under the License.
159c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall */
169c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
179c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lallpackage com.android.camera.async;
189c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
199c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lallimport java.util.Set;
20e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lallimport java.util.concurrent.CopyOnWriteArraySet;
219c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lallimport java.util.concurrent.Executor;
229c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
23e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport javax.annotation.CheckReturnValue;
244961ad31d9a877e3a68566fb5d4b33b7f79ce44ePuneet Lallimport javax.annotation.Nonnull;
25e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lallimport javax.annotation.ParametersAreNonnullByDefault;
264961ad31d9a877e3a68566fb5d4b33b7f79ce44ePuneet Lall
279c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall/**
289c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * Generic asynchronous state wrapper which supports two methods of interaction:
299c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall * polling for the latest value and listening for updates.
309c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall */
31e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall@ParametersAreNonnullByDefault
3217fc13a74ff71e3c721218624815c244dccc33f7Puneet Lallpublic class ConcurrentState<T> implements Updatable<T>, Observable<T> {
33e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall    private static class ExecutorListenerPair implements Runnable {
349c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall        private final Executor mExecutor;
35e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        private final Runnable mListener;
369c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
37e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        public ExecutorListenerPair(Executor executor, Runnable listener) {
389c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall            mExecutor = executor;
399c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall            mListener = listener;
409c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall        }
419c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
429c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall        /**
43e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall         * Runs the callback on the executor.
449c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall         */
45e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        @Override
46e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        public void run() {
47e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall            mExecutor.execute(mListener);
489c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall        }
499c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    }
509c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
51e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall    private final Set<ExecutorListenerPair> mListeners;
52e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall    private volatile T mValue;
539c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
549ad0984f36ff9cd133c61c4e979032988b77a995Puneet Lall    public ConcurrentState(T initialValue) {
55e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        // Callbacks are typically only added and removed at startup/shutdown,
56e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        // but {@link #update} is often called at high-frequency. So, using a
57e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        // read-optimized data structure is appropriate here.
58e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        mListeners = new CopyOnWriteArraySet<>();
599ad0984f36ff9cd133c61c4e979032988b77a995Puneet Lall        mValue = initialValue;
609c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    }
619c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
629c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    /**
639c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall     * Updates the state to the latest value, notifying all listeners.
649c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall     */
659c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    @Override
66e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    public void update(T newValue) {
67e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        mValue = newValue;
68e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        for (ExecutorListenerPair pair : mListeners) {
69e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall            pair.run();
709c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall        }
719c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    }
729c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
73e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @CheckReturnValue
74e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @Nonnull
7517fc13a74ff71e3c721218624815c244dccc33f7Puneet Lall    @Override
76e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall    public SafeCloseable addCallback(Runnable callback, Executor executor) {
77e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        final ExecutorListenerPair pair = new ExecutorListenerPair(executor, callback);
78e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        mListeners.add(pair);
79e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        return new SafeCloseable() {
80e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall            @Override
81e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall            public void close() {
82e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall                mListeners.remove(pair);
83e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall            }
84e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        };
859c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    }
869c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall
879c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    /**
889c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall     * Polls for the latest value.
899c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall     *
909c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall     * @return The latest state.
919c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall     */
92e919a48fb40b9d6c698a495acf40adbc0e320431Puneet Lall    @Nonnull
939c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    @Override
949ad0984f36ff9cd133c61c4e979032988b77a995Puneet Lall    public T get() {
95e606c4d68b74293e7d7725aecbaa9c915751cd43Puneet Lall        return mValue;
969c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall    }
979c94ab32a69a1ad3642a0f1e38e68bcfd97d3511Puneet Lall}
98