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