1cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher/*
2cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * Copyright (C) 2014 The Android Open Source Project
3cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher *
4cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * Licensed under the Apache License, Version 2.0 (the "License"),
5cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * you may not use this file except in compliance with the License.
6cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * You may obtain a copy of the License at
7cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher *
8cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher *      http://www.apache.org/licenses/LICENSE-2.0
9cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher *
10cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * Unless required by applicable law or agreed to in writing, software
11cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * distributed under the License is distributed on an "AS IS" BASIS,
12cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * See the License for the specific language governing permissions and
14cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher * limitations under the License.
15cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher */
16cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
17cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucherpackage com.android.ex.camera2.portability;
18cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
19cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucherimport android.os.SystemClock;
20cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
21cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucherimport com.android.ex.camera2.portability.debug.Log;
22cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
23a0842b40441db5332a5290f941021636b1182761Sol Boucherpublic abstract class CameraStateHolder {
24a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static final Log.Tag TAG = new Log.Tag("CamStateHolder");
25cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
26cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    private int mState;
272f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    private boolean mInvalid;
28cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
292f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    /**
302f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * Construct a new instance of @{link CameraStateHolder} with an initial state.
312f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     *
322f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * @param state The initial state.
332f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     */
34cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    public CameraStateHolder(int state) {
35cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        setState(state);
362f5251072284508374cb36d1e83f7e24cc590049Senpo Hu        mInvalid = false;
37cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
38cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
392f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    /**
402f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * Change to a new state.
412f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     *
422f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * @param state The new state.
432f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     */
44cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    public synchronized void setState(int state) {
456a9babad6eb8ac3e79a5e036d878ed7408e79f26Igor Murashkin        if (mState != state) {
466a9babad6eb8ac3e79a5e036d878ed7408e79f26Igor Murashkin            Log.v(TAG, "setState - state = " + Integer.toBinaryString(state));
476a9babad6eb8ac3e79a5e036d878ed7408e79f26Igor Murashkin        }
48cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        mState = state;
49cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        this.notifyAll();
50cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
51cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
522f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    /**
532f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * Obtain the current state.
542f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     *
552f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * @return The current state.
562f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     */
57cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    public synchronized int getState() {
58cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        return mState;
59cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
60cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
612f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    /**
627921659d7096a618634153ca7fed88e8563e03f5Sheng-hao Tsao     * Change the state to be invalid. Once invalidated, the state will be invalid forever.
632f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     */
642f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    public synchronized void invalidate() {
652f5251072284508374cb36d1e83f7e24cc590049Senpo Hu        mInvalid = true;
662f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    }
672f5251072284508374cb36d1e83f7e24cc590049Senpo Hu
682f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    /**
692f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * Whether the state is invalid.
702f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     *
712f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     * @return True if the state is invalid.
722f5251072284508374cb36d1e83f7e24cc590049Senpo Hu     */
732f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    public synchronized boolean isInvalid() {
742f5251072284508374cb36d1e83f7e24cc590049Senpo Hu        return mInvalid;
752f5251072284508374cb36d1e83f7e24cc590049Senpo Hu    }
762f5251072284508374cb36d1e83f7e24cc590049Senpo Hu
77a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static interface ConditionChecker {
78cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        /**
79cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher         * @return Whether the condition holds.
80cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher         */
81cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        boolean success();
82cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
83cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
84cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    /**
85cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * A helper method used by {@link #waitToAvoidStates(int)} and
86cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * {@link #waitForStates(int)}. This method will wait until the
87cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * condition is successful.
88cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     *
89cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @param stateChecker The state checker to be used.
90cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @param timeoutMs The timeout limit in milliseconds.
91cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @return {@code false} if the wait is interrupted or timeout limit is
92cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     *         reached.
93cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     */
94cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    private boolean waitForCondition(ConditionChecker stateChecker,
95cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            long timeoutMs) {
96cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        long timeBound = SystemClock.uptimeMillis() + timeoutMs;
97cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        synchronized (this) {
98cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            while (!stateChecker.success()) {
99cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                try {
100cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                    this.wait(timeoutMs);
101cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                } catch (InterruptedException ex) {
102cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                    if (SystemClock.uptimeMillis() > timeBound) {
103cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                        // Timeout.
104cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                        Log.w(TAG, "Timeout waiting.");
105cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                    }
106cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                    return false;
107cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher                }
108cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            }
109cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        }
110cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        return true;
111cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
112cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
113cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    /**
114cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * Block the current thread until the state becomes one of the
115cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * specified.
116cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     *
117cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @param states Expected states.
118cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @return {@code false} if the wait is interrupted or timeout limit is
119cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     *         reached.
120cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     */
121cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    public boolean waitForStates(final int states) {
1226a9babad6eb8ac3e79a5e036d878ed7408e79f26Igor Murashkin        Log.v(TAG, "waitForStates - states = " + Integer.toBinaryString(states));
123cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        return waitForCondition(new ConditionChecker() {
124cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            @Override
125cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            public boolean success() {
126a0842b40441db5332a5290f941021636b1182761Sol Boucher                return (states | getState()) == states;
127cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            }
1284f425ba476d62b4be7078f2084af37cf306b31c6Sol Boucher        }, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS);
129cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
130cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher
131cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    /**
132cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * Block the current thread until the state becomes NOT one of the
133cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * specified.
134cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     *
135cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @param states States to avoid.
136cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     * @return {@code false} if the wait is interrupted or timeout limit is
137cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     *         reached.
138cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher     */
139cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    public boolean waitToAvoidStates(final int states) {
1406a9babad6eb8ac3e79a5e036d878ed7408e79f26Igor Murashkin        Log.v(TAG, "waitToAvoidStates - states = " + Integer.toBinaryString(states));
141cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher        return waitForCondition(new ConditionChecker() {
142cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            @Override
143cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            public boolean success() {
144a0842b40441db5332a5290f941021636b1182761Sol Boucher                return (states & getState()) == 0;
145cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher            }
1464f425ba476d62b4be7078f2084af37cf306b31c6Sol Boucher        }, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS);
147cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher    }
148cef46862d6937bc98bf1a6b087c5daa22b5239f3Sol Boucher}
149