Home | History | Annotate | Download | only in pos
      1 /*
      2  * Copyright 2013 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 package com.android.ex.camera2.pos;
     17 
     18 import android.hardware.camera2.CameraDevice;
     19 import android.hardware.camera2.CaptureResult.Key;
     20 import android.hardware.camera2.CaptureRequest;
     21 import android.hardware.camera2.CaptureResult;
     22 import android.util.Log;
     23 
     24 import com.android.ex.camera2.utils.SysTrace;
     25 
     26 /**
     27  * Manage the auto focus state machine for CameraDevice.
     28  *
     29  * <p>Requests are created only when the AF needs to be manipulated from the user,
     30  * but automatic camera-caused AF state changes are broadcasted from any new result.</p>
     31  */
     32 public class AutoFocusStateMachine {
     33 
     34     /**
     35      * Observe state AF state transitions triggered by
     36      * {@link AutoFocusStateMachine#onCaptureCompleted onCaptureCompleted}.
     37      */
     38     public interface AutoFocusStateListener {
     39         /**
     40          * The camera is currently focused (either active or passive).
     41          *
     42          * @param locked True if the lens has been locked from moving, false otherwise.
     43          */
     44         void onAutoFocusSuccess(CaptureResult result, boolean locked);
     45 
     46         /**
     47          * The camera is currently not focused (either active or passive).
     48          *
     49          * @param locked False if the AF is still scanning, true if needs a restart.
     50          */
     51         void onAutoFocusFail(CaptureResult result, boolean locked);
     52 
     53         /**
     54          * The camera is currently scanning (either active or passive)
     55          * and has not yet converged.
     56          *
     57          * <p>This is not called for results where the AF either succeeds or fails.</p>
     58          */
     59         void onAutoFocusScan(CaptureResult result);
     60 
     61         /**
     62          * The camera is currently not doing anything with the autofocus.
     63          *
     64          * <p>Autofocus could be off, or this could be an intermediate state transition as
     65          * scanning restarts.</p>
     66          */
     67         void onAutoFocusInactive(CaptureResult result);
     68     }
     69 
     70     private static final String TAG = "AutoFocusStateMachine";
     71     private static final boolean DEBUG_LOGGING = Log.isLoggable(TAG, Log.DEBUG);
     72     private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
     73     private static final int AF_UNINITIALIZED = -1;
     74 
     75     private final AutoFocusStateListener mListener;
     76     private int mLastAfState = AF_UNINITIALIZED;
     77     private int mLastAfMode = AF_UNINITIALIZED;
     78     private int mCurrentAfMode = AF_UNINITIALIZED;
     79     private int mCurrentAfTrigger = AF_UNINITIALIZED;
     80 
     81     private int mCurrentAfCookie = AF_UNINITIALIZED;
     82     private String mCurrentAfTrace = "";
     83     private int mLastAfCookie = 0;
     84 
     85     public AutoFocusStateMachine(AutoFocusStateListener listener) {
     86         if (listener == null) {
     87             throw new IllegalArgumentException("listener should not be null");
     88         }
     89         mListener = listener;
     90     }
     91 
     92     /**
     93      * Invoke every time we get a new CaptureResult via
     94      * {@link CameraDevice.CaptureCallback#onCaptureCompleted}.
     95      *
     96      * <p>This function is responsible for dispatching updates via the
     97      * {@link AutoFocusStateListener} so without calling this on a regular basis, no
     98      * AF changes will be observed.</p>
     99      *
    100      * @param result CaptureResult
    101      */
    102     public synchronized void onCaptureCompleted(CaptureResult result) {
    103 
    104         /**
    105          * Work-around for b/11269834
    106          * Although these should never-ever happen, harden for ship
    107          */
    108         if (result == null) {
    109             Log.w(TAG, "onCaptureCompleted - missing result, skipping AF update");
    110             return;
    111         }
    112 
    113         Key<Integer> keyAfState = CaptureResult.CONTROL_AF_STATE;
    114         if (keyAfState == null) {
    115             Log.e(TAG, "onCaptureCompleted - missing android.control.afState key, " +
    116                     "skipping AF update");
    117             return;
    118         }
    119 
    120         Key<Integer> keyAfMode = CaptureResult.CONTROL_AF_MODE;
    121         if (keyAfMode == null) {
    122             Log.e(TAG, "onCaptureCompleted - missing android.control.afMode key, " +
    123                     "skipping AF update");
    124             return;
    125         }
    126 
    127         Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
    128         Integer afMode = result.get(CaptureResult.CONTROL_AF_MODE);
    129 
    130         /**
    131          * Work-around for b/11238865
    132          * This is a HAL bug as these fields should be there always.
    133          */
    134         if (afState == null) {
    135             Log.w(TAG, "onCaptureCompleted - missing android.control.afState !");
    136             return;
    137         } else if (afMode == null) {
    138             Log.w(TAG, "onCaptureCompleted - missing android.control.afMode !");
    139             return;
    140         }
    141 
    142         if (DEBUG_LOGGING) Log.d(TAG, "onCaptureCompleted - new AF mode = " + afMode +
    143                 " new AF state = " + afState);
    144 
    145         if (mLastAfState == afState && afMode == mLastAfMode) {
    146             // Same AF state as last time, nothing else needs to be done.
    147             return;
    148         }
    149 
    150         if (VERBOSE_LOGGING) Log.v(TAG, "onCaptureCompleted - new AF mode = " + afMode +
    151                 " new AF state = " + afState);
    152 
    153         mLastAfState = afState;
    154         mLastAfMode = afMode;
    155 
    156         switch (afState) {
    157             case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
    158                 mListener.onAutoFocusSuccess(result, /*locked*/true);
    159                 endTraceAsync();
    160                 break;
    161             case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
    162                 mListener.onAutoFocusFail(result, /*locked*/true);
    163                 endTraceAsync();
    164                 break;
    165             case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
    166                 mListener.onAutoFocusSuccess(result, /*locked*/false);
    167                 break;
    168             case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
    169                 mListener.onAutoFocusFail(result, /*locked*/false);
    170                 break;
    171             case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:
    172                 mListener.onAutoFocusScan(result);
    173                 break;
    174             case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
    175                 mListener.onAutoFocusScan(result);
    176                 break;
    177             case CaptureResult.CONTROL_AF_STATE_INACTIVE:
    178                 mListener.onAutoFocusInactive(result);
    179                 break;
    180         }
    181     }
    182 
    183     /**
    184      * Reset the current AF state.
    185      *
    186      * <p>
    187      * When dropping capture results (by not invoking {@link #onCaptureCompleted} when a new
    188      * {@link CaptureResult} is available), call this function to reset the state. Otherwise
    189      * the next time a new state is observed this class may incorrectly consider it as the same
    190      * state as before, and not issue any callbacks by {@link AutoFocusStateListener}.
    191      * </p>
    192      */
    193     public synchronized void resetState() {
    194         if (VERBOSE_LOGGING) Log.v(TAG, "resetState - last state was " + mLastAfState);
    195 
    196         mLastAfState = AF_UNINITIALIZED;
    197     }
    198 
    199     /**
    200      * Lock the lens from moving. Typically used before taking a picture.
    201      *
    202      * <p>After calling this function, submit the new requestBuilder as a separate capture.
    203      * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
    204      *
    205      * <p>Create a new repeating request from repeatingBuilder and set that as the updated
    206      * repeating request.</p>
    207      *
    208      * <p>If the lock succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
    209      * {@code locked == true} will be invoked. If the lock fails,
    210      * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
    211      * invoked.</p>
    212      *
    213      * @param repeatingBuilder Builder for a repeating request.
    214      * @param requestBuilder Builder for a non-repeating request.
    215      *
    216      */
    217     public synchronized void lockAutoFocus(CaptureRequest.Builder repeatingBuilder,
    218             CaptureRequest.Builder requestBuilder) {
    219 
    220         if (VERBOSE_LOGGING) Log.v(TAG, "lockAutoFocus");
    221 
    222         if (mCurrentAfMode == AF_UNINITIALIZED) {
    223             throw new IllegalStateException("AF mode was not enabled");
    224         }
    225 
    226         beginTraceAsync("AFSM_lockAutoFocus");
    227 
    228         mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_START;
    229 
    230         repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    231         requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    232 
    233         repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    234                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    235         requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    236                 CaptureRequest.CONTROL_AF_TRIGGER_START);
    237     }
    238 
    239     /**
    240      * Unlock the lens, allowing it to move again. Typically used after taking a picture.
    241      *
    242      * <p>After calling this function, submit the new requestBuilder as a separate capture.
    243      * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
    244      *
    245      * <p>Create a new repeating request from repeatingBuilder and set that as the updated
    246      * repeating request.</p>
    247      *
    248      * <p>Once the unlock takes effect, {@link AutoFocusStateListener#onAutoFocusInactive} is
    249      * invoked, and after that the effects depend on which mode you were in:
    250      * <ul>
    251      * <li>Passive - Scanning restarts with {@link AutoFocusStateListener#onAutoFocusScan}</li>
    252      * <li>Active - The lens goes back to a default position (no callbacks)</li>
    253      * </ul>
    254      * </p>
    255      *
    256      * @param repeatingBuilder Builder for a repeating request.
    257      * @param requestBuilder Builder for a non-repeating request.
    258      *
    259      */
    260     public synchronized void unlockAutoFocus(CaptureRequest.Builder repeatingBuilder,
    261             CaptureRequest.Builder requestBuilder) {
    262 
    263         if (VERBOSE_LOGGING) Log.v(TAG, "unlockAutoFocus");
    264 
    265         if (mCurrentAfMode == AF_UNINITIALIZED) {
    266             throw new IllegalStateException("AF mode was not enabled");
    267         }
    268 
    269         mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_CANCEL;
    270 
    271         repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    272         requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    273 
    274         repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    275                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    276         requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    277                 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
    278     }
    279 
    280     /**
    281      * Enable active auto focus, immediately triggering a converging scan.
    282      *
    283      * <p>This is typically only used when locking the passive AF has failed.</p>
    284      *
    285      * <p>Once active AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
    286      * invoked.</p>
    287      *
    288      * <p>If the active scan succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
    289      * {@code locked == true} will be invoked. If the active scan fails,
    290      * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
    291      * invoked.</p>
    292      *
    293      * <p>After calling this function, submit the new requestBuilder as a separate capture.
    294      * Do not submit it as a repeating request or the AF trigger will be repeated every time.</p>
    295      *
    296      * <p>Create a new repeating request from repeatingBuilder and set that as the updated
    297      * repeating request.</p>
    298      *
    299      * @param repeatingBuilder Builder for a repeating request.
    300      * @param requestBuilder Builder for a non-repeating request.
    301      *
    302      * @param repeatingBuilder Builder for a repeating request.
    303      */
    304     public synchronized void setActiveAutoFocus(CaptureRequest.Builder repeatingBuilder,
    305             CaptureRequest.Builder requestBuilder) {
    306         if (VERBOSE_LOGGING) Log.v(TAG, "setActiveAutoFocus");
    307 
    308         beginTraceAsync("AFSM_setActiveAutoFocus");
    309 
    310         mCurrentAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
    311 
    312         repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    313         requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    314 
    315         repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    316                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    317         requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    318                 CaptureRequest.CONTROL_AF_TRIGGER_START);
    319     }
    320 
    321     /**
    322      * Enable passive autofocus, immediately triggering a non-converging scan.
    323      *
    324      * <p>While passive autofocus is enabled, use {@link #lockAutoFocus} to lock
    325      * the lens before taking a picture. Once a picture is taken, use {@link #unlockAutoFocus}
    326      * to let the lens go back into passive scanning.</p>
    327      *
    328      * <p>Once passive AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
    329      * invoked.</p>
    330      *
    331      * @param repeatingBuilder Builder for a repeating request.
    332      * @param picture True for still capture AF, false for video AF.
    333      */
    334     public synchronized void setPassiveAutoFocus(boolean picture,
    335             CaptureRequest.Builder repeatingBuilder) {
    336         if (VERBOSE_LOGGING) Log.v(TAG, "setPassiveAutoFocus - picture " + picture);
    337 
    338         if (picture) {
    339             mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
    340         } else {
    341             mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
    342         }
    343 
    344         repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    345     }
    346 
    347     private synchronized void beginTraceAsync(String sectionName) {
    348         if (mCurrentAfCookie != AF_UNINITIALIZED) {
    349             // Terminate any currently active async sections before beginning another section
    350             SysTrace.endSectionAsync(mCurrentAfTrace, mCurrentAfCookie);
    351         }
    352 
    353         mLastAfCookie++;
    354         mCurrentAfCookie = mLastAfCookie;
    355         mCurrentAfTrace = sectionName;
    356 
    357         SysTrace.beginSectionAsync(sectionName, mCurrentAfCookie);
    358     }
    359 
    360     private synchronized void endTraceAsync() {
    361         if (mCurrentAfCookie == AF_UNINITIALIZED) {
    362             Log.w(TAG, "endTraceAsync - no current trace active");
    363             return;
    364         }
    365 
    366         SysTrace.endSectionAsync(mCurrentAfTrace, mCurrentAfCookie);
    367         mCurrentAfCookie = AF_UNINITIALIZED;
    368     }
    369 
    370     /**
    371      * Update the repeating request with current focus mode.
    372      *
    373      * <p>This is typically used when a new repeating request is created to update preview with
    374      * new metadata (i.e. crop region). The current auto focus mode needs to be carried over for
    375      * correct auto focus behavior.<p>
    376      *
    377      * @param repeatingBuilder Builder for a repeating request.
    378      */
    379     public synchronized void updateCaptureRequest(CaptureRequest.Builder repeatingBuilder) {
    380         if (repeatingBuilder == null) {
    381             throw new IllegalArgumentException("repeatingBuilder shouldn't be null");
    382         }
    383 
    384         if (mCurrentAfMode == AF_UNINITIALIZED) {
    385             throw new IllegalStateException("AF mode was not enabled");
    386         }
    387 
    388         repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
    389     }
    390 }
    391