Home | History | Annotate | Download | only in portability
      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