1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"), 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ex.camera2.portability; 18 19 import android.os.SystemClock; 20 21 import com.android.ex.camera2.portability.debug.Log; 22 23 public abstract class CameraStateHolder { 24 private static final Log.Tag TAG = new Log.Tag("CamStateHolder"); 25 26 private int mState; 27 private boolean mInvalid; 28 29 /** 30 * Construct a new instance of @{link CameraStateHolder} with an initial state. 31 * 32 * @param state The initial state. 33 */ 34 public CameraStateHolder(int state) { 35 setState(state); 36 mInvalid = false; 37 } 38 39 /** 40 * Change to a new state. 41 * 42 * @param state The new state. 43 */ 44 public synchronized void setState(int state) { 45 if (mState != state) { 46 Log.v(TAG, "setState - state = " + Integer.toBinaryString(state)); 47 } 48 mState = state; 49 this.notifyAll(); 50 } 51 52 /** 53 * Obtain the current state. 54 * 55 * @return The current state. 56 */ 57 public synchronized int getState() { 58 return mState; 59 } 60 61 /** 62 * Change the state to be invalid. Once invalidated, the state will be invalid forever. 63 */ 64 public synchronized void invalidate() { 65 mInvalid = true; 66 } 67 68 /** 69 * Whether the state is invalid. 70 * 71 * @return True if the state is invalid. 72 */ 73 public synchronized boolean isInvalid() { 74 return mInvalid; 75 } 76 77 private static interface ConditionChecker { 78 /** 79 * @return Whether the condition holds. 80 */ 81 boolean success(); 82 } 83 84 /** 85 * A helper method used by {@link #waitToAvoidStates(int)} and 86 * {@link #waitForStates(int)}. This method will wait until the 87 * condition is successful. 88 * 89 * @param stateChecker The state checker to be used. 90 * @param timeoutMs The timeout limit in milliseconds. 91 * @return {@code false} if the wait is interrupted or timeout limit is 92 * reached. 93 */ 94 private boolean waitForCondition(ConditionChecker stateChecker, 95 long timeoutMs) { 96 long timeBound = SystemClock.uptimeMillis() + timeoutMs; 97 synchronized (this) { 98 while (!stateChecker.success()) { 99 try { 100 this.wait(timeoutMs); 101 } catch (InterruptedException ex) { 102 if (SystemClock.uptimeMillis() > timeBound) { 103 // Timeout. 104 Log.w(TAG, "Timeout waiting."); 105 } 106 return false; 107 } 108 } 109 } 110 return true; 111 } 112 113 /** 114 * Block the current thread until the state becomes one of the 115 * specified. 116 * 117 * @param states Expected states. 118 * @return {@code false} if the wait is interrupted or timeout limit is 119 * reached. 120 */ 121 public boolean waitForStates(final int states) { 122 Log.v(TAG, "waitForStates - states = " + Integer.toBinaryString(states)); 123 return waitForCondition(new ConditionChecker() { 124 @Override 125 public boolean success() { 126 return (states | getState()) == states; 127 } 128 }, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS); 129 } 130 131 /** 132 * Block the current thread until the state becomes NOT one of the 133 * specified. 134 * 135 * @param states States to avoid. 136 * @return {@code false} if the wait is interrupted or timeout limit is 137 * reached. 138 */ 139 public boolean waitToAvoidStates(final int states) { 140 Log.v(TAG, "waitToAvoidStates - states = " + Integer.toBinaryString(states)); 141 return waitForCondition(new ConditionChecker() { 142 @Override 143 public boolean success() { 144 return (states & getState()) == 0; 145 } 146 }, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS); 147 } 148 } 149