summaryrefslogtreecommitdiffstats
path: root/camera2/portability/src/com/android/ex/camera2/portability/CameraStateHolder.java
blob: b758af2278aee993171134e18be5103d1c58be15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * Copyright (C) 2014 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 com.android.ex.camera2.portability;

import android.os.SystemClock;

import com.android.ex.camera2.portability.debug.Log;

public abstract class CameraStateHolder {
    private static final Log.Tag TAG = new Log.Tag("CamStateHolder");

    private int mState;
    private boolean mInvalid;

    /**
     * Construct a new instance of @{link CameraStateHolder} with an initial state.
     *
     * @param state The initial state.
     */
    public CameraStateHolder(int state) {
        setState(state);
        mInvalid = false;
    }

    /**
     * Change to a new state.
     *
     * @param state The new state.
     */
    public synchronized void setState(int state) {
        if (mState != state) {
            Log.v(TAG, "setState - state = " + Integer.toBinaryString(state));
        }
        mState = state;
        this.notifyAll();
    }

    /**
     * Obtain the current state.
     *
     * @return The current state.
     */
    public synchronized int getState() {
        return mState;
    }

    /**
     * Change the state to be invalid. Once invalidated, the state will be invalid forever.
     */
    public synchronized void invalidate() {
        mInvalid = true;
    }

    /**
     * Whether the state is invalid.
     *
     * @return True if the state is invalid.
     */
    public synchronized boolean isInvalid() {
        return mInvalid;
    }

    private static interface ConditionChecker {
        /**
         * @return Whether the condition holds.
         */
        boolean success();
    }

    /**
     * A helper method used by {@link #waitToAvoidStates(int)} and
     * {@link #waitForStates(int)}. This method will wait until the
     * condition is successful.
     *
     * @param stateChecker The state checker to be used.
     * @param timeoutMs The timeout limit in milliseconds.
     * @return {@code false} if the wait is interrupted or timeout limit is
     *         reached.
     */
    private boolean waitForCondition(ConditionChecker stateChecker,
            long timeoutMs) {
        long timeBound = SystemClock.uptimeMillis() + timeoutMs;
        synchronized (this) {
            while (!stateChecker.success()) {
                try {
                    this.wait(timeoutMs);
                } catch (InterruptedException ex) {
                    if (SystemClock.uptimeMillis() > timeBound) {
                        // Timeout.
                        Log.w(TAG, "Timeout waiting.");
                    }
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Block the current thread until the state becomes one of the
     * specified.
     *
     * @param states Expected states.
     * @return {@code false} if the wait is interrupted or timeout limit is
     *         reached.
     */
    public boolean waitForStates(final int states) {
        Log.v(TAG, "waitForStates - states = " + Integer.toBinaryString(states));
        return waitForCondition(new ConditionChecker() {
            @Override
            public boolean success() {
                return (states | getState()) == states;
            }
        }, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS);
    }

    /**
     * Block the current thread until the state becomes NOT one of the
     * specified.
     *
     * @param states States to avoid.
     * @return {@code false} if the wait is interrupted or timeout limit is
     *         reached.
     */
    public boolean waitToAvoidStates(final int states) {
        Log.v(TAG, "waitToAvoidStates - states = " + Integer.toBinaryString(states));
        return waitForCondition(new ConditionChecker() {
            @Override
            public boolean success() {
                return (states & getState()) == 0;
            }
        }, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS);
    }
}