Bare-bones emulated fake camera for HAL version 3

- Uses same backend as HAL version 2 fake camera.
- No fake 3A yet
- No reprocessing support
- No JPEG support

Change-Id: I9b55b05fbeac9d42340eb988021e65491d13a2f9
diff --git a/camera/Android.mk b/camera/Android.mk
index 0f1685c..8f20cdb 100755
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -39,27 +39,28 @@
 
 LOCAL_SRC_FILES := \
 	EmulatedCameraHal.cpp \
-    EmulatedCameraFactory.cpp \
-    EmulatedBaseCamera.cpp \
-    EmulatedCamera.cpp \
-	EmulatedCameraDevice.cpp \
-	EmulatedQemuCamera.cpp \
-	EmulatedQemuCameraDevice.cpp \
-	EmulatedFakeCamera.cpp \
-	EmulatedFakeCameraDevice.cpp \
-	Converters.cpp \
-	PreviewWindow.cpp \
-	CallbackNotifier.cpp \
-	QemuClient.cpp \
-	JpegCompressor.cpp \
-    EmulatedCamera2.cpp \
-    EmulatedCameraHotplugThread.cpp \
-	EmulatedFakeCamera2.cpp \
-	EmulatedQemuCamera2.cpp \
-	fake-pipeline2/Scene.cpp \
-	fake-pipeline2/Sensor.cpp \
-	fake-pipeline2/JpegCompressor.cpp
-
+	EmulatedCameraFactory.cpp \
+	EmulatedCameraHotplugThread.cpp \
+	EmulatedBaseCamera.cpp \
+	EmulatedCamera.cpp \
+		EmulatedCameraDevice.cpp \
+		EmulatedQemuCamera.cpp \
+		EmulatedQemuCameraDevice.cpp \
+		EmulatedFakeCamera.cpp \
+		EmulatedFakeCameraDevice.cpp \
+		Converters.cpp \
+		PreviewWindow.cpp \
+		CallbackNotifier.cpp \
+		QemuClient.cpp \
+		JpegCompressor.cpp \
+	EmulatedCamera2.cpp \
+		EmulatedFakeCamera2.cpp \
+		EmulatedQemuCamera2.cpp \
+		fake-pipeline2/Scene.cpp \
+		fake-pipeline2/Sensor.cpp \
+		fake-pipeline2/JpegCompressor.cpp \
+	EmulatedCamera3.cpp \
+		EmulatedFakeCamera3.cpp
 
 ifeq ($(TARGET_PRODUCT),vbox_x86)
 LOCAL_MODULE := camera.vbox_x86
diff --git a/camera/EmulatedCamera3.cpp b/camera/EmulatedCamera3.cpp
new file mode 100644
index 0000000..47de44f
--- /dev/null
+++ b/camera/EmulatedCamera3.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/**
+ * Contains implementation of a class EmulatedCamera that encapsulates
+ * functionality common to all version 3.0 emulated camera devices.  Instances
+ * of this class (for each emulated camera) are created during the construction
+ * of the EmulatedCameraFactory instance.  This class serves as an entry point
+ * for all camera API calls that defined by camera3_device_ops_t API.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera3_Camera"
+#include <cutils/log.h>
+
+#include "EmulatedCamera3.h"
+#include "system/camera_metadata.h"
+
+namespace android {
+
+/**
+ * Constructs EmulatedCamera3 instance.
+ * Param:
+ *  cameraId - Zero based camera identifier, which is an index of the camera
+ *      instance in camera factory's array.
+ *  module - Emulated camera HAL module descriptor.
+ */
+EmulatedCamera3::EmulatedCamera3(int cameraId,
+        struct hw_module_t* module):
+        EmulatedBaseCamera(cameraId,
+                CAMERA_DEVICE_API_VERSION_3_0,
+                &common,
+                module),
+        mStatus(STATUS_ERROR)
+{
+    common.close = EmulatedCamera3::close;
+    ops = &sDeviceOps;
+
+    mCallbackOps = NULL;
+
+    mVendorTagOps.get_camera_vendor_section_name =
+            EmulatedCamera3::get_camera_vendor_section_name;
+    mVendorTagOps.get_camera_vendor_tag_name =
+            EmulatedCamera3::get_camera_vendor_tag_name;
+    mVendorTagOps.get_camera_vendor_tag_type =
+            EmulatedCamera3::get_camera_vendor_tag_type;
+    mVendorTagOps.parent = this;
+}
+
+/* Destructs EmulatedCamera3 instance. */
+EmulatedCamera3::~EmulatedCamera3() {
+}
+
+/****************************************************************************
+ * Abstract API
+ ***************************************************************************/
+
+/****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+status_t EmulatedCamera3::Initialize() {
+    ALOGV("%s", __FUNCTION__);
+
+    mStatus = STATUS_CLOSED;
+    return NO_ERROR;
+}
+
+/****************************************************************************
+ * Camera API implementation
+ ***************************************************************************/
+
+status_t EmulatedCamera3::connectCamera(hw_device_t** device) {
+    ALOGV("%s", __FUNCTION__);
+    if (device == NULL) return BAD_VALUE;
+
+    if (mStatus != STATUS_CLOSED) {
+        ALOGE("%s: Trying to open a camera in state %d!",
+                __FUNCTION__, mStatus);
+        return INVALID_OPERATION;
+    }
+
+    *device = &common;
+    mStatus = STATUS_OPEN;
+    return NO_ERROR;
+}
+
+status_t EmulatedCamera3::closeCamera() {
+    mStatus = STATUS_CLOSED;
+    return NO_ERROR;
+}
+
+status_t EmulatedCamera3::getCameraInfo(struct camera_info* info) {
+    return EmulatedBaseCamera::getCameraInfo(info);
+}
+
+/****************************************************************************
+ * Camera Device API implementation.
+ * These methods are called from the camera API callback routines.
+ ***************************************************************************/
+
+status_t EmulatedCamera3::initializeDevice(
+        const camera3_callback_ops *callbackOps) {
+    if (callbackOps == NULL) {
+        ALOGE("%s: NULL callback ops provided to HAL!",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (mStatus != STATUS_OPEN) {
+        ALOGE("%s: Trying to initialize a camera in state %d!",
+                __FUNCTION__, mStatus);
+        return INVALID_OPERATION;
+    }
+
+    mCallbackOps = callbackOps;
+    mStatus = STATUS_READY;
+
+    return NO_ERROR;
+}
+
+status_t EmulatedCamera3::configureStreams(
+        camera3_stream_configuration *streamList) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t EmulatedCamera3::registerStreamBuffers(
+        const camera3_stream_buffer_set *bufferSet) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+const camera_metadata_t* EmulatedCamera3::constructDefaultRequestSettings(
+        int type) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return NULL;
+}
+
+status_t EmulatedCamera3::processCaptureRequest(
+        camera3_capture_request *request) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+/** Custom tag query methods */
+
+const char* EmulatedCamera3::getVendorSectionName(uint32_t tag) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return NULL;
+}
+
+const char* EmulatedCamera3::getVendorTagName(uint32_t tag) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return NULL;
+}
+
+int EmulatedCamera3::getVendorTagType(uint32_t tag) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return -1;
+}
+
+/** Debug methods */
+
+void EmulatedCamera3::dump(int fd) {
+    ALOGE("%s: Not implemented", __FUNCTION__);
+    return;
+}
+
+/****************************************************************************
+ * Protected API. Callbacks to the framework.
+ ***************************************************************************/
+
+void EmulatedCamera3::sendCaptureResult(camera3_capture_result_t *result) {
+    mCallbackOps->process_capture_result(mCallbackOps, result);
+}
+
+void EmulatedCamera3::sendNotify(camera3_notify_msg_t *msg) {
+    mCallbackOps->notify(mCallbackOps, msg);
+}
+
+/****************************************************************************
+ * Private API.
+ ***************************************************************************/
+
+/****************************************************************************
+ * Camera API callbacks as defined by camera3_device_ops structure.  See
+ * hardware/libhardware/include/hardware/camera3.h for information on each
+ * of these callbacks. Implemented in this class, these callbacks simply
+ * dispatch the call into an instance of EmulatedCamera3 class defined by the
+ * 'camera_device3' parameter, or set a member value in the same.
+ ***************************************************************************/
+
+EmulatedCamera3* getInstance(const camera3_device_t *d) {
+    const EmulatedCamera3* cec = static_cast<const EmulatedCamera3*>(d);
+    return const_cast<EmulatedCamera3*>(cec);
+}
+
+int EmulatedCamera3::initialize(const struct camera3_device *d,
+        const camera3_callback_ops_t *callback_ops) {
+    EmulatedCamera3* ec = getInstance(d);
+    return ec->initializeDevice(callback_ops);
+}
+
+int EmulatedCamera3::configure_streams(const struct camera3_device *d,
+        camera3_stream_configuration_t *stream_list) {
+    EmulatedCamera3* ec = getInstance(d);
+    return ec->configureStreams(stream_list);
+}
+
+int EmulatedCamera3::register_stream_buffers(
+        const struct camera3_device *d,
+        const camera3_stream_buffer_set_t *buffer_set) {
+    EmulatedCamera3* ec = getInstance(d);
+    return ec->registerStreamBuffers(buffer_set);
+}
+
+int EmulatedCamera3::process_capture_request(
+        const struct camera3_device *d,
+        camera3_capture_request_t *request) {
+    EmulatedCamera3* ec = getInstance(d);
+    return ec->processCaptureRequest(request);
+}
+
+const camera_metadata_t* EmulatedCamera3::construct_default_request_settings(
+        const camera3_device_t *d, int type) {
+    EmulatedCamera3* ec = getInstance(d);
+    return ec->constructDefaultRequestSettings(type);
+}
+
+void EmulatedCamera3::get_metadata_vendor_tag_ops(const camera3_device_t *d,
+        vendor_tag_query_ops_t *ops) {
+    ops->get_camera_vendor_section_name = get_camera_vendor_section_name;
+    ops->get_camera_vendor_tag_name = get_camera_vendor_tag_name;
+    ops->get_camera_vendor_tag_type = get_camera_vendor_tag_type;
+}
+
+const char* EmulatedCamera3::get_camera_vendor_section_name(
+        const vendor_tag_query_ops_t *v,
+        uint32_t tag) {
+    EmulatedCamera3* ec = static_cast<const TagOps*>(v)->parent;
+    return ec->getVendorSectionName(tag);
+}
+
+const char* EmulatedCamera3::get_camera_vendor_tag_name(
+        const vendor_tag_query_ops_t *v,
+        uint32_t tag) {
+    EmulatedCamera3* ec = static_cast<const TagOps*>(v)->parent;
+    return ec->getVendorTagName(tag);
+}
+
+int EmulatedCamera3::get_camera_vendor_tag_type(
+        const vendor_tag_query_ops_t *v,
+        uint32_t tag)  {
+    EmulatedCamera3* ec = static_cast<const TagOps*>(v)->parent;
+    return ec->getVendorTagType(tag);
+}
+
+void EmulatedCamera3::dump(const camera3_device_t *d, int fd) {
+    EmulatedCamera3* ec = getInstance(d);
+    ec->dump(fd);
+}
+
+int EmulatedCamera3::close(struct hw_device_t* device) {
+    EmulatedCamera3* ec =
+            static_cast<EmulatedCamera3*>(
+                reinterpret_cast<camera3_device_t*>(device) );
+    if (ec == NULL) {
+        ALOGE("%s: Unexpected NULL camera3 device", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    return ec->closeCamera();
+}
+
+camera3_device_ops_t EmulatedCamera3::sDeviceOps = {
+    EmulatedCamera3::initialize,
+    EmulatedCamera3::configure_streams,
+    EmulatedCamera3::register_stream_buffers,
+    EmulatedCamera3::construct_default_request_settings,
+    EmulatedCamera3::process_capture_request,
+    EmulatedCamera3::get_metadata_vendor_tag_ops,
+    EmulatedCamera3::dump
+};
+
+}; /* namespace android */
diff --git a/camera/EmulatedCamera3.h b/camera/EmulatedCamera3.h
new file mode 100644
index 0000000..c1bddf6
--- /dev/null
+++ b/camera/EmulatedCamera3.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H
+#define HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H
+
+/**
+ * Contains declaration of a class EmulatedCamera that encapsulates
+ * functionality common to all version 3.0 emulated camera devices.  Instances
+ * of this class (for each emulated camera) are created during the construction
+ * of the EmulatedCameraFactory instance.  This class serves as an entry point
+ * for all camera API calls that defined by camera3_device_ops_t API.
+ */
+
+#include "hardware/camera3.h"
+#include "system/camera_metadata.h"
+#include "EmulatedBaseCamera.h"
+
+namespace android {
+
+/**
+ * Encapsulates functionality common to all version 3.0 emulated camera devices
+ *
+ * Note that EmulatedCameraFactory instantiates an object of this class just
+ * once, when EmulatedCameraFactory instance gets constructed. Connection to /
+ * disconnection from the actual camera device is handled by calls to
+ * connectDevice(), and closeCamera() methods of this class that are invoked in
+ * response to hw_module_methods_t::open, and camera_device::close callbacks.
+ */
+class EmulatedCamera3 : public camera3_device, public EmulatedBaseCamera {
+public:
+    /* Constructs EmulatedCamera3 instance.
+     * Param:
+     *  cameraId - Zero based camera identifier, which is an index of the camera
+     *      instance in camera factory's array.
+     *  module - Emulated camera HAL module descriptor.
+     */
+    EmulatedCamera3(int cameraId,
+            struct hw_module_t* module);
+
+    /* Destructs EmulatedCamera2 instance. */
+    virtual ~EmulatedCamera3();
+
+    /****************************************************************************
+     * Abstract API
+     ***************************************************************************/
+
+public:
+
+    /****************************************************************************
+     * Public API
+     ***************************************************************************/
+
+public:
+    virtual status_t Initialize();
+
+    /****************************************************************************
+     * Camera module API and generic hardware device API implementation
+     ***************************************************************************/
+
+public:
+    virtual status_t connectCamera(hw_device_t** device);
+
+    virtual status_t closeCamera();
+
+    virtual status_t getCameraInfo(struct camera_info* info);
+
+    /****************************************************************************
+     * Camera API implementation.
+     * These methods are called from the camera API callback routines.
+     ***************************************************************************/
+
+protected:
+
+    virtual status_t initializeDevice(
+        const camera3_callback_ops *callbackOps);
+
+    virtual status_t configureStreams(
+        camera3_stream_configuration *streamList);
+
+    virtual status_t registerStreamBuffers(
+        const camera3_stream_buffer_set *bufferSet) ;
+
+    virtual const camera_metadata_t* constructDefaultRequestSettings(
+        int type);
+
+    virtual status_t processCaptureRequest(camera3_capture_request *request);
+
+    /** Debug methods */
+
+    virtual void dump(int fd);
+
+    /** Tag query methods */
+    virtual const char *getVendorSectionName(uint32_t tag);
+
+    virtual const char *getVendorTagName(uint32_t tag);
+
+    virtual int getVendorTagType(uint32_t tag);
+
+    /****************************************************************************
+     * Camera API callbacks as defined by camera3_device_ops structure.  See
+     * hardware/libhardware/include/hardware/camera3.h for information on each
+     * of these callbacks. Implemented in this class, these callbacks simply
+     * dispatch the call into an instance of EmulatedCamera3 class defined in
+     * the 'camera_device3' parameter.
+     ***************************************************************************/
+
+private:
+
+    /** Startup */
+    static int initialize(const struct camera3_device *,
+            const camera3_callback_ops_t *callback_ops);
+
+    /** Stream configuration and buffer registration */
+
+    static int configure_streams(const struct camera3_device *,
+            camera3_stream_configuration_t *stream_list);
+
+    static int register_stream_buffers(const struct camera3_device *,
+            const camera3_stream_buffer_set_t *buffer_set);
+
+    /** Template request settings provision */
+
+    static const camera_metadata_t* construct_default_request_settings(
+            const struct camera3_device *, int type);
+
+    /** Submission of capture requests to HAL */
+
+    static int process_capture_request(const struct camera3_device *,
+            camera3_capture_request_t *request);
+
+    /** Vendor metadata registration */
+    static void get_metadata_vendor_tag_ops(const camera3_device_t *,
+            vendor_tag_query_ops_t *ops);
+    // for get_metadata_vendor_tag_ops
+    static const char* get_camera_vendor_section_name(
+            const vendor_tag_query_ops_t *,
+            uint32_t tag);
+    static const char* get_camera_vendor_tag_name(
+            const vendor_tag_query_ops_t *,
+            uint32_t tag);
+    static int get_camera_vendor_tag_type(
+            const vendor_tag_query_ops_t *,
+            uint32_t tag);
+
+    static void dump(const camera3_device_t *, int fd);
+
+    /** For hw_device_t ops */
+    static int close(struct hw_device_t* device);
+
+    /****************************************************************************
+     * Data members shared with implementations
+     ***************************************************************************/
+  protected:
+
+    struct TagOps : public vendor_tag_query_ops {
+        EmulatedCamera3 *parent;
+    };
+    TagOps      mVendorTagOps;
+
+    enum {
+        // State at construction time, and after a device operation error
+        STATUS_ERROR = 0,
+        // State after startup-time init and after device instance close
+        STATUS_CLOSED,
+        // State after being opened, before device instance init
+        STATUS_OPEN,
+        // State after device instance initialization
+        STATUS_READY,
+        // State while actively capturing data
+        STATUS_ACTIVE
+    } mStatus;
+
+    /**
+     * Callbacks back to the framework
+     */
+
+    void sendCaptureResult(camera3_capture_result_t *result);
+    void sendNotify(camera3_notify_msg_t *msg);
+
+    /****************************************************************************
+     * Data members
+     ***************************************************************************/
+  private:
+    static camera3_device_ops_t   sDeviceOps;
+    const camera3_callback_ops_t *mCallbackOps;
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H */
diff --git a/camera/EmulatedCameraFactory.cpp b/camera/EmulatedCameraFactory.cpp
index d36a215..0a8ada7 100755
--- a/camera/EmulatedCameraFactory.cpp
+++ b/camera/EmulatedCameraFactory.cpp
@@ -26,6 +26,7 @@
 #include "EmulatedQemuCamera.h"
 #include "EmulatedFakeCamera.h"
 #include "EmulatedFakeCamera2.h"
+#include "EmulatedFakeCamera3.h"
 #include "EmulatedCameraHotplugThread.h"
 #include "EmulatedCameraFactory.h"
 
@@ -86,6 +87,11 @@
                         new EmulatedFakeCamera2(camera_id, true,
                                 &HAL_MODULE_INFO_SYM.common);
                 break;
+            case 3:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera3(camera_id, true,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
             default:
                 ALOGE("%s: Unknown back camera hal version requested: %d", __FUNCTION__,
                         getBackCameraHalVersion());
@@ -137,6 +143,11 @@
                         new EmulatedFakeCamera2(camera_id, false,
                                 &HAL_MODULE_INFO_SYM.common);
                 break;
+            case 3:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera3(camera_id, false,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
             default:
                 ALOGE("%s: Unknown front camera hal version requested: %d",
                         __FUNCTION__,
diff --git a/camera/EmulatedFakeCamera2.cpp b/camera/EmulatedFakeCamera2.cpp
index ab69063..0fe3a30 100644
--- a/camera/EmulatedFakeCamera2.cpp
+++ b/camera/EmulatedFakeCamera2.cpp
@@ -157,7 +157,7 @@
     mConfigureThread = new ConfigureThread(this);
     mReadoutThread = new ReadoutThread(this);
     mControlThread = new ControlThread(this);
-    mSensor = new Sensor(this);
+    mSensor = new Sensor();
     mJpegCompressor = new JpegCompressor(this);
 
     mNextStreamId = 1;
diff --git a/camera/EmulatedFakeCamera3.cpp b/camera/EmulatedFakeCamera3.cpp
new file mode 100644
index 0000000..8fd4df0
--- /dev/null
+++ b/camera/EmulatedFakeCamera3.cpp
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * Contains implementation of a class EmulatedFakeCamera3 that encapsulates
+ * functionality of an advanced fake camera.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_FakeCamera3"
+#include <utils/Log.h>
+
+#include "EmulatedFakeCamera3.h"
+#include "EmulatedCameraFactory.h"
+#include <ui/Fence.h>
+#include <ui/Rect.h>
+#include <ui/GraphicBufferMapper.h>
+#include "gralloc_cb.h"
+#include "fake-pipeline2/Sensor.h"
+#include "fake-pipeline2/JpegCompressor.h"
+
+namespace android {
+
+/**
+ * Constants for camera capabilities
+ */
+
+const int64_t USEC = 1000LL;
+const int64_t MSEC = USEC * 1000LL;
+const int64_t SEC = MSEC * 1000LL;
+
+const uint32_t EmulatedFakeCamera3::kAvailableFormats[4] = {
+        HAL_PIXEL_FORMAT_RAW_SENSOR,
+        HAL_PIXEL_FORMAT_BLOB,
+        HAL_PIXEL_FORMAT_RGBA_8888,
+        //        HAL_PIXEL_FORMAT_YV12,
+        HAL_PIXEL_FORMAT_YCrCb_420_SP
+};
+
+const uint32_t EmulatedFakeCamera3::kAvailableRawSizes[2] = {
+    640, 480
+    //    Sensor::kResolution[0], Sensor::kResolution[1]
+};
+
+const uint64_t EmulatedFakeCamera3::kAvailableRawMinDurations[1] = {
+    (const uint64_t)Sensor::kFrameDurationRange[0]
+};
+
+const uint32_t EmulatedFakeCamera3::kAvailableProcessedSizesBack[4] = {
+    640, 480, 320, 240
+    //    Sensor::kResolution[0], Sensor::kResolution[1]
+};
+
+const uint32_t EmulatedFakeCamera3::kAvailableProcessedSizesFront[4] = {
+    320, 240, 160, 120
+    //    Sensor::kResolution[0], Sensor::kResolution[1]
+};
+
+const uint64_t EmulatedFakeCamera3::kAvailableProcessedMinDurations[1] = {
+    (const uint64_t)Sensor::kFrameDurationRange[0]
+};
+
+const uint32_t EmulatedFakeCamera3::kAvailableJpegSizesBack[2] = {
+    640, 480
+    //    Sensor::kResolution[0], Sensor::kResolution[1]
+};
+
+const uint32_t EmulatedFakeCamera3::kAvailableJpegSizesFront[2] = {
+    320, 240
+    //    Sensor::kResolution[0], Sensor::kResolution[1]
+};
+
+
+const uint64_t EmulatedFakeCamera3::kAvailableJpegMinDurations[1] = {
+    (const uint64_t)Sensor::kFrameDurationRange[0]
+};
+
+/**
+ * Camera device lifecycle methods
+ */
+
+EmulatedFakeCamera3::EmulatedFakeCamera3(int cameraId, bool facingBack,
+        struct hw_module_t* module) :
+        EmulatedCamera3(cameraId, module),
+        mFacingBack(facingBack) {
+    ALOGD("Constructing emulated fake camera 3 facing %s",
+            facingBack ? "back" : "front");
+
+    for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++) {
+        mDefaultTemplates[i] = NULL;
+    }
+}
+
+EmulatedFakeCamera3::~EmulatedFakeCamera3() {
+    for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++) {
+        if (mDefaultTemplates[i] != NULL) {
+            free_camera_metadata(mDefaultTemplates[i]);
+        }
+    }
+}
+
+status_t EmulatedFakeCamera3::Initialize() {
+    ALOGV("%s: E", __FUNCTION__);
+    status_t res;
+
+    if (mStatus != STATUS_ERROR) {
+        ALOGE("%s: Already initialized!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    res = constructStaticInfo();
+    if (res != OK) {
+        ALOGE("%s: Unable to allocate static info: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    return EmulatedCamera3::Initialize();
+}
+
+status_t EmulatedFakeCamera3::connectCamera(hw_device_t** device) {
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock l(mLock);
+    status_t res;
+
+    if (mStatus != STATUS_CLOSED) {
+        ALOGE("%s: Can't connect in state %d", __FUNCTION__, mStatus);
+        return INVALID_OPERATION;
+    }
+
+    mSensor = new Sensor();
+
+    res = mSensor->startUp();
+    if (res != NO_ERROR) return res;
+
+    mReadoutThread = new ReadoutThread(this);
+
+    res = mReadoutThread->run("EmuCam3::readoutThread");
+    if (res != NO_ERROR) return res;
+
+    return EmulatedCamera3::connectCamera(device);
+}
+
+status_t EmulatedFakeCamera3::closeCamera() {
+    ALOGV("%s: E", __FUNCTION__);
+    status_t res;
+    {
+        Mutex::Autolock l(mLock);
+        if (mStatus == STATUS_CLOSED) return OK;
+
+        res = mSensor->shutDown();
+        if (res != NO_ERROR) {
+            ALOGE("%s: Unable to shut down sensor: %d", __FUNCTION__, res);
+            return res;
+        }
+        mSensor.clear();
+
+        mReadoutThread->requestExit();
+    }
+
+    mReadoutThread->join();
+
+    {
+        Mutex::Autolock l(mLock);
+        // Clear out private stream information
+        for (StreamIterator s = mStreams.begin(); s != mStreams.end(); s++) {
+            PrivateStreamInfo *privStream =
+                    static_cast<PrivateStreamInfo*>((*s)->priv);
+            delete privStream;
+            (*s)->priv = NULL;
+        }
+        mStreams.clear();
+        mReadoutThread.clear();
+    }
+
+    return EmulatedCamera3::closeCamera();
+}
+
+status_t EmulatedFakeCamera3::getCameraInfo(struct camera_info *info) {
+    info->facing = mFacingBack ? CAMERA_FACING_BACK : CAMERA_FACING_FRONT;
+    info->orientation = gEmulatedCameraFactory.getFakeCameraOrientation();
+    return EmulatedCamera3::getCameraInfo(info);
+}
+
+/**
+ * Camera3 interface methods
+ */
+
+status_t EmulatedFakeCamera3::configureStreams(
+        camera3_stream_configuration *streamList) {
+    Mutex::Autolock l(mLock);
+    ALOGV("%s: %d streams", __FUNCTION__, streamList->num_streams);
+
+    if (mStatus != STATUS_OPEN && mStatus != STATUS_READY) {
+        ALOGE("%s: Cannot configure streams in state %d",
+                __FUNCTION__, mStatus);
+        return NO_INIT;
+    }
+
+    /**
+     * Sanity-check input list.
+     */
+    if (streamList == NULL) {
+        ALOGE("%s: NULL stream configuration", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (streamList->streams == NULL) {
+        ALOGE("%s: NULL stream list", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (streamList->num_streams < 1) {
+        ALOGE("%s: Bad number of streams requested: %d", __FUNCTION__,
+                streamList->num_streams);
+        return BAD_VALUE;
+    }
+
+    camera3_stream_t *inputStream = NULL;
+    for (size_t i = 0; i < streamList->num_streams; i++) {
+        camera3_stream_t *newStream = streamList->streams[i];
+        if (newStream->stream_type == CAMERA3_STREAM_INPUT) {
+            if (inputStream != NULL) {
+
+                ALOGE("%s: Multiple input streams requested!", __FUNCTION__);
+                return BAD_VALUE;
+            }
+            inputStream = newStream;
+        }
+    }
+    mInputStream = inputStream;
+
+    /**
+     * Initially mark all existing streams as not alive
+     */
+    for (StreamIterator s = mStreams.begin(); s != mStreams.end(); ++s) {
+        PrivateStreamInfo *privStream =
+                static_cast<PrivateStreamInfo*>((*s)->priv);
+        privStream->alive = false;
+    }
+
+    /**
+     * Find new streams and mark still-alive ones
+     */
+    for (size_t i = 0; i < streamList->num_streams; i++) {
+        camera3_stream_t *newStream = streamList->streams[i];
+        if (newStream->priv == NULL) {
+            // New stream, construct info
+            PrivateStreamInfo *privStream = new PrivateStreamInfo();
+            privStream->alive = true;
+            privStream->registered = false;
+
+            switch (newStream->stream_type) {
+                case CAMERA3_STREAM_OUTPUT:
+                    newStream->usage = GRALLOC_USAGE_HW_CAMERA_WRITE;
+                    break;
+                case CAMERA3_STREAM_INPUT:
+                    newStream->usage = GRALLOC_USAGE_HW_CAMERA_READ;
+                    break;
+                case CAMERA3_STREAM_BIDIRECTIONAL:
+                    newStream->usage = GRALLOC_USAGE_HW_CAMERA_READ |
+                            GRALLOC_USAGE_HW_CAMERA_WRITE;
+                    break;
+            }
+            newStream->max_buffers = kMaxBufferCount;
+            newStream->priv = privStream;
+            mStreams.push_back(newStream);
+        } else {
+            // Existing stream, mark as still alive.
+            PrivateStreamInfo *privStream =
+                    static_cast<PrivateStreamInfo*>(newStream->priv);
+            privStream->alive = true;
+        }
+    }
+
+    /**
+     * Reap the dead streams
+     */
+    for (StreamIterator s = mStreams.begin(); s != mStreams.end();) {
+        PrivateStreamInfo *privStream =
+                static_cast<PrivateStreamInfo*>((*s)->priv);
+        if (!privStream->alive) {
+            (*s)->priv = NULL;
+            delete privStream;
+            s = mStreams.erase(s);
+        } else {
+            ++s;
+        }
+    }
+
+    /**
+     * Can't reuse settings across configure call
+     */
+    mPrevSettings.clear();
+
+    return OK;
+}
+
+status_t EmulatedFakeCamera3::registerStreamBuffers(
+        const camera3_stream_buffer_set *bufferSet) {
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock l(mLock);
+
+    /**
+     * Sanity checks
+     */
+
+    if (mStatus != STATUS_READY) {
+        ALOGE("%s: Cannot register buffers in state %d",
+                __FUNCTION__, mStatus);
+        return NO_INIT;
+    }
+
+    if (bufferSet == NULL) {
+        ALOGE("%s: NULL buffer set!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    StreamIterator s = mStreams.begin();
+    for (; s != mStreams.end(); ++s) {
+        if (bufferSet->stream == *s) break;
+    }
+    if (s == mStreams.end()) {
+        ALOGE("%s: Trying to register buffers for a non-configured stream!",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    /**
+     * Register the buffers. This doesn't mean anything to the emulator besides
+     * marking them off as registered.
+     */
+
+    PrivateStreamInfo *privStream =
+            static_cast<PrivateStreamInfo*>((*s)->priv);
+    privStream->registered = true;
+
+    return OK;
+}
+
+const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings(
+        int type) {
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock l(mLock);
+
+    if (type < 0 || type >= CAMERA2_TEMPLATE_COUNT) {
+        ALOGE("%s: Unknown request settings template: %d",
+                __FUNCTION__, type);
+        return NULL;
+    }
+
+    /**
+     * Cache is not just an optimization - pointer returned has to live at
+     * least as long as the camera device instance does.
+     */
+    if (mDefaultTemplates[type] != NULL) {
+        return mDefaultTemplates[type];
+    }
+
+    CameraMetadata settings;
+
+    /** android.request */
+
+    static const uint8_t requestType = ANDROID_REQUEST_TYPE_CAPTURE;
+    settings.update(ANDROID_REQUEST_TYPE, &requestType, 1);
+
+    static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_MODE_FULL;
+    settings.update(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1);
+
+    static const int32_t id = 0;
+    settings.update(ANDROID_REQUEST_ID, &id, 1);
+
+    static const int32_t frameCount = 0;
+    settings.update(ANDROID_REQUEST_FRAME_COUNT, &frameCount, 1);
+
+    /** android.lens */
+
+    static const float focusDistance = 0;
+    settings.update(ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1);
+
+    static const float aperture = 2.8f;
+    settings.update(ANDROID_LENS_APERTURE, &aperture, 1);
+
+    static const float focalLength = 5.0f;
+    settings.update(ANDROID_LENS_FOCAL_LENGTH, &focalLength, 1);
+
+    static const float filterDensity = 0;
+    settings.update(ANDROID_LENS_FILTER_DENSITY, &filterDensity, 1);
+
+    static const uint8_t opticalStabilizationMode =
+            ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+    settings.update(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+            &opticalStabilizationMode, 1);
+
+    // FOCUS_RANGE set only in frame
+
+    /** android.sensor */
+
+    static const int64_t exposureTime = 10 * MSEC;
+    settings.update(ANDROID_SENSOR_EXPOSURE_TIME, &exposureTime, 1);
+
+    static const int64_t frameDuration = 33333333L; // 1/30 s
+    settings.update(ANDROID_SENSOR_FRAME_DURATION, &frameDuration, 1);
+
+    static const int32_t sensitivity = 100;
+    settings.update(ANDROID_SENSOR_SENSITIVITY, &sensitivity, 1);
+
+    // TIMESTAMP set only in frame
+
+    /** android.flash */
+
+    static const uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
+    settings.update(ANDROID_FLASH_MODE, &flashMode, 1);
+
+    static const uint8_t flashPower = 10;
+    settings.update(ANDROID_FLASH_FIRING_POWER, &flashPower, 1);
+
+    static const int64_t firingTime = 0;
+    settings.update(ANDROID_FLASH_FIRING_TIME, &firingTime, 1);
+
+    /** Processing block modes */
+    uint8_t hotPixelMode = 0;
+    uint8_t demosaicMode = 0;
+    uint8_t noiseMode = 0;
+    uint8_t shadingMode = 0;
+    uint8_t geometricMode = 0;
+    uint8_t colorMode = 0;
+    uint8_t tonemapMode = 0;
+    uint8_t edgeMode = 0;
+    switch (type) {
+      case CAMERA2_TEMPLATE_STILL_CAPTURE:
+        // fall-through
+      case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
+        // fall-through
+      case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
+        hotPixelMode = ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY;
+        demosaicMode = ANDROID_DEMOSAIC_MODE_HIGH_QUALITY;
+        noiseMode = ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY;
+        shadingMode = ANDROID_SHADING_MODE_HIGH_QUALITY;
+        geometricMode = ANDROID_GEOMETRIC_MODE_HIGH_QUALITY;
+        colorMode = ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY;
+        tonemapMode = ANDROID_TONEMAP_MODE_HIGH_QUALITY;
+        edgeMode = ANDROID_EDGE_MODE_HIGH_QUALITY;
+        break;
+      case CAMERA2_TEMPLATE_PREVIEW:
+        // fall-through
+      case CAMERA2_TEMPLATE_VIDEO_RECORD:
+        // fall-through
+      default:
+        hotPixelMode = ANDROID_HOT_PIXEL_MODE_FAST;
+        demosaicMode = ANDROID_DEMOSAIC_MODE_FAST;
+        noiseMode = ANDROID_NOISE_REDUCTION_MODE_FAST;
+        shadingMode = ANDROID_SHADING_MODE_FAST;
+        geometricMode = ANDROID_GEOMETRIC_MODE_FAST;
+        colorMode = ANDROID_COLOR_CORRECTION_MODE_FAST;
+        tonemapMode = ANDROID_TONEMAP_MODE_FAST;
+        edgeMode = ANDROID_EDGE_MODE_FAST;
+        break;
+    }
+    settings.update(ANDROID_HOT_PIXEL_MODE, &hotPixelMode, 1);
+    settings.update(ANDROID_DEMOSAIC_MODE, &demosaicMode, 1);
+    settings.update(ANDROID_NOISE_REDUCTION_MODE, &noiseMode, 1);
+    settings.update(ANDROID_SHADING_MODE, &shadingMode, 1);
+    settings.update(ANDROID_GEOMETRIC_MODE, &geometricMode, 1);
+    settings.update(ANDROID_COLOR_CORRECTION_MODE, &colorMode, 1);
+    settings.update(ANDROID_TONEMAP_MODE, &tonemapMode, 1);
+    settings.update(ANDROID_EDGE_MODE, &edgeMode, 1);
+
+    /** android.noise */
+    static const uint8_t noiseStrength = 5;
+    settings.update(ANDROID_NOISE_REDUCTION_STRENGTH, &noiseStrength, 1);
+
+    /** android.color */
+    static const float colorTransform[9] = {
+        1.0f, 0.f, 0.f,
+        0.f, 1.f, 0.f,
+        0.f, 0.f, 1.f
+    };
+    settings.update(ANDROID_COLOR_CORRECTION_TRANSFORM, colorTransform, 9);
+
+    /** android.tonemap */
+    static const float tonemapCurve[4] = {
+        0.f, 0.f,
+        1.f, 1.f
+    };
+    settings.update(ANDROID_TONEMAP_CURVE_RED, tonemapCurve, 4);
+    settings.update(ANDROID_TONEMAP_CURVE_GREEN, tonemapCurve, 4);
+    settings.update(ANDROID_TONEMAP_CURVE_BLUE, tonemapCurve, 4);
+
+    /** android.edge */
+    static const uint8_t edgeStrength = 5;
+    settings.update(ANDROID_EDGE_STRENGTH, &edgeStrength, 1);
+
+    /** android.scaler */
+    static const int32_t cropRegion[3] = {
+        0, 0, (int32_t)Sensor::kResolution[0]
+    };
+    settings.update(ANDROID_SCALER_CROP_REGION, cropRegion, 3);
+
+    /** android.jpeg */
+    static const uint8_t jpegQuality = 80;
+    settings.update(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
+
+    static const int32_t thumbnailSize[2] = {
+        640, 480
+    };
+    settings.update(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
+
+    static const uint8_t thumbnailQuality = 80;
+    settings.update(ANDROID_JPEG_THUMBNAIL_QUALITY, &thumbnailQuality, 1);
+
+    static const double gpsCoordinates[2] = {
+        0, 0
+    };
+    settings.update(ANDROID_JPEG_GPS_COORDINATES, gpsCoordinates, 2);
+
+    static const uint8_t gpsProcessingMethod[32] = "None";
+    settings.update(ANDROID_JPEG_GPS_PROCESSING_METHOD, gpsProcessingMethod, 32);
+
+    static const int64_t gpsTimestamp = 0;
+    settings.update(ANDROID_JPEG_GPS_TIMESTAMP, &gpsTimestamp, 1);
+
+    static const int32_t jpegOrientation = 0;
+    settings.update(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
+
+    /** android.stats */
+
+    static const uint8_t faceDetectMode =
+        ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+    settings.update(ANDROID_STATISTICS_FACE_DETECT_MODE, &faceDetectMode, 1);
+
+    static const uint8_t histogramMode = ANDROID_STATISTICS_HISTOGRAM_MODE_OFF;
+    settings.update(ANDROID_STATISTICS_HISTOGRAM_MODE, &histogramMode, 1);
+
+    static const uint8_t sharpnessMapMode =
+        ANDROID_STATISTICS_SHARPNESS_MAP_MODE_OFF;
+    settings.update(ANDROID_STATISTICS_SHARPNESS_MAP_MODE, &sharpnessMapMode, 1);
+
+    // faceRectangles, faceScores, faceLandmarks, faceIds, histogram,
+    // sharpnessMap only in frames
+
+    /** android.control */
+
+    uint8_t controlIntent = 0;
+    switch (type) {
+      case CAMERA2_TEMPLATE_PREVIEW:
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+        break;
+      case CAMERA2_TEMPLATE_STILL_CAPTURE:
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
+        break;
+      case CAMERA2_TEMPLATE_VIDEO_RECORD:
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+        break;
+      case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
+        break;
+      case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
+        break;
+      default:
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM;
+        break;
+    }
+    settings.update(ANDROID_CONTROL_CAPTURE_INTENT, &controlIntent, 1);
+
+    static const uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;
+    settings.update(ANDROID_CONTROL_MODE, &controlMode, 1);
+
+    static const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
+    settings.update(ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
+
+    static const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
+    settings.update(ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
+
+    static const uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH;
+    settings.update(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
+    static const uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;
+    settings.update(ANDROID_CONTROL_AE_LOCK, &aeLock, 1);
+
+    static const int32_t controlRegions[5] = {
+        0, 0, (int32_t)Sensor::kResolution[0], (int32_t)Sensor::kResolution[1],
+        1000
+    };
+    settings.update(ANDROID_CONTROL_AE_REGIONS, controlRegions, 5);
+
+    static const int32_t aeExpCompensation = 0;
+    settings.update(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &aeExpCompensation, 1);
+
+    static const int32_t aeTargetFpsRange[2] = {
+        10, 30
+    };
+    settings.update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, aeTargetFpsRange, 2);
+
+    static const uint8_t aeAntibandingMode =
+            ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+    settings.update(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &aeAntibandingMode, 1);
+
+    static const uint8_t awbMode =
+            ANDROID_CONTROL_AWB_MODE_AUTO;
+    settings.update(ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
+
+    static const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+    settings.update(ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+    settings.update(ANDROID_CONTROL_AWB_REGIONS, controlRegions, 5);
+
+    uint8_t afMode = 0;
+    switch (type) {
+      case CAMERA2_TEMPLATE_PREVIEW:
+        afMode = ANDROID_CONTROL_AF_MODE_AUTO;
+        break;
+      case CAMERA2_TEMPLATE_STILL_CAPTURE:
+        afMode = ANDROID_CONTROL_AF_MODE_AUTO;
+        break;
+      case CAMERA2_TEMPLATE_VIDEO_RECORD:
+        afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+        break;
+      case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
+        afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+        break;
+      case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
+        afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+        break;
+      default:
+        afMode = ANDROID_CONTROL_AF_MODE_AUTO;
+        break;
+    }
+    settings.update(ANDROID_CONTROL_AF_MODE, &afMode, 1);
+
+    settings.update(ANDROID_CONTROL_AF_REGIONS, controlRegions, 5);
+
+    static const uint8_t vstabMode =
+        ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+    settings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &vstabMode, 1);
+
+    // aeState, awbState, afState only in frame
+
+    mDefaultTemplates[type] = settings.release();
+
+    return mDefaultTemplates[type];
+}
+
+status_t EmulatedFakeCamera3::processCaptureRequest(
+        camera3_capture_request *request) {
+
+    Mutex::Autolock l(mLock);
+    status_t res;
+
+    /** Validation */
+
+    if (mStatus < STATUS_READY) {
+        ALOGE("%s: Can't submit capture requests in state %d", __FUNCTION__,
+                mStatus);
+        return INVALID_OPERATION;
+    }
+
+    if (request == NULL) {
+        ALOGE("%s: NULL request!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    uint32_t frameNumber = request->frame_number;
+
+    if (request->settings == NULL && mPrevSettings.isEmpty()) {
+        ALOGE("%s: Request %d: NULL settings for first request after"
+                "configureStreams()", __FUNCTION__, frameNumber);
+        return BAD_VALUE;
+    }
+
+    if (request->input_buffer != NULL &&
+            request->input_buffer->stream != mInputStream) {
+        ALOGE("%s: Request %d: Input buffer not from input stream!",
+                __FUNCTION__, frameNumber);
+        return BAD_VALUE;
+    }
+
+    if (request->num_output_buffers < 1 || request->output_buffers == NULL) {
+        ALOGE("%s: Request %d: No output buffers provided!",
+                __FUNCTION__, frameNumber);
+        return BAD_VALUE;
+    }
+
+    // Validate all buffers, starting with input buffer if it's given
+
+    ssize_t idx;
+    const camera3_stream_buffer_t *b;
+    if (request->input_buffer != NULL) {
+        idx = -1;
+        b = request->input_buffer;
+    } else {
+        idx = 0;
+        b = request->output_buffers;
+    }
+    do {
+        PrivateStreamInfo *priv =
+                static_cast<PrivateStreamInfo*>(b->stream->priv);
+        if (priv == NULL) {
+            ALOGE("%s: Request %d: Buffer %d: Unconfigured stream!",
+                    __FUNCTION__, frameNumber, idx);
+            return BAD_VALUE;
+        }
+        if (!priv->alive || !priv->registered) {
+            ALOGE("%s: Request %d: Buffer %d: Unregistered or dead stream!",
+                    __FUNCTION__, frameNumber, idx);
+            return BAD_VALUE;
+        }
+        if (b->status != CAMERA3_BUFFER_STATUS_OK) {
+            ALOGE("%s: Request %d: Buffer %d: Status not OK!",
+                    __FUNCTION__, frameNumber, idx);
+            return BAD_VALUE;
+        }
+        if (b->release_fence != -1) {
+            ALOGE("%s: Request %d: Buffer %d: Has a release fence!",
+                    __FUNCTION__, frameNumber, idx);
+            return BAD_VALUE;
+        }
+        if (b->buffer == NULL) {
+            ALOGE("%s: Request %d: Buffer %d: NULL buffer handle!",
+                    __FUNCTION__, frameNumber, idx);
+            return BAD_VALUE;
+        }
+        idx++;
+        b = &(request->output_buffers[idx]);
+    } while (idx < (ssize_t)request->num_output_buffers);
+
+    // TODO: Validate settings parameters
+
+    /**
+     * Start processing this request
+     */
+
+    mStatus = STATUS_ACTIVE;
+
+    CameraMetadata settings;
+
+    if (request->settings == NULL) {
+        settings.acquire(mPrevSettings);
+    } else {
+        settings = request->settings;
+    }
+
+    // TODO: Apply 3A overrides
+
+    // TODO: Handle reprocessing
+
+    /**
+     * Get ready for sensor config
+     */
+
+    nsecs_t  exposureTime;
+    nsecs_t  frameDuration;
+    uint32_t sensitivity;
+
+    exposureTime = settings.find(ANDROID_SENSOR_EXPOSURE_TIME).data.i64[0];
+    frameDuration = settings.find(ANDROID_SENSOR_FRAME_DURATION).data.i64[0];
+    sensitivity = settings.find(ANDROID_SENSOR_SENSITIVITY).data.i32[0];
+
+    Buffers *sensorBuffers = new Buffers();
+    Vector<camera3_stream_buffer> *buffers = new Vector<camera3_stream_buffer>();
+
+    sensorBuffers->setCapacity(request->num_output_buffers);
+    buffers->setCapacity(request->num_output_buffers);
+
+    // Process all the buffers we got for output, constructing internal buffer
+    // structures for them, and lock them for writing.
+    for (size_t i = 0; i < request->num_output_buffers; i++) {
+        const camera3_stream_buffer &srcBuf = request->output_buffers[i];
+        const cb_handle_t *privBuffer =
+                static_cast<const cb_handle_t*>(*srcBuf.buffer);
+        StreamBuffer destBuf;
+        destBuf.streamId = 0;
+        destBuf.width  = srcBuf.stream->width;
+        destBuf.height = srcBuf.stream->height;
+        destBuf.format = privBuffer->format; // Use real private format
+        destBuf.stride = srcBuf.stream->width; // TODO: query from gralloc
+        destBuf.buffer = srcBuf.buffer;
+
+        // Wait on fence
+        sp<Fence> bufferAcquireFence = new Fence(srcBuf.acquire_fence);
+        res = bufferAcquireFence->wait(kFenceTimeoutMs);
+        if (res == TIMED_OUT) {
+            ALOGE("%s: Request %d: Buffer %d: Fence timed out after %d ms",
+                    __FUNCTION__, frameNumber, i, kFenceTimeoutMs);
+        }
+        if (res == OK) {
+            // Lock buffer for writing
+            const Rect rect(destBuf.width, destBuf.height);
+            res = GraphicBufferMapper::get().lock(*(destBuf.buffer),
+                    GRALLOC_USAGE_HW_CAMERA_WRITE, rect, (void**)&(destBuf.img));
+            if (res != OK) {
+                ALOGE("%s: Request %d: Buffer %d: Unable to lock buffer",
+                        __FUNCTION__, frameNumber, i);
+            }
+        }
+
+        if (res != OK) {
+            // Either waiting or locking failed. Unlock locked buffers and bail out.
+            for (size_t j = 0; j < i; j++) {
+                GraphicBufferMapper::get().unlock(
+                        *(request->output_buffers[i].buffer));
+            }
+            return NO_INIT;
+        }
+
+        sensorBuffers->push_back(destBuf);
+        buffers->push_back(srcBuf);
+    }
+
+    /**
+     * Wait until the in-flight queue has room
+     */
+    res = mReadoutThread->waitForReadout();
+    if (res != OK) {
+        return NO_INIT;
+    }
+
+    /**
+     * Wait until sensor's ready. This waits for lengthy amounts of time with
+     * mLock held, but the interface spec is that no other calls may by done to
+     * the HAL by the framework while process_capture_request is happening.
+     */
+    int syncTimeoutCount = 0;
+    while(!mSensor->waitForVSync(kSyncWaitTimeout)) {
+        if (mStatus == STATUS_ERROR) {
+            return NO_INIT;
+        }
+        if (syncTimeoutCount == kMaxSyncTimeoutCount) {
+            ALOGE("%s: Request %d: Sensor sync timed out after %lld ms",
+                    __FUNCTION__, frameNumber,
+                    kSyncWaitTimeout * kMaxSyncTimeoutCount / 1000000);
+            return NO_INIT;
+        }
+        syncTimeoutCount++;
+    }
+
+    /**
+     * Configure sensor and queue up the request to the readout thread
+     */
+    mSensor->setExposureTime(exposureTime);
+    mSensor->setFrameDuration(frameDuration);
+    mSensor->setSensitivity(sensitivity);
+    mSensor->setDestinationBuffers(sensorBuffers);
+
+    ReadoutThread::Request r;
+    r.frameNumber = request->frame_number;
+    r.settings = settings;
+    r.sensorBuffers = sensorBuffers;
+    r.buffers = buffers;
+
+    mReadoutThread->queueCaptureRequest(r);
+
+    // Cache the settings for next time
+    mPrevSettings.acquire(settings);
+
+    return OK;
+}
+
+/** Debug methods */
+
+void EmulatedFakeCamera3::dump(int fd) {
+
+}
+
+/** Tag query methods */
+const char* EmulatedFakeCamera3::getVendorSectionName(uint32_t tag) {
+    return NULL;
+}
+
+const char* EmulatedFakeCamera3::getVendorTagName(uint32_t tag) {
+    return NULL;
+}
+
+int EmulatedFakeCamera3::getVendorTagType(uint32_t tag) {
+    return 0;
+}
+
+/**
+ * Private methods
+ */
+
+status_t EmulatedFakeCamera3::constructStaticInfo() {
+
+    CameraMetadata info;
+    // android.lens
+
+    // 5 cm min focus distance for back camera, infinity (fixed focus) for front
+    const float minFocusDistance = mFacingBack ? 1.0/0.05 : 0.0;
+    info.update(ANDROID_LENS_INFO_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;
+    info.update(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
+            &minFocusDistance, 1);
+
+    static const float focalLength = 3.30f; // mm
+    info.update(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
+            &focalLength, 1);
+    static const float aperture = 2.8f;
+    info.update(ANDROID_LENS_INFO_AVAILABLE_APERTURES,
+            &aperture, 1);
+    static const float filterDensity = 0;
+    info.update(ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
+            &filterDensity, 1);
+    static const uint8_t availableOpticalStabilization =
+            ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+    info.update(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+            &availableOpticalStabilization, 1);
+
+    static const int32_t lensShadingMapSize[] = {1, 1};
+    info.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, lensShadingMapSize,
+            sizeof(lensShadingMapSize)/sizeof(int32_t));
+
+    static const float lensShadingMap[3 * 1 * 1 ] =
+            { 1.f, 1.f, 1.f };
+    info.update(ANDROID_LENS_INFO_SHADING_MAP, lensShadingMap,
+            sizeof(lensShadingMap)/sizeof(float));
+
+    // Identity transform
+    static const int32_t geometricCorrectionMapSize[] = {2, 2};
+    info.update(ANDROID_LENS_INFO_GEOMETRIC_CORRECTION_MAP_SIZE,
+            geometricCorrectionMapSize,
+            sizeof(geometricCorrectionMapSize)/sizeof(int32_t));
+
+    static const float geometricCorrectionMap[2 * 3 * 2 * 2] = {
+            0.f, 0.f,  0.f, 0.f,  0.f, 0.f,
+            1.f, 0.f,  1.f, 0.f,  1.f, 0.f,
+            0.f, 1.f,  0.f, 1.f,  0.f, 1.f,
+            1.f, 1.f,  1.f, 1.f,  1.f, 1.f};
+    info.update(ANDROID_LENS_INFO_GEOMETRIC_CORRECTION_MAP,
+            geometricCorrectionMap,
+            sizeof(geometricCorrectionMap)/sizeof(float));
+
+    uint8_t lensFacing = mFacingBack ?
+            ANDROID_LENS_FACING_BACK : ANDROID_LENS_FACING_FRONT;
+    info.update(ANDROID_LENS_FACING, &lensFacing, 1);
+
+    float lensPosition[3];
+    if (mFacingBack) {
+        // Back-facing camera is center-top on device
+        lensPosition[0] = 0;
+        lensPosition[1] = 20;
+        lensPosition[2] = -5;
+    } else {
+        // Front-facing camera is center-right on device
+        lensPosition[0] = 20;
+        lensPosition[1] = 20;
+        lensPosition[2] = 0;
+    }
+    info.update(ANDROID_LENS_POSITION, lensPosition, sizeof(lensPosition)/
+            sizeof(float));
+
+    // android.sensor
+
+    info.update(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
+            Sensor::kExposureTimeRange, 2);
+
+    info.update(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+            &Sensor::kFrameDurationRange[1], 1);
+
+    info.update(ANDROID_SENSOR_INFO_AVAILABLE_SENSITIVITIES,
+            (int32_t*)Sensor::kAvailableSensitivities,
+            sizeof(Sensor::kAvailableSensitivities)
+            /sizeof(uint32_t));
+
+    info.update(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
+            &Sensor::kColorFilterArrangement, 1);
+
+    static const float sensorPhysicalSize[2] = {3.20f, 2.40f}; // mm
+    info.update(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
+            sensorPhysicalSize, 2);
+
+    info.update(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+            (int32_t*)Sensor::kResolution, 2);
+
+    info.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+            (int32_t*)Sensor::kResolution, 2);
+
+    info.update(ANDROID_SENSOR_INFO_WHITE_LEVEL,
+            (int32_t*)&Sensor::kMaxRawValue, 1);
+
+    static const int32_t blackLevelPattern[4] = {
+            (int32_t)Sensor::kBlackLevel, (int32_t)Sensor::kBlackLevel,
+            (int32_t)Sensor::kBlackLevel, (int32_t)Sensor::kBlackLevel
+    };
+    info.update(ANDROID_SENSOR_BLACK_LEVEL_PATTERN,
+            blackLevelPattern, sizeof(blackLevelPattern)/sizeof(int32_t));
+
+    //TODO: sensor color calibration fields
+
+    // android.flash
+    static const uint8_t flashAvailable = 0;
+    info.update(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1);
+
+    static const int64_t flashChargeDuration = 0;
+    info.update(ANDROID_FLASH_INFO_CHARGE_DURATION, &flashChargeDuration, 1);
+
+    // android.tonemap
+
+    static const int32_t tonemapCurvePoints = 128;
+    info.update(ANDROID_TONEMAP_MAX_CURVE_POINTS, &tonemapCurvePoints, 1);
+
+    // android.scaler
+
+    info.update(ANDROID_SCALER_AVAILABLE_FORMATS,
+            (int32_t*)kAvailableFormats,
+            sizeof(kAvailableFormats)/sizeof(uint32_t));
+
+    info.update(ANDROID_SCALER_AVAILABLE_RAW_SIZES,
+            (int32_t*)kAvailableRawSizes,
+            sizeof(kAvailableRawSizes)/sizeof(uint32_t));
+
+    info.update(ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
+            (int64_t*)kAvailableRawMinDurations,
+            sizeof(kAvailableRawMinDurations)/sizeof(uint64_t));
+
+    if (mFacingBack) {
+        info.update(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
+                (int32_t*)kAvailableProcessedSizesBack,
+                sizeof(kAvailableProcessedSizesBack)/sizeof(uint32_t));
+    } else {
+        info.update(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
+                (int32_t*)kAvailableProcessedSizesFront,
+                sizeof(kAvailableProcessedSizesFront)/sizeof(uint32_t));
+    }
+
+    info.update(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
+            (int64_t*)kAvailableProcessedMinDurations,
+            sizeof(kAvailableProcessedMinDurations)/sizeof(uint64_t));
+
+    if (mFacingBack) {
+        info.update(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
+                (int32_t*)kAvailableJpegSizesBack,
+                sizeof(kAvailableJpegSizesBack)/sizeof(uint32_t));
+    } else {
+        info.update(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
+                (int32_t*)kAvailableJpegSizesFront,
+                sizeof(kAvailableJpegSizesFront)/sizeof(uint32_t));
+    }
+
+    info.update(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
+            (int64_t*)kAvailableJpegMinDurations,
+            sizeof(kAvailableJpegMinDurations)/sizeof(uint64_t));
+
+    static const int32_t maxZoom = 10;
+    info.update(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+            &maxZoom, 1);
+
+    // android.jpeg
+
+    static const int32_t jpegThumbnailSizes[] = {
+            0, 0,
+            160, 120,
+            320, 240
+     };
+    info.update(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+            jpegThumbnailSizes, sizeof(jpegThumbnailSizes)/sizeof(int32_t));
+
+    static const int32_t jpegMaxSize = JpegCompressor::kMaxJpegSize;
+    info.update(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
+
+    // android.stats
+
+    static const uint8_t availableFaceDetectModes[] = {
+        ANDROID_STATISTICS_FACE_DETECT_MODE_OFF,
+        ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE,
+        ANDROID_STATISTICS_FACE_DETECT_MODE_FULL
+    };
+
+    info.update(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+            availableFaceDetectModes,
+            sizeof(availableFaceDetectModes));
+
+    static const int32_t maxFaceCount = 8;
+    info.update(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
+            &maxFaceCount, 1);
+
+    static const int32_t histogramSize = 64;
+    info.update(ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT,
+            &histogramSize, 1);
+
+    static const int32_t maxHistogramCount = 1000;
+    info.update(ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
+            &maxHistogramCount, 1);
+
+    static const int32_t sharpnessMapSize[2] = {64, 64};
+    info.update(ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
+            sharpnessMapSize, sizeof(sharpnessMapSize)/sizeof(int32_t));
+
+    static const int32_t maxSharpnessMapValue = 1000;
+    info.update(ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
+            &maxSharpnessMapValue, 1);
+
+    // android.control
+
+    static const uint8_t availableSceneModes[] = {
+            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED
+    };
+    info.update(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+            availableSceneModes, sizeof(availableSceneModes));
+
+    static const uint8_t availableEffects[] = {
+            ANDROID_CONTROL_EFFECT_MODE_OFF
+    };
+    info.update(ANDROID_CONTROL_AVAILABLE_EFFECTS,
+            availableEffects, sizeof(availableEffects));
+
+    int32_t max3aRegions = 0;
+    info.update(ANDROID_CONTROL_MAX_REGIONS,
+            &max3aRegions, 1);
+
+    static const uint8_t availableAeModes[] = {
+            ANDROID_CONTROL_AE_MODE_OFF,
+            ANDROID_CONTROL_AE_MODE_ON
+    };
+    info.update(ANDROID_CONTROL_AE_AVAILABLE_MODES,
+            availableAeModes, sizeof(availableAeModes));
+
+    static const camera_metadata_rational exposureCompensationStep = {
+            1, 3
+    };
+    info.update(ANDROID_CONTROL_AE_COMPENSATION_STEP,
+            &exposureCompensationStep, 1);
+
+    int32_t exposureCompensationRange[] = {-9, 9};
+    info.update(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+            exposureCompensationRange,
+            sizeof(exposureCompensationRange)/sizeof(int32_t));
+
+    static const int32_t availableTargetFpsRanges[] = {
+            5, 30, 15, 30
+    };
+    info.update(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+            availableTargetFpsRanges,
+            sizeof(availableTargetFpsRanges)/sizeof(int32_t));
+
+    static const uint8_t availableAntibandingModes[] = {
+            ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
+            ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO
+    };
+    info.update(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+            availableAntibandingModes, sizeof(availableAntibandingModes));
+
+    static const uint8_t availableAwbModes[] = {
+            ANDROID_CONTROL_AWB_MODE_OFF,
+            ANDROID_CONTROL_AWB_MODE_AUTO,
+            ANDROID_CONTROL_AWB_MODE_INCANDESCENT,
+            ANDROID_CONTROL_AWB_MODE_FLUORESCENT,
+            ANDROID_CONTROL_AWB_MODE_DAYLIGHT,
+            ANDROID_CONTROL_AWB_MODE_SHADE
+    };
+    info.update(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+            availableAwbModes, sizeof(availableAwbModes));
+
+    static const uint8_t availableAfModesBack[] = {
+            ANDROID_CONTROL_AF_MODE_OFF,
+            ANDROID_CONTROL_AF_MODE_AUTO,
+            ANDROID_CONTROL_AF_MODE_MACRO,
+            ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
+            ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE
+    };
+
+    static const uint8_t availableAfModesFront[] = {
+            ANDROID_CONTROL_AF_MODE_OFF
+    };
+
+    if (mFacingBack) {
+        info.update(ANDROID_CONTROL_AF_AVAILABLE_MODES,
+                    availableAfModesBack, sizeof(availableAfModesBack));
+    } else {
+        info.update(ANDROID_CONTROL_AF_AVAILABLE_MODES,
+                    availableAfModesFront, sizeof(availableAfModesFront));
+    }
+
+    static const uint8_t availableVstabModes[] = {
+            ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF
+    };
+    info.update(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+            availableVstabModes, sizeof(availableVstabModes));
+
+    mCameraInfo = info.release();
+
+    return OK;
+}
+
+void EmulatedFakeCamera3::signalReadoutIdle() {
+    Mutex::Autolock l(mLock);
+    // Need to chek isIdle again because waiting on mLock may have allowed
+    // something to be placed in the in-flight queue.
+    if (mStatus == STATUS_ACTIVE && mReadoutThread->isIdle()) {
+        ALOGV("Now idle");
+        mStatus = STATUS_READY;
+    }
+}
+
+EmulatedFakeCamera3::ReadoutThread::ReadoutThread(EmulatedFakeCamera3 *parent) :
+        mParent(parent) {
+}
+
+EmulatedFakeCamera3::ReadoutThread::~ReadoutThread() {
+    for (List<Request>::iterator i = mInFlightQueue.begin();
+         i != mInFlightQueue.end(); i++) {
+        delete i->buffers;
+        delete i->sensorBuffers;
+    }
+}
+
+void EmulatedFakeCamera3::ReadoutThread::queueCaptureRequest(const Request &r) {
+    Mutex::Autolock l(mLock);
+
+    mInFlightQueue.push_back(r);
+    mInFlightSignal.signal();
+}
+
+bool EmulatedFakeCamera3::ReadoutThread::isIdle() {
+    Mutex::Autolock l(mLock);
+    return mInFlightQueue.empty() && !mThreadActive;
+}
+
+status_t EmulatedFakeCamera3::ReadoutThread::waitForReadout() {
+    status_t res;
+    Mutex::Autolock l(mLock);
+    int loopCount = 0;
+    while (mInFlightQueue.size() >= kMaxQueueSize) {
+        res = mInFlightSignal.waitRelative(mLock, kWaitPerLoop);
+        if (res != OK && res != TIMED_OUT) {
+            ALOGE("%s: Error waiting for in-flight queue to shrink",
+                    __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+        if (loopCount == kMaxWaitLoops) {
+            ALOGE("%s: Timed out waiting for in-flight queue to shrink",
+                    __FUNCTION__);
+            return TIMED_OUT;
+        }
+        loopCount++;
+    }
+    return OK;
+}
+
+bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
+    status_t res;
+
+    // First wait for a request from the in-flight queue
+
+    if (mCurrentRequest.settings.isEmpty()) {
+        Mutex::Autolock l(mLock);
+        if (mInFlightQueue.empty()) {
+            res = mInFlightSignal.waitRelative(mLock, kWaitPerLoop);
+            if (res == TIMED_OUT) {
+                return true;
+            } else if (res != NO_ERROR) {
+                ALOGE("%s: Error waiting for capture requests: %d",
+                        __FUNCTION__, res);
+                return false;
+            }
+        }
+        mCurrentRequest.frameNumber = mInFlightQueue.begin()->frameNumber;
+        mCurrentRequest.settings.acquire(mInFlightQueue.begin()->settings);
+        mCurrentRequest.buffers = mInFlightQueue.begin()->buffers;
+        mCurrentRequest.sensorBuffers = mInFlightQueue.begin()->sensorBuffers;
+        mInFlightQueue.erase(mInFlightQueue.begin());
+        mInFlightSignal.signal();
+        mThreadActive = true;
+    }
+
+    // Then wait for it to be delivered from the sensor
+
+    nsecs_t captureTime;
+    bool gotFrame =
+            mParent->mSensor->waitForNewFrame(kWaitPerLoop, &captureTime);
+    if (!gotFrame) return true;
+
+    // Got everything, construct result
+
+    camera3_capture_result result;
+
+    mCurrentRequest.settings.update(ANDROID_SENSOR_TIMESTAMP,
+            &captureTime, 1);
+
+    for (size_t i = 0; i < mCurrentRequest.buffers->size(); i++) {
+        camera3_stream_buffer &buf = mCurrentRequest.buffers->editItemAt(i);
+
+        GraphicBufferMapper::get().unlock(*buf.buffer);
+
+        buf.status = CAMERA3_BUFFER_STATUS_OK;
+        buf.acquire_fence = -1;
+        buf.release_fence = -1;
+    }
+
+    result.frame_number = mCurrentRequest.frameNumber;
+    result.result = mCurrentRequest.settings.getAndLock();
+    result.num_output_buffers = mCurrentRequest.buffers->size();
+    result.output_buffers = mCurrentRequest.buffers->array();
+
+    // Go idle if queue is empty, before sending result
+    bool signalIdle = false;
+    {
+        Mutex::Autolock l(mLock);
+        if (mInFlightQueue.empty()) {
+            mThreadActive = false;
+            signalIdle = true;
+        }
+    }
+    if (signalIdle) mParent->signalReadoutIdle();
+
+    // Send it off to the framework
+
+    mParent->sendCaptureResult(&result);
+
+    // Clean up
+    mCurrentRequest.settings.unlock(result.result);
+
+    delete mCurrentRequest.buffers;
+    mCurrentRequest.buffers = NULL;
+    delete mCurrentRequest.sensorBuffers;
+    mCurrentRequest.sensorBuffers = NULL;
+    mCurrentRequest.settings.clear();
+
+    return true;
+}
+
+
+}; // namespace android
diff --git a/camera/EmulatedFakeCamera3.h b/camera/EmulatedFakeCamera3.h
new file mode 100644
index 0000000..74f8496
--- /dev/null
+++ b/camera/EmulatedFakeCamera3.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA3_H
+#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA3_H
+
+/**
+ * Contains declaration of a class EmulatedCamera that encapsulates
+ * functionality of a fake camera that implements version 3 of the camera device
+ * interace.
+ */
+
+#include "EmulatedCamera3.h"
+#include "fake-pipeline2/Base.h"
+#include "fake-pipeline2/Sensor.h"
+#include "fake-pipeline2/JpegCompressor.h"
+#include <camera/CameraMetadata.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+/* Encapsulates functionality common to all version 3.0 emulated camera devices
+ *
+ * Note that EmulatedCameraFactory instantiates an object of this class just
+ * once, when EmulatedCameraFactory instance gets constructed. Connection to /
+ * disconnection from the actual camera device is handled by calls to
+ * connectDevice(), and closeCamera() methods of this class that are invoked in
+ * response to hw_module_methods_t::open, and camera_device::close callbacks.
+ */
+class EmulatedFakeCamera3 : public EmulatedCamera3 {
+public:
+
+    EmulatedFakeCamera3(int cameraId, bool facingBack,
+            struct hw_module_t* module);
+
+    virtual ~EmulatedFakeCamera3();
+
+    /****************************************************************************
+     * EmulatedCamera3 virtual overrides
+     ***************************************************************************/
+
+public:
+
+    virtual status_t Initialize();
+
+    /****************************************************************************
+     * Camera module API and generic hardware device API implementation
+     ***************************************************************************/
+
+public:
+    virtual status_t connectCamera(hw_device_t** device);
+
+    virtual status_t closeCamera();
+
+    virtual status_t getCameraInfo(struct camera_info *info);
+
+    /****************************************************************************
+     * EmualtedCamera3 abstract API implementation
+     ***************************************************************************/
+
+protected:
+
+    virtual status_t configureStreams(
+        camera3_stream_configuration *streamList);
+
+    virtual status_t registerStreamBuffers(
+        const camera3_stream_buffer_set *bufferSet) ;
+
+    virtual const camera_metadata_t* constructDefaultRequestSettings(
+        int type);
+
+    virtual status_t processCaptureRequest(camera3_capture_request *request);
+
+    /** Debug methods */
+
+    virtual void dump(int fd);
+
+    /** Tag query methods */
+    virtual const char *getVendorSectionName(uint32_t tag);
+
+    virtual const char *getVendorTagName(uint32_t tag);
+
+    virtual int getVendorTagType(uint32_t tag);
+
+private:
+
+    status_t constructStaticInfo();
+
+    /** Signal from readout thread that it doesn't have anything to do */
+    void     signalReadoutIdle();
+
+    /****************************************************************************
+     * Static configuration information
+     ***************************************************************************/
+private:
+    static const uint32_t kMaxRawStreamCount = 1;
+    static const uint32_t kMaxProcessedStreamCount = 3;
+    static const uint32_t kMaxJpegStreamCount = 1;
+    static const uint32_t kMaxReprocessStreamCount = 2;
+    static const uint32_t kMaxBufferCount = 4;
+    static const uint32_t kAvailableFormats[];
+    static const uint32_t kAvailableRawSizes[];
+    static const uint64_t kAvailableRawMinDurations[];
+    static const uint32_t kAvailableProcessedSizesBack[];
+    static const uint32_t kAvailableProcessedSizesFront[];
+    static const uint64_t kAvailableProcessedMinDurations[];
+    static const uint32_t kAvailableJpegSizesBack[];
+    static const uint32_t kAvailableJpegSizesFront[];
+    static const uint64_t kAvailableJpegMinDurations[];
+
+    static const int64_t  kSyncWaitTimeout     = 10000000; // 10 ms
+    static const int32_t  kMaxSyncTimeoutCount = 1000; // 1000 kSyncWaitTimeouts
+    static const uint32_t kFenceTimeoutMs      = 2000; // 2 s
+
+    /****************************************************************************
+     * Data members.
+     ***************************************************************************/
+
+    /* HAL interface serialization lock. */
+    Mutex mLock;
+
+    /* Facing back (true) or front (false) switch. */
+    bool mFacingBack;
+
+    /**
+     * Cache for default templates. Once one is requested, the pointer must be
+     * valid at least until close() is called on the device
+     */
+    camera_metadata_t *mDefaultTemplates[CAMERA3_TEMPLATE_COUNT];
+
+    /**
+     * Private stream information, stored in camera3_stream_t->priv.
+     */
+    struct PrivateStreamInfo {
+        bool alive;
+        bool registered;
+    };
+
+    // Shortcut to the input stream
+    camera3_stream_t* mInputStream;
+
+    // All streams, including input stream
+    List<camera3_stream_t*> mStreams;
+
+    typedef List<camera3_stream_t*>::iterator StreamIterator;
+
+    // Cached settings from latest submitted request
+    CameraMetadata mPrevSettings;
+
+    /** Fake hardware interfaces */
+    sp<Sensor> mSensor;
+    sp<JpegCompressor> mJpegCompressor;
+
+    /** Processing thread for sending out results */
+
+    class ReadoutThread : public Thread {
+      public:
+        ReadoutThread(EmulatedFakeCamera3 *parent);
+        ~ReadoutThread();
+
+        struct Request {
+            uint32_t frameNumber;
+            CameraMetadata settings;
+            Vector<camera3_stream_buffer> *buffers;
+            Buffers *sensorBuffers;
+        };
+
+        void queueCaptureRequest(const Request &r);
+        bool isIdle();
+        status_t waitForReadout();
+
+      private:
+        static const nsecs_t kWaitPerLoop  = 10000000L; // 10 ms
+        static const nsecs_t kMaxWaitLoops = 1000;
+        static const size_t  kMaxQueueSize = 2;
+
+        EmulatedFakeCamera3 *mParent;
+        Mutex mLock;
+
+        List<Request> mInFlightQueue;
+        Condition     mInFlightSignal;
+        bool          mThreadActive;
+
+        virtual bool threadLoop();
+
+        // Only accessed by threadLoop
+
+        Request mCurrentRequest;
+
+    };
+
+    sp<ReadoutThread> mReadoutThread;
+};
+
+} // namespace android
+
+#endif // HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H
diff --git a/camera/fake-pipeline2/Sensor.cpp b/camera/fake-pipeline2/Sensor.cpp
index 316fe02..0c12f6f 100644
--- a/camera/fake-pipeline2/Sensor.cpp
+++ b/camera/fake-pipeline2/Sensor.cpp
@@ -100,9 +100,8 @@
 
 
 
-Sensor::Sensor(EmulatedFakeCamera2 *parent):
+Sensor::Sensor():
         Thread(false),
-        mParent(parent),
         mGotVSync(false),
         mExposureTime(kFrameDurationRange[0]-kMinVerticalBlank),
         mFrameDuration(kFrameDurationRange[0]),
diff --git a/camera/fake-pipeline2/Sensor.h b/camera/fake-pipeline2/Sensor.h
index ce7b4ad..72128c5 100644
--- a/camera/fake-pipeline2/Sensor.h
+++ b/camera/fake-pipeline2/Sensor.h
@@ -87,7 +87,7 @@
 class Sensor: private Thread, public virtual RefBase {
   public:
 
-    Sensor(EmulatedFakeCamera2 *parent);
+    Sensor();
     ~Sensor();
 
     /*
@@ -172,8 +172,6 @@
     static const uint32_t kDefaultSensitivity;
 
   private:
-    EmulatedFakeCamera2 *mParent;
-
     Mutex mControlMutex; // Lock before accessing control parameters
     // Start of control parameters
     Condition mVSync;