summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-09-24 17:46:56 -0700
committerIgor Murashkin <iam@google.com>2013-09-24 19:34:26 -0700
commitfc121178a18d0860d020e9cb2253c5b00dbf19c3 (patch)
tree12081eaf212a94e406fcd1a0b2373aff36e566da
parent07f09b47112dc1094649da00f7e86024b67d5777 (diff)
downloadandroid_frameworks_ex-fc121178a18d0860d020e9cb2253c5b00dbf19c3.tar.gz
android_frameworks_ex-fc121178a18d0860d020e9cb2253c5b00dbf19c3.tar.bz2
android_frameworks_ex-fc121178a18d0860d020e9cb2253c5b00dbf19c3.zip
camera2: Add state machine for doing auto-focus easily from apps
Bug: 10890749 Change-Id: I966768bdcdbb2876d44eefc2156e7aca64c4e601
-rw-r--r--camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java275
1 files changed, 275 insertions, 0 deletions
diff --git a/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java b/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java
new file mode 100644
index 0000000..ba32b12
--- /dev/null
+++ b/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2013 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.pos;
+
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Log;
+
+/**
+ * Manage the auto focus state machine for CameraDevice.
+ *
+ * <p>Requests are created only when the AF needs to be manipulated from the user,
+ * but automatic camera-caused AF state changes are broadcasted from any new result.</p>
+ */
+public class AutoFocusStateMachine {
+
+ public interface AutoFocusStateListener {
+ /**
+ * The camera is currently focused (either active or passive).
+ *
+ * @param locked True if the lens has been locked from moving, false otherwise.
+ */
+ void onAutoFocusSuccess(CaptureResult result, boolean locked);
+
+ /**
+ * The camera is currently not focused (either active or passive).
+ *
+ * @param locked False if the AF is still scanning, true if needs a restart.
+ */
+ void onAutoFocusFail(CaptureResult result, boolean locked);
+
+ /**
+ * The camera is currently scanning (either active or passive)
+ * and has not yet converged.
+ *
+ * <p>This is not called for results where the AF either succeeds or fails.</p>
+ */
+ void onAutoFocusScan(CaptureResult result);
+
+ /**
+ * The camera is currently not doing anything with the autofocus.
+ *
+ * <p>Autofocus could be off, or this could be an intermediate state transition as
+ * scanning restarts.</p>
+ */
+ void onAutoFocusInactive(CaptureResult result);
+ }
+
+ private static final String TAG = "AutoFocusStateMachine";
+ private static final boolean DEBUG_LOGGING = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
+ private static final int AF_UNINITIALIZED = -1;
+
+ private final AutoFocusStateListener mListener;
+ private int mLastAfState = AF_UNINITIALIZED;
+ private int mLastAfMode = AF_UNINITIALIZED;
+ private int mCurrentAfMode = AF_UNINITIALIZED;
+ private int mCurrentAfTrigger = AF_UNINITIALIZED;
+
+ public AutoFocusStateMachine(AutoFocusStateListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener should not be null");
+ }
+ mListener = listener;
+ }
+
+ /**
+ * Invoke every time we get a new CaptureResult via
+ * {@link CameraDevice.CaptureListener#onCaptureCompleted}.
+ *
+ * <p>This function is responsible for dispatching updates via the
+ * {@link AutoFocusStateListener} so without calling this on a regular basis, no
+ * AF changes will be observed.</p>
+ *
+ * @param result CaptureResult
+ */
+ public synchronized void onCaptureCompleted(CaptureResult result) {
+
+ int afState = result.get(CaptureResult.CONTROL_AF_STATE);
+
+ if (DEBUG_LOGGING) Log.d(TAG, "onCaptureCompleted - new AF state = " + afState);
+
+ if (mLastAfState == afState) {
+ // Same AF state as last time, nothing else needs to be done.
+ return;
+ }
+
+ if (VERBOSE_LOGGING) Log.v(TAG, "onCaptureCompleted - new AF state = " + afState);
+
+ mLastAfState = afState;
+ mLastAfMode = result.get(CaptureResult.CONTROL_AF_MODE);
+
+ switch (afState) {
+ case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
+ mListener.onAutoFocusSuccess(result, /*locked*/true);
+ break;
+ case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
+ mListener.onAutoFocusFail(result, /*locked*/true);
+ break;
+ case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
+ mListener.onAutoFocusSuccess(result, /*locked*/true);
+ break;
+ //case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: // not yet pushed
+ // mListener.onAutoFocusFail(result, /*locked*/false);
+ // break;
+ case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:
+ mListener.onAutoFocusScan(result);
+ break;
+ case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
+ mListener.onAutoFocusScan(result);
+ break;
+ case CaptureResult.CONTROL_AF_STATE_INACTIVE:
+ mListener.onAutoFocusInactive(result);
+ break;
+ }
+ }
+
+ /**
+ * Lock the lens from moving. Typically used before taking a picture.
+ *
+ * <p>After calling this function, submit the new requestBuilder as a separate capture.
+ * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
+ *
+ * <p>Create a new repeating request from repeatingBuilder and set that as the updated
+ * repeating request.</p>
+ *
+ * <p>If the lock succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
+ * {@code locked == true} will be invoked. If the lock fails,
+ * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
+ * invoked.</p>
+ *
+ * @param repeatingBuilder Builder for a repeating request.
+ * @param requestBuilder Builder for a non-repeating request.
+ *
+ */
+ public synchronized void lockAutoFocus(CaptureRequest.Builder repeatingBuilder,
+ CaptureRequest.Builder requestBuilder) {
+
+ if (VERBOSE_LOGGING) Log.v(TAG, "lockAutoFocus");
+
+ if (mCurrentAfMode == AF_UNINITIALIZED) {
+ throw new IllegalStateException("AF mode was not enabled");
+ }
+
+ mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_START;
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+ requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+ requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_START);
+ }
+
+ /**
+ * Unlock the lens, allowing it to move again. Typically used after taking a picture.
+ *
+ * <p>After calling this function, submit the new requestBuilder as a separate capture.
+ * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
+ *
+ * <p>Create a new repeating request from repeatingBuilder and set that as the updated
+ * repeating request.</p>
+ *
+ * <p>Once the unlock takes effect, {@link AutoFocusStateListener#onAutoFocusInactive} is
+ * invoked, and after that the effects depend on which mode you were in:
+ * <ul>
+ * <li>Passive - Scanning restarts with {@link AutoFocusStateListener#onAutoFocusScan}</li>
+ * <li>Active - The lens goes back to a default position (no callbacks)</li>
+ * </ul>
+ * </p>
+ *
+ * @param repeatingBuilder Builder for a repeating request.
+ * @param requestBuilder Builder for a non-repeating request.
+ *
+ */
+ public synchronized void unlockAutoFocus(CaptureRequest.Builder repeatingBuilder,
+ CaptureRequest.Builder requestBuilder) {
+
+ if (VERBOSE_LOGGING) Log.v(TAG, "unlockAutoFocus");
+
+ if (mCurrentAfMode == AF_UNINITIALIZED) {
+ throw new IllegalStateException("AF mode was not enabled");
+ }
+
+ mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_CANCEL;
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+ requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+ requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
+ }
+
+ /**
+ * Enable active auto focus, immediately triggering a converging scan.
+ *
+ * <p>This is typically only used when locking the passive AF has failed.</p>
+ *
+ * <p>Once active AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
+ * invoked.</p>
+ *
+ * <p>If the active scan succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
+ * {@code locked == true} will be invoked. If the active scan fails,
+ * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
+ * invoked.</p>
+ *
+ * <p>After calling this function, submit the new requestBuilder as a separate capture.
+ * Do not submit it as a repeating request or the AF trigger will be repeated every time.</p>
+ *
+ * <p>Create a new repeating request from repeatingBuilder and set that as the updated
+ * repeating request.</p>
+ *
+ * @param repeatingBuilder Builder for a repeating request.
+ * @param requestBuilder Builder for a non-repeating request.
+ *
+ * @param repeatingBuilder Builder for a repeating request.
+ */
+ public synchronized void setActiveAutoFocus(CaptureRequest.Builder repeatingBuilder,
+ CaptureRequest.Builder requestBuilder) {
+ if (VERBOSE_LOGGING) Log.v(TAG, "setActiveAutoFocus");
+
+ mCurrentAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+ requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+ requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_START);
+ }
+
+ /**
+ * Enable passive autofocus, immediately triggering a non-converging scan.
+ *
+ * <p>While passive autofocus is enabled, use {@link #lockAutoFocus} to lock
+ * the lens before taking a picture. Once a picture is taken, use {@link #unlockAutoFocus}
+ * to let the lens go back into passive scanning.</p>
+ *
+ * <p>Once passive AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
+ * invoked.</p>
+ *
+ * @param repeatingBuilder Builder for a repeating request.
+ * @param picture True for still capture AF, false for video AF.
+ */
+ public synchronized void setPassiveAutoFocus(boolean picture,
+ CaptureRequest.Builder repeatingBuilder) {
+ if (VERBOSE_LOGGING) Log.v(TAG, "setPassiveAutoFocus - picture " + picture);
+
+ if (picture) {
+ mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+ } else {
+ mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+ }
+
+ repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
+ }
+}