EmulatedFakeCamera2: Add autofocus management

- Add skeleton ControlThread for 3A processing
- Add fake autofocus management into ControlThread
- Support AUTO, MACRO, CONTINUOUS_PICTURE, CONTINUOUS_VIDEO

Bug: 6243944
Change-Id: Ic47f5be642d4705db86021b94aaba8dcc7f32cf0
diff --git a/tools/emulator/system/camera/EmulatedCamera2.cpp b/tools/emulator/system/camera/EmulatedCamera2.cpp
index 599bd16..fa7ee4d 100644
--- a/tools/emulator/system/camera/EmulatedCamera2.cpp
+++ b/tools/emulator/system/camera/EmulatedCamera2.cpp
@@ -305,6 +305,7 @@
 int EmulatedCamera2::set_notify_callback(const camera2_device_t *d,
         camera2_notify_callback notify_cb, void* user) {
     EmulatedCamera2* ec = getInstance(d);
+    Mutex::Autolock l(ec->mMutex);
     ec->mNotifyCb = notify_cb;
     ec->mNotifyUserPtr = user;
     return NO_ERROR;
@@ -355,6 +356,18 @@
     return ec->closeCamera();
 }
 
+void EmulatedCamera2::sendNotification(int32_t msgType,
+        int32_t ext1, int32_t ext2, int32_t ext3) {
+    camera2_notify_callback notifyCb;
+    {
+        Mutex::Autolock l(mMutex);
+        notifyCb = mNotifyCb;
+    }
+    if (notifyCb != NULL) {
+        notifyCb(msgType, ext1, ext2, ext3, mNotifyUserPtr);
+    }
+}
+
 camera2_device_ops_t EmulatedCamera2::sDeviceOps = {
     EmulatedCamera2::set_request_queue_src_ops,
     EmulatedCamera2::notify_request_queue_not_empty,
diff --git a/tools/emulator/system/camera/EmulatedCamera2.h b/tools/emulator/system/camera/EmulatedCamera2.h
index 2c813a4..a294454 100644
--- a/tools/emulator/system/camera/EmulatedCamera2.h
+++ b/tools/emulator/system/camera/EmulatedCamera2.h
@@ -28,6 +28,8 @@
 #include "hardware/camera2.h"
 #include "system/camera_metadata.h"
 #include "EmulatedBaseCamera.h"
+#include <utils/Thread.h>
+#include <utils/Mutex.h>
 
 namespace android {
 
@@ -128,7 +130,7 @@
 
     /** 3A action triggering */
     virtual int triggerAction(uint32_t trigger_id,
-            int ext1, int ext2);
+            int32_t ext1, int32_t ext2);
 
     /** Custom tag definitions */
     virtual const char* getVendorSectionName(uint32_t tag);
@@ -232,21 +234,27 @@
      * Data members shared with implementations
      ***************************************************************************/
   protected:
+    /** Mutex for calls through camera2 device interface */
+    Mutex mMutex;
+
     const camera2_request_queue_src_ops *mRequestQueueSrc;
     const camera2_frame_queue_dst_ops *mFrameQueueDst;
-    camera2_notify_callback mNotifyCb;
-    void* mNotifyUserPtr;
 
     struct TagOps : public vendor_tag_query_ops {
         EmulatedCamera2 *parent;
     };
     TagOps      mVendorTagOps;
 
+    void sendNotification(int32_t msgType,
+            int32_t ext1, int32_t ext2, int32_t ext3);
+
     /****************************************************************************
      * Data members
      ***************************************************************************/
   private:
     static camera2_device_ops_t sDeviceOps;
+    camera2_notify_callback mNotifyCb;
+    void* mNotifyUserPtr;
 };
 
 }; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp
index f614f1d..70297c6 100644
--- a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp
+++ b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp
@@ -133,6 +133,7 @@
 
     mConfigureThread = new ConfigureThread(this);
     mReadoutThread = new ReadoutThread(this);
+    mControlThread = new ControlThread(this);
     mSensor = new Sensor(this);
     mJpegCompressor = new JpegCompressor(this);
 
@@ -147,6 +148,9 @@
     res = mReadoutThread->run("EmulatedFakeCamera2::readoutThread");
     if (res != NO_ERROR) return res;
 
+    res = mControlThread->run("EmulatedFakeCamera2::controlThread");
+    if (res != NO_ERROR) return res;
+
     return EmulatedCamera2::connectCamera(device);
 }
 
@@ -164,11 +168,12 @@
 
     mConfigureThread->requestExit();
     mReadoutThread->requestExit();
+    mControlThread->requestExit();
     mJpegCompressor->cancel();
 
     mConfigureThread->join();
     mReadoutThread->join();
-
+    mControlThread->join();
 
     ALOGV("%s exit", __FUNCTION__);
     return NO_ERROR;
@@ -431,6 +436,14 @@
     return NO_ERROR;
 }
 
+int EmulatedFakeCamera2::triggerAction(uint32_t trigger_id,
+        int32_t ext1,
+        int32_t ext2) {
+    Mutex::Autolock l(mMutex);
+    return mControlThread->triggerAction(trigger_id,
+            ext1, ext2);
+}
+
 /** Custom tag definitions */
 
 // Emulator camera metadata sections
@@ -535,8 +548,8 @@
 EmulatedFakeCamera2::ConfigureThread::ConfigureThread(EmulatedFakeCamera2 *parent):
         Thread(false),
         mParent(parent),
-        mNextBuffers(NULL),
-        mRequestCount(0) {
+        mRequestCount(0),
+        mNextBuffers(NULL) {
     mRunning = false;
 }
 
@@ -635,7 +648,7 @@
         }
         // Get necessary parameters for sensor config
 
-        sort_camera_metadata(mRequest);
+        mParent->mControlThread->processRequest(mRequest);
 
         camera_metadata_entry_t streams;
         res = find_camera_metadata_entry(mRequest,
@@ -803,10 +816,9 @@
         mParent(parent),
         mRunning(false),
         mActive(false),
+        mRequestCount(0),
         mRequest(NULL),
-        mBuffers(NULL),
-        mRequestCount(0)
-{
+        mBuffers(NULL) {
     mInFlightQueue = new InFlightQueue[kInFlightQueueSize];
     mInFlightHead = 0;
     mInFlightTail = 0;
@@ -1046,6 +1058,343 @@
     return true;
 }
 
+EmulatedFakeCamera2::ControlThread::ControlThread(EmulatedFakeCamera2 *parent):
+        Thread(false),
+        mParent(parent) {
+    mRunning = false;
+}
+
+EmulatedFakeCamera2::ControlThread::~ControlThread() {
+}
+
+status_t EmulatedFakeCamera2::ControlThread::readyToRun() {
+    Mutex::Autolock lock(mInputMutex);
+
+    ALOGV("Starting up ControlThread");
+    mRunning = true;
+    mStartAf = false;
+    mCancelAf = false;
+    mStartPrecapture = false;
+
+    mControlMode = ANDROID_CONTROL_AUTO;
+
+    mEffectMode = ANDROID_CONTROL_EFFECT_OFF;
+    mSceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
+
+    mAfMode = ANDROID_CONTROL_AF_AUTO;
+    mAfModeChange = false;
+
+    mAeMode = ANDROID_CONTROL_AE_ON;
+    mAwbMode = ANDROID_CONTROL_AWB_AUTO;
+
+    mAfTriggerId = 0;
+    mPrecaptureTriggerId = 0;
+
+    mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
+    mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE;
+
+    mInputSignal.signal();
+    return NO_ERROR;
+}
+
+status_t EmulatedFakeCamera2::ControlThread::waitUntilRunning() {
+    Mutex::Autolock lock(mInputMutex);
+    if (!mRunning) {
+        ALOGV("Waiting for control thread to start");
+        mInputSignal.wait(mInputMutex);
+    }
+    return OK;
+}
+
+status_t EmulatedFakeCamera2::ControlThread::processRequest(camera_metadata_t *request) {
+    Mutex::Autolock lock(mInputMutex);
+    // TODO: Add handling for all android.control.* fields here
+    camera_metadata_entry_t mode;
+    status_t res;
+
+    res = find_camera_metadata_entry(request,
+            ANDROID_CONTROL_MODE,
+            &mode);
+    mControlMode = mode.data.u8[0];
+
+    res = find_camera_metadata_entry(request,
+            ANDROID_CONTROL_EFFECT_MODE,
+            &mode);
+    mEffectMode = mode.data.u8[0];
+
+    res = find_camera_metadata_entry(request,
+            ANDROID_CONTROL_SCENE_MODE,
+            &mode);
+    mSceneMode = mode.data.u8[0];
+
+    res = find_camera_metadata_entry(request,
+            ANDROID_CONTROL_AF_MODE,
+            &mode);
+    if (mAfMode != mode.data.u8[0]) {
+        ALOGV("AF new mode: %d, old mode %d", mode.data.u8[0], mAfMode);
+        mAfMode = mode.data.u8[0];
+        mAfModeChange = true;
+        mStartAf = false;
+        mCancelAf = false;
+    }
+
+    res = find_camera_metadata_entry(request,
+            ANDROID_CONTROL_AE_MODE,
+            &mode);
+    mAeMode = mode.data.u8[0];
+
+    res = find_camera_metadata_entry(request,
+            ANDROID_CONTROL_AWB_MODE,
+            &mode);
+    mAwbMode = mode.data.u8[0];
+
+    // TODO: Override control fields
+
+    return OK;
+}
+
+status_t EmulatedFakeCamera2::ControlThread::triggerAction(uint32_t msgType,
+        int32_t ext1, int32_t ext2) {
+    Mutex::Autolock lock(mInputMutex);
+    switch (msgType) {
+        case CAMERA2_TRIGGER_AUTOFOCUS:
+            mAfTriggerId = ext1;
+            mStartAf = true;
+            mCancelAf = false;
+            break;
+        case CAMERA2_TRIGGER_CANCEL_AUTOFOCUS:
+            mAfTriggerId = ext1;
+            mStartAf = false;
+            mCancelAf = true;
+            break;
+        case CAMERA2_TRIGGER_PRECAPTURE_METERING:
+            mPrecaptureTriggerId = ext1;
+            mStartPrecapture = true;
+            break;
+        default:
+            ALOGE("%s: Unknown action triggered: %d (arguments %d %d)",
+                    __FUNCTION__, msgType, ext1, ext2);
+            return BAD_VALUE;
+    }
+    return OK;
+}
+
+const nsecs_t EmulatedFakeCamera2::ControlThread::kControlCycleDelay = 100000000;
+const nsecs_t EmulatedFakeCamera2::ControlThread::kMinAfDuration = 500000000;
+const nsecs_t EmulatedFakeCamera2::ControlThread::kMaxAfDuration = 900000000;
+const float EmulatedFakeCamera2::ControlThread::kAfSuccessRate = 0.9;
+const float EmulatedFakeCamera2::ControlThread::kContinuousAfStartRate =
+    kControlCycleDelay / 5000000000.0; // Once every 5 seconds
+
+bool EmulatedFakeCamera2::ControlThread::threadLoop() {
+    bool afModeChange = false;
+    bool afTriggered = false;
+    bool afCancelled = false;
+    uint8_t afState;
+    uint8_t afMode;
+    int32_t afTriggerId;
+    nsecs_t nextSleep = kControlCycleDelay;
+
+    {
+        Mutex::Autolock lock(mInputMutex);
+        if (mStartAf) {
+            afTriggered = true;
+            mStartAf = false;
+        } else if (mCancelAf) {
+            afCancelled = true;
+            mCancelAf = false;
+        }
+        afState = mAfState;
+        afMode = mAfMode;
+        afModeChange = mAfModeChange;
+        mAfModeChange = false;
+
+        afTriggerId = mAfTriggerId;
+    }
+
+    if (afCancelled || afModeChange) {
+        ALOGV("Resetting AF state due to cancel/mode change");
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+        updateAfState(afState, afTriggerId);
+        mAfScanDuration = 0;
+        mLockAfterPassiveScan = false;
+    }
+
+    uint8_t oldAfState = afState;
+
+    if (afTriggered) {
+        afState = processAfTrigger(afMode, afState);
+    }
+
+    afState = maybeStartAfScan(afMode, afState);
+
+    afState = updateAfScan(afMode, afState, &nextSleep);
+
+    updateAfState(afState, afTriggerId);
+
+    int ret;
+    timespec t;
+    t.tv_sec = 0;
+    t.tv_nsec = nextSleep;
+    do {
+        ret = nanosleep(&t, &t);
+    } while (ret != 0);
+
+    return true;
+}
+
+int EmulatedFakeCamera2::ControlThread::processAfTrigger(uint8_t afMode,
+        uint8_t afState) {
+    switch (afMode) {
+        case ANDROID_CONTROL_AF_OFF:
+        case ANDROID_CONTROL_AF_EDOF:
+            // Do nothing
+            break;
+        case ANDROID_CONTROL_AF_MACRO:
+        case ANDROID_CONTROL_AF_AUTO:
+            switch (afState) {
+                case ANDROID_CONTROL_AF_STATE_INACTIVE:
+                case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
+                case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
+                    // Start new focusing cycle
+                    mAfScanDuration =  ((double)rand() / RAND_MAX) *
+                        (kMaxAfDuration - kMinAfDuration) + kMinAfDuration;
+                    afState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
+                    ALOGV("%s: AF scan start, duration %lld ms",
+                          __FUNCTION__, mAfScanDuration / 1000000);
+                    break;
+                case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN:
+                    // Ignore new request, already scanning
+                    break;
+                default:
+                    ALOGE("Unexpected AF state in AUTO/MACRO AF mode: %d",
+                          afState);
+            }
+            break;
+        case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
+            switch (afState) {
+                // Picture mode waits for passive scan to complete
+                case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
+                    mLockAfterPassiveScan = true;
+                    break;
+                case ANDROID_CONTROL_AF_STATE_INACTIVE:
+                    afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
+                    break;
+                case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
+                    afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+                    break;
+                case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
+                case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
+                    // Must cancel to get out of these states
+                    break;
+                default:
+                    ALOGE("Unexpected AF state in CONTINUOUS_PICTURE AF mode: %d",
+                          afState);
+            }
+            break;
+        case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
+            switch (afState) {
+                // Video mode does not wait for passive scan to complete
+                case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
+                case ANDROID_CONTROL_AF_STATE_INACTIVE:
+                    afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
+                    break;
+                case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
+                    afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+                    break;
+                case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
+                case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
+                    // Must cancel to get out of these states
+                    break;
+                default:
+                    ALOGE("Unexpected AF state in CONTINUOUS_VIDEO AF mode: %d",
+                          afState);
+            }
+            break;
+        default:
+            break;
+    }
+    return afState;
+}
+
+int EmulatedFakeCamera2::ControlThread::maybeStartAfScan(uint8_t afMode,
+        uint8_t afState) {
+    if ((afMode == ANDROID_CONTROL_AF_CONTINUOUS_VIDEO ||
+            afMode == ANDROID_CONTROL_AF_CONTINUOUS_PICTURE) &&
+        (afState == ANDROID_CONTROL_AF_STATE_INACTIVE ||
+            afState == ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)) {
+
+        bool startScan = ((double)rand() / RAND_MAX) < kContinuousAfStartRate;
+        if (startScan) {
+            // Start new passive focusing cycle
+            mAfScanDuration =  ((double)rand() / RAND_MAX) *
+                (kMaxAfDuration - kMinAfDuration) + kMinAfDuration;
+            afState = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
+            ALOGV("%s: AF passive scan start, duration %lld ms",
+                __FUNCTION__, mAfScanDuration / 1000000);
+        }
+    }
+    return afState;
+}
+
+int EmulatedFakeCamera2::ControlThread::updateAfScan(uint8_t afMode,
+        uint8_t afState, nsecs_t *maxSleep) {
+    if (! (afState == ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN ||
+            afState == ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN ) ) {
+        return afState;
+    }
+
+    if (mAfScanDuration == 0) {
+        ALOGV("%s: AF scan done", __FUNCTION__);
+        switch (afMode) {
+            case ANDROID_CONTROL_AF_MACRO:
+            case ANDROID_CONTROL_AF_AUTO: {
+                bool success = ((double)rand() / RAND_MAX) < kAfSuccessRate;
+                if (success) {
+                    afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+                } else {
+                    afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
+                }
+                break;
+            }
+            case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
+                if (mLockAfterPassiveScan) {
+                    afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+                    mLockAfterPassiveScan = false;
+                } else {
+                    afState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
+                }
+                break;
+            case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
+                afState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
+                break;
+            default:
+                ALOGE("Unexpected AF mode in scan state");
+        }
+    } else {
+        if (mAfScanDuration <= *maxSleep) {
+            *maxSleep = mAfScanDuration;
+            mAfScanDuration = 0;
+        } else {
+            mAfScanDuration -= *maxSleep;
+        }
+    }
+    return afState;
+}
+
+void EmulatedFakeCamera2::ControlThread::updateAfState(uint8_t newState,
+        int32_t triggerId) {
+    Mutex::Autolock lock(mInputMutex);
+    if (mAfState != newState) {
+        ALOGV("%s: Autofocus state now %d, id %d", __FUNCTION__,
+                newState, triggerId);
+        mAfState = newState;
+        mParent->sendNotification(CAMERA2_MSG_AUTOFOCUS,
+                newState, triggerId, 0);
+    }
+}
+
 /** Private methods */
 
 status_t EmulatedFakeCamera2::constructStaticInfo(
@@ -1062,9 +1411,12 @@
 
     // android.lens
 
-    static const float minFocusDistance = 0;
+    // 5 cm min focus distance for back camera, infinity (fixed focus) for front
+    const float minFocusDistance = mFacingBack ? 1.0/0.05 : 0.0;
     ADD_OR_SIZE(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE,
             &minFocusDistance, 1);
+    // 5 m hyperfocal distance for back camera, infinity (fixed focus) for front
+    const float hyperFocalDistance = mFacingBack ? 1.0/5.0 : 0.0;
     ADD_OR_SIZE(ANDROID_LENS_HYPERFOCAL_DISTANCE,
             &minFocusDistance, 1);
 
@@ -1323,11 +1675,25 @@
     ADD_OR_SIZE(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
             availableAwbModes, sizeof(availableAwbModes));
 
-    static const uint8_t availableAfModes[] = {
+    static const uint8_t availableAfModesBack[] = {
+            ANDROID_CONTROL_AF_OFF,
+            ANDROID_CONTROL_AF_AUTO,
+            ANDROID_CONTROL_AF_MACRO,
+            ANDROID_CONTROL_AF_CONTINUOUS_VIDEO,
+            ANDROID_CONTROL_AF_CONTINUOUS_PICTURE
+    };
+
+    static const uint8_t availableAfModesFront[] = {
             ANDROID_CONTROL_AF_OFF
     };
-    ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
-            availableAfModes, sizeof(availableAfModes));
+
+    if (mFacingBack) {
+        ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
+                    availableAfModesBack, sizeof(availableAfModesBack));
+    } else {
+        ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
+                    availableAfModesFront, sizeof(availableAfModesFront));
+    }
 
     static const uint8_t availableVstabModes[] = {
             ANDROID_CONTROL_VIDEO_STABILIZATION_OFF
diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.h b/tools/emulator/system/camera/EmulatedFakeCamera2.h
index 5563c1d..4621cec 100644
--- a/tools/emulator/system/camera/EmulatedFakeCamera2.h
+++ b/tools/emulator/system/camera/EmulatedFakeCamera2.h
@@ -31,7 +31,6 @@
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/String16.h>
-#include <utils/Thread.h>
 
 namespace android {
 
@@ -113,9 +112,9 @@
 
     // virtual int releaseReprocessStream(uint32_t stream_id);
 
-    // virtual int triggerAction(uint32_t trigger_id,
-    //        int ext1,
-    //        int ext2);
+    virtual int triggerAction(uint32_t trigger_id,
+            int32_t ext1,
+            int32_t ext2);
 
     /** Custom tag definitions */
     virtual const char* getVendorSectionName(uint32_t tag);
@@ -245,6 +244,80 @@
 
     };
 
+    // 3A management thread (auto-exposure, focus, white balance)
+    class ControlThread: public Thread {
+      public:
+        ControlThread(EmulatedFakeCamera2 *parent);
+        ~ControlThread();
+
+        status_t readyToRun();
+
+        status_t waitUntilRunning();
+
+        // Interpret request's control parameters and override
+        // capture settings as needed
+        status_t processRequest(camera_metadata_t *request);
+
+        status_t triggerAction(uint32_t msgType,
+                int32_t ext1, int32_t ext2);
+      private:
+        ControlThread(const ControlThread &t);
+        ControlThread& operator=(const ControlThread &t);
+
+        // Constants controlling fake 3A behavior
+        static const nsecs_t kControlCycleDelay;
+        static const nsecs_t kMinAfDuration;
+        static const nsecs_t kMaxAfDuration;
+        static const float kAfSuccessRate;
+        static const float kContinuousAfStartRate;
+
+        EmulatedFakeCamera2 *mParent;
+
+        bool mRunning;
+        bool threadLoop();
+
+        Mutex mInputMutex; // Protects input methods
+        Condition mInputSignal;
+
+        // Trigger notifications
+        bool mStartAf;
+        bool mCancelAf;
+        bool mStartPrecapture;
+
+        // Latest state for 3A request fields
+        uint8_t mControlMode;
+
+        uint8_t mEffectMode;
+        uint8_t mSceneMode;
+
+        uint8_t mAfMode;
+        bool mAfModeChange;
+
+        uint8_t mAwbMode;
+        uint8_t mAeMode;
+
+        // Latest trigger IDs
+        int32_t mAfTriggerId;
+        int32_t mPrecaptureTriggerId;
+
+        // Current state for 3A algorithms
+        uint8_t mAfState;
+        uint8_t mAeState;
+        uint8_t mAwbState;
+
+        // Private to threadLoop and its utility methods
+
+        nsecs_t mAfScanDuration;
+        bool mLockAfterPassiveScan;
+
+        // Utility methods
+        int processAfTrigger(uint8_t afMode, uint8_t afState);
+        int maybeStartAfScan(uint8_t afMode, uint8_t afState);
+        int updateAfScan(uint8_t afMode, uint8_t afState, nsecs_t *maxSleep);
+        void updateAfState(uint8_t newState, int32_t triggerId);
+
+    };
+
     /****************************************************************************
      * Static configuration information
      ***************************************************************************/
@@ -271,9 +344,6 @@
     bool mFacingBack;
 
 private:
-    /** Mutex for calls through camera2 device interface */
-    Mutex mMutex;
-
     /** Stream manipulation */
     uint32_t mNextStreamId;
     uint32_t mRawStreamCount;
@@ -289,6 +359,7 @@
     /** Pipeline control threads */
     sp<ConfigureThread> mConfigureThread;
     sp<ReadoutThread>   mReadoutThread;
+    sp<ControlThread>   mControlThread;
 };
 
 }; /* namespace android */