Camera service: Initialization for camera2 clients and devices

- Refactor initialization code to hide device type from CameraService
- Add metadata queue class to Camera2Device
- Initialization of Camera2Device, Camera2Client
- Conversion from HAL2 device static metadata to camera API
  parameters.

Bug: 6243944
Change-Id: I524145b45438e906d8493dae202704ce8f090aeb
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index a2a7e57..9f713fa 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -21,7 +21,8 @@
     libmedia_native \
     libcamera_client \
     libgui \
-    libhardware
+    libhardware \
+    libcamera_metadata
 
 LOCAL_C_INCLUDES += \
     system/media/camera/include
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index f0725ed..e138cd1 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -16,11 +16,14 @@
 
 #define LOG_TAG "Camera2Client"
 //#define LOG_NDEBUG 0
+#include <utils/Log.h>
 
 #include <cutils/properties.h>
 #include <gui/SurfaceTextureClient.h>
 #include <gui/Surface.h>
 
+#include <math.h>
+
 #include "Camera2Client.h"
 
 namespace android {
@@ -28,11 +31,14 @@
 #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
 
-#define ALOG1_ENTRY {       \
+#define ALOG1_ENTRY        \
     int callingPid = getCallingPid(); \
     ALOG1("%s: E (pid %d, id %d) ", __FUNCTION__, \
-            callingPid, mCameraId);      \
-}
+            callingPid, mCameraId)
+
+#define ALOG1_EXIT        \
+    ALOG1("%s: X (pid %d, id %d) ", __FUNCTION__, \
+            callingPid, mCameraId)
 
 static int getCallingPid() {
     return IPCThreadState::self()->getCallingPid();
@@ -46,19 +52,54 @@
 
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
-        const sp<Camera2Device>& device,
         int cameraId,
         int cameraFacing,
         int clientPid):
         Client(cameraService, cameraClient,
-                cameraId, cameraFacing, clientPid) {
-    int callingPid = getCallingPid();
-    ALOG1("%s: E (pid %d, id %d)", __FUNCTION__, callingPid, cameraId);
+                cameraId, cameraFacing, clientPid),
+        mParams(NULL)
+{
     ALOG1_ENTRY;
 
+    mDevice = new Camera2Device(cameraId);
+
+    ALOG1_EXIT;
+}
+
+status_t Camera2Client::initialize(camera_module_t *module)
+{
+    ALOG1_ENTRY;
+    status_t res;
+
+    res = mDevice->initialize(module);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    res = buildDefaultParameters();
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+    if (gLogLevel >= 1) {
+        ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
+              mCameraId);
+        mParams->dump();
+    }
+
+    ALOG1_EXIT;
+    return OK;
 }
 
 Camera2Client::~Camera2Client() {
+    mDestructionStarted = true;
+
+    if (mParams) delete mParams;
+
+    disconnect();
 }
 
 status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
@@ -68,6 +109,11 @@
 // ICamera interface
 
 void Camera2Client::disconnect() {
+
+    if (mDevice == 0) return;
+
+    mDevice->setStreamingRequest(NULL);
+
     CameraService::Client::disconnect();
 }
 
@@ -141,13 +187,657 @@
 status_t Camera2Client::setParameters(const String8& params) {
     return BAD_VALUE;
 }
+
 String8 Camera2Client::getParameters() const {
-    return String8();
+    return mParams->flatten();
 }
 
 status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
     return BAD_VALUE;
 }
 
+// private methods
+
+status_t Camera2Client::buildDefaultParameters() {
+    status_t res;
+    if (mParams) {
+        delete mParams;
+    }
+    mParams = new CameraParameters;
+
+    camera_metadata_entry_t availableProcessedSizes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
+            &availableProcessedSizes);
+    if (res != OK) return res;
+    if (availableProcessedSizes.count < 2) {
+        ALOGE("%s: Camera %d: "
+                "Malformed %s entry",
+                __FUNCTION__, mCameraId,
+                get_camera_metadata_tag_name(
+                    ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES));
+        return NO_INIT;
+    }
+
+    // TODO: Pick more intelligently
+    int previewWidth = availableProcessedSizes.data.i32[0];
+    int previewHeight = availableProcessedSizes.data.i32[1];
+
+    mParams->setPreviewSize(previewWidth, previewHeight);
+    mParams->setVideoSize(previewWidth, previewHeight);
+    mParams->set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO,
+            String8::format("%dx%d",previewWidth,previewHeight));
+    {
+        String8 supportedPreviewSizes;
+        for (size_t i=0; i < availableProcessedSizes.count; i += 2) {
+            if (i != 0) supportedPreviewSizes += ",";
+            supportedPreviewSizes += String8::format("%dx%d",
+                    availableProcessedSizes.data.i32[i],
+                    availableProcessedSizes.data.i32[i+1]);
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
+                supportedPreviewSizes);
+        mParams->set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
+                supportedPreviewSizes);
+    }
+
+    camera_metadata_entry_t availableFpsRanges;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+            &availableFpsRanges);
+    if (res != OK) return res;
+    if (availableFpsRanges.count < 2) {
+        ALOGE("%s: Camera %d: "
+                "Malformed %s entry",
+                __FUNCTION__, mCameraId,
+                get_camera_metadata_tag_name(
+                    ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES));
+        return NO_INIT;
+    }
+
+    int previewFpsRangeMin = availableFpsRanges.data.i32[0];
+    int previewFpsRangeMax = availableFpsRanges.data.i32[1];
+
+    mParams->set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+            String8::format("%d,%d", previewFpsRangeMin, previewFpsRangeMax));
+
+    {
+        String8 supportedPreviewFpsRange;
+        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+            if (i != 0) supportedPreviewFpsRange += ",";
+            supportedPreviewFpsRange += String8::format("(%d,%d)",
+                    availableFpsRanges.data.i32[i],
+                    availableFpsRanges.data.i32[i+1]);
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+                supportedPreviewFpsRange);
+    }
+
+    mParams->set(CameraParameters::KEY_PREVIEW_FORMAT,
+            "yuv420sp"); // NV21
+
+    camera_metadata_entry_t availableFormats;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_SCALER_AVAILABLE_FORMATS,
+            &availableFormats);
+    {
+        String8 supportedPreviewFormats;
+        bool addComma = false;
+        for (size_t i=0; i < availableFormats.count; i++) {
+            if (addComma) supportedPreviewFormats += ",";
+            addComma = true;
+            switch (availableFormats.data.i32[i]) {
+            case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+                supportedPreviewFormats += "yuv422sp";
+                break;
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+                supportedPreviewFormats += "yuv420sp";
+                break;
+            case HAL_PIXEL_FORMAT_YCbCr_422_I:
+                supportedPreviewFormats += "yuv422i-yuyv";
+                break;
+            case HAL_PIXEL_FORMAT_YV12:
+                supportedPreviewFormats += "yuv420p";
+                break;
+            case HAL_PIXEL_FORMAT_RGB_565:
+                supportedPreviewFormats += "rgb565";
+                break;
+                // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+            case HAL_PIXEL_FORMAT_RAW_SENSOR:
+                addComma = false;
+                break;
+            default:
+                ALOGW("%s: Camera %d: Unknown preview format: %x",
+                        __FUNCTION__, mCameraId, availableFormats.data.i32[i]);
+                addComma = false;
+                break;
+            }
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
+                supportedPreviewFormats);
+    }
+
+    // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
+    // still have to do something sane for them
+
+    mParams->set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
+            previewFpsRangeMin);
+
+    {
+        String8 supportedPreviewFrameRates;
+        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+            if (i != 0) supportedPreviewFrameRates += ",";
+            supportedPreviewFrameRates += String8::format("%d",
+                    availableFpsRanges.data.i32[i]);
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
+                supportedPreviewFrameRates);
+    }
+
+    camera_metadata_entry_t availableJpegSizes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
+            &availableJpegSizes);
+    if (res != OK) return res;
+    if (availableJpegSizes.count < 2) {
+        ALOGE("%s: Camera %d: "
+                "Malformed %s entry",
+                __FUNCTION__, mCameraId,
+                get_camera_metadata_tag_name(
+                    ANDROID_SCALER_AVAILABLE_JPEG_SIZES));
+        return NO_INIT;
+    }
+
+    // TODO: Pick maximum
+    int32_t pictureWidth = availableJpegSizes.data.i32[0];
+    int32_t pictureHeight = availableJpegSizes.data.i32[1];
+
+    mParams->setPictureSize(pictureWidth, pictureHeight);
+
+    {
+        String8 supportedPictureSizes;
+        for (size_t i=0; i < availableJpegSizes.count; i += 2) {
+            if (i != 0) supportedPictureSizes += ",";
+            supportedPictureSizes += String8::format("%dx%d",
+                    availableJpegSizes.data.i32[i],
+                    availableJpegSizes.data.i32[i+1]);
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
+                supportedPictureSizes);
+    }
+
+    mParams->setPictureFormat("jpeg");
+
+    mParams->set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
+            "jpeg");
+
+    camera_metadata_entry_t availableJpegThumbnailSizes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+            &availableJpegThumbnailSizes);
+    if (res != OK) return res;
+    if (availableJpegThumbnailSizes.count < 2) {
+        ALOGE("%s: Camera %d: "
+                "Malformed %s entry",
+                __FUNCTION__, mCameraId,
+                get_camera_metadata_tag_name(
+                    ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES));
+        return NO_INIT;
+    }
+
+    // TODO: Pick default thumbnail size sensibly
+    int32_t jpegThumbWidth = availableJpegThumbnailSizes.data.i32[0];
+    int32_t jpegThumbHeight = availableJpegThumbnailSizes.data.i32[1];
+
+    mParams->set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+            jpegThumbWidth);
+    mParams->set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+            jpegThumbHeight);
+
+    {
+        String8 supportedJpegThumbSizes;
+        for (size_t i=0; i < availableJpegThumbnailSizes.count; i += 2) {
+            if (i != 0) supportedJpegThumbSizes += ",";
+            supportedJpegThumbSizes += String8::format("%dx%d",
+                    availableJpegThumbnailSizes.data.i32[i],
+                    availableJpegThumbnailSizes.data.i32[i+1]);
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES,
+                supportedJpegThumbSizes);
+    }
+
+    mParams->set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
+            "90");
+    mParams->set(CameraParameters::KEY_JPEG_QUALITY,
+            "90");
+    mParams->set(CameraParameters::KEY_ROTATION,
+            "0");
+    // Not settting GPS fields
+
+    mParams->set(CameraParameters::KEY_WHITE_BALANCE,
+            "auto");
+
+    camera_metadata_entry_t availableWhiteBalanceModes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+            &availableWhiteBalanceModes);
+    {
+        String8 supportedWhiteBalance;
+        bool addComma = false;
+        for (size_t i=0; i < availableWhiteBalanceModes.count; i++) {
+            if (addComma) supportedWhiteBalance += ",";
+            addComma = true;
+            switch (availableWhiteBalanceModes.data.u8[i]) {
+            case ANDROID_CONTROL_AWB_AUTO:
+                supportedWhiteBalance += "auto";
+                break;
+            case ANDROID_CONTROL_AWB_INCANDESCENT:
+                supportedWhiteBalance += "incandescent";
+                break;
+            case ANDROID_CONTROL_AWB_FLUORESCENT:
+                supportedWhiteBalance += "fluorescent";
+                break;
+            case ANDROID_CONTROL_AWB_WARM_FLUORESCENT:
+                supportedWhiteBalance += "warm-fluorescent";
+                break;
+            case ANDROID_CONTROL_AWB_DAYLIGHT:
+                supportedWhiteBalance += "daylight";
+                break;
+            case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT:
+                supportedWhiteBalance += "cloudy-daylight";
+                break;
+            case ANDROID_CONTROL_AWB_TWILIGHT:
+                supportedWhiteBalance += "twilight";
+                break;
+            case ANDROID_CONTROL_AWB_SHADE:
+                supportedWhiteBalance += "shade";
+                break;
+            // Skipping values not mappable to v1 API
+            case ANDROID_CONTROL_AWB_OFF:
+                addComma = false;
+                break;
+            default:
+                ALOGW("%s: Camera %d: Unknown white balance value: %d",
+                        __FUNCTION__, mCameraId,
+                        availableWhiteBalanceModes.data.u8[i]);
+                addComma = false;
+                break;
+            }
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+                supportedWhiteBalance);
+    }
+
+    mParams->set(CameraParameters::KEY_EFFECT, "none");
+    camera_metadata_entry_t availableEffects;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AVAILABLE_EFFECTS,
+            &availableEffects);
+    if (res != OK) return res;
+    {
+        String8 supportedEffects;
+        bool addComma = false;
+        for (size_t i=0; i < availableEffects.count; i++) {
+            if (addComma) supportedEffects += ",";
+            addComma = true;
+            switch (availableEffects.data.u8[i]) {
+                case ANDROID_CONTROL_EFFECT_OFF:
+                    supportedEffects += "none";
+                    break;
+                case ANDROID_CONTROL_EFFECT_MONO:
+                    supportedEffects += "mono";
+                case ANDROID_CONTROL_EFFECT_NEGATIVE:
+                    supportedEffects += "negative";
+                    break;
+                case ANDROID_CONTROL_EFFECT_SOLARIZE:
+                    supportedEffects += "solarize";
+                    break;
+                case ANDROID_CONTROL_EFFECT_SEPIA:
+                    supportedEffects += "sepia";
+                    break;
+                case ANDROID_CONTROL_EFFECT_POSTERIZE:
+                    supportedEffects += "posterize";
+                    break;
+                case ANDROID_CONTROL_EFFECT_WHITEBOARD:
+                    supportedEffects += "whiteboard";
+                    break;
+                case ANDROID_CONTROL_EFFECT_BLACKBOARD:
+                    supportedEffects += "blackboard";
+                    break;
+                case ANDROID_CONTROL_EFFECT_AQUA:
+                    supportedEffects += "aqua";
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown effect value: %d",
+                        __FUNCTION__, mCameraId, availableEffects.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_EFFECTS, supportedEffects);
+    }
+
+    mParams->set(CameraParameters::KEY_ANTIBANDING, "auto");
+    camera_metadata_entry_t availableAntibandingModes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+            &availableAntibandingModes);
+    if (res != OK) return res;
+    {
+        String8 supportedAntibanding;
+        bool addComma = false;
+        for (size_t i=0; i < availableAntibandingModes.count; i++) {
+            if (addComma) supportedAntibanding += ",";
+            addComma = true;
+            switch (availableAntibandingModes.data.u8[i]) {
+                case ANDROID_CONTROL_AE_ANTIBANDING_OFF:
+                    supportedAntibanding += "off";
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_50HZ:
+                    supportedAntibanding += "50hz";
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_60HZ:
+                    supportedAntibanding += "60hz";
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_AUTO:
+                    supportedAntibanding += "auto";
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown antibanding value: %d",
+                        __FUNCTION__, mCameraId,
+                            availableAntibandingModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+                supportedAntibanding);
+    }
+
+    mParams->set(CameraParameters::KEY_SCENE_MODE, "auto");
+    camera_metadata_entry_t availableSceneModes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+            &availableSceneModes);
+    if (res != OK) return res;
+    {
+        String8 supportedSceneModes("auto");
+        bool addComma = true;
+        bool noSceneModes = false;
+        for (size_t i=0; i < availableSceneModes.count; i++) {
+            if (addComma) supportedSceneModes += ",";
+            addComma = true;
+            switch (availableSceneModes.data.u8[i]) {
+                case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+                    noSceneModes = true;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
+                    // Not in old API
+                    addComma = false;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_ACTION:
+                    supportedSceneModes += "action";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_PORTRAIT:
+                    supportedSceneModes += "portrait";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_LANDSCAPE:
+                    supportedSceneModes += "landscape";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_NIGHT:
+                    supportedSceneModes += "night";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT:
+                    supportedSceneModes += "night-portrait";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_THEATRE:
+                    supportedSceneModes += "theatre";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_BEACH:
+                    supportedSceneModes += "beach";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SNOW:
+                    supportedSceneModes += "snow";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SUNSET:
+                    supportedSceneModes += "sunset";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO:
+                    supportedSceneModes += "steadyphoto";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_FIREWORKS:
+                    supportedSceneModes += "fireworks";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SPORTS:
+                    supportedSceneModes += "sports";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_PARTY:
+                    supportedSceneModes += "party";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT:
+                    supportedSceneModes += "candlelight";
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_BARCODE:
+                    supportedSceneModes += "barcode";
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown scene mode value: %d",
+                        __FUNCTION__, mCameraId, availableSceneModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        if (!noSceneModes) {
+            mParams->set(CameraParameters::KEY_SUPPORTED_SCENE_MODES,
+                    supportedSceneModes);
+        }
+    }
+
+    camera_metadata_entry_t flashAvailable;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_FLASH_AVAILABLE, &flashAvailable);
+    if (res != OK) return res;
+
+    camera_metadata_entry_t availableAeModes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AE_AVAILABLE_MODES,
+            &availableAeModes);
+    if (res != OK) return res;
+
+    if (flashAvailable.data.u8[0]) {
+        mParams->set(CameraParameters::KEY_FLASH_MODE, "auto");
+        String8 supportedFlashModes("off,auto,on,torch");
+        for (size_t i=0; i < availableAeModes.count; i++) {
+            if (availableAeModes.data.u8[i] ==
+                    ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE) {
+                supportedFlashModes += ",red-eye";
+                break;
+            }
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+                supportedFlashModes);
+    }
+
+    camera_metadata_entry_t minFocusDistance;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_LENS_MINIMUM_FOCUS_DISTANCE,
+            &minFocusDistance);
+    if (res != OK) return res;
+    camera_metadata_entry_t availableAfModes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AF_AVAILABLE_MODES,
+            &availableAfModes);
+    if (res != OK) return res;
+    if (minFocusDistance.data.f[0] == 0) {
+        // Fixed-focus lens
+        mParams->set(CameraParameters::KEY_FOCUS_MODE, "fixed");
+        mParams->set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, "fixed");
+    } else {
+        mParams->set(CameraParameters::KEY_FOCUS_MODE, "auto");
+        String8 supportedFocusModes("fixed,infinity");
+        bool addComma = true;
+        for (size_t i=0; i < availableAfModes.count; i++) {
+            if (addComma) supportedFocusModes += ",";
+            addComma = true;
+            switch (availableAfModes.data.u8[i]) {
+                case ANDROID_CONTROL_AF_AUTO:
+                    supportedFocusModes += "auto";
+                    break;
+                case ANDROID_CONTROL_AF_MACRO:
+                    supportedFocusModes += "macro";
+                    break;
+                case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
+                    supportedFocusModes += "continuous-video";
+                    break;
+                case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
+                    supportedFocusModes += "continuous-picture";
+                    break;
+                case ANDROID_CONTROL_AF_EDOF:
+                    supportedFocusModes += "edof";
+                    break;
+                // Not supported in v1 API
+                case ANDROID_CONTROL_AF_OFF:
+                    addComma = false;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown AF mode value: %d",
+                        __FUNCTION__, mCameraId, availableAfModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        mParams->set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+                supportedFocusModes);
+    }
+
+    camera_metadata_entry_t max3aRegions;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_MAX_REGIONS, &max3aRegions);
+    if (res != OK) return res;
+
+    mParams->set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS,
+            max3aRegions.data.i32[0]);
+    mParams->set(CameraParameters::KEY_FOCUS_AREAS,
+            "(0,0,0,0,0)");
+
+    camera_metadata_entry_t availableFocalLengths;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS,
+            &availableFocalLengths);
+    if (res != OK) return res;
+    float minFocalLength = availableFocalLengths.data.f[0];
+    mParams->setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+
+    camera_metadata_entry_t sensorSize;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_SENSOR_PHYSICAL_SIZE,
+            &sensorSize);
+    if (res != OK) return res;
+
+    // The fields of view here assume infinity focus, maximum wide angle
+    float horizFov = 180 / M_PI *
+            2 * atanf(sensorSize.data.f[0] / (2 * minFocalLength));
+    float vertFov  = 180 / M_PI *
+            2 * atanf(sensorSize.data.f[1] / (2 * minFocalLength));
+    mParams->setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, horizFov);
+    mParams->setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, vertFov);
+
+    mParams->set(CameraParameters::KEY_EXPOSURE_COMPENSATION, 0);
+
+    camera_metadata_entry_t exposureCompensationRange;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE,
+            &exposureCompensationRange);
+    if (res != OK) return res;
+    mParams->set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION,
+            exposureCompensationRange.data.i32[1]);
+    mParams->set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION,
+            exposureCompensationRange.data.i32[0]);
+
+    camera_metadata_entry_t exposureCompensationStep;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AE_EXP_COMPENSATION_STEP,
+            &exposureCompensationStep);
+    if (res != OK) return res;
+    mParams->setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP,
+            exposureCompensationStep.data.r[0].numerator /
+            exposureCompensationStep.data.r[0].denominator);
+
+    mParams->set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, "false");
+    mParams->set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, "true");
+
+    mParams->set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, "false");
+    mParams->set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, "true");
+
+    mParams->set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
+            max3aRegions.data.i32[0]);
+    mParams->set(CameraParameters::KEY_METERING_AREAS,
+            "(0,0,0,0,0)");
+
+    mParams->set(CameraParameters::KEY_ZOOM, 0);
+    mParams->set(CameraParameters::KEY_MAX_ZOOM, kNumZoomSteps - 1);
+
+    camera_metadata_entry_t maxDigitalZoom;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_SCALER_AVAILABLE_MAX_ZOOM, &maxDigitalZoom);
+    if (res != OK) return res;
+
+    {
+        String8 zoomRatios;
+        float zoom = 1.f;
+        float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
+                (kNumZoomSteps-1);
+        bool addComma = false;
+        for (size_t i=0; i < kNumZoomSteps; i++) {
+            if (addComma) zoomRatios += ",";
+            addComma = true;
+            zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
+            zoom += zoomIncrement;
+        }
+        mParams->set(CameraParameters::KEY_ZOOM_RATIOS, zoomRatios);
+    }
+
+    mParams->set(CameraParameters::KEY_ZOOM_SUPPORTED, "true");
+    mParams->set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "true");
+
+    mParams->set(CameraParameters::KEY_FOCUS_DISTANCES,
+            "Infinity,Infinity,Infinity");
+
+    camera_metadata_entry_t maxFacesDetected;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_STATS_MAX_FACE_COUNT,
+            &maxFacesDetected);
+    mParams->set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
+            maxFacesDetected.data.i32[0]);
+    mParams->set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
+            0);
+
+    mParams->set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
+            "yuv420sp");
+
+    mParams->set(CameraParameters::KEY_RECORDING_HINT,
+            "false");
+
+    mParams->set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED,
+            "true");
+
+    mParams->set(CameraParameters::KEY_VIDEO_STABILIZATION,
+            "false");
+
+    camera_metadata_entry_t availableVideoStabilizationModes;
+    res = find_camera_metadata_entry(mDevice->info(),
+            ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+            &availableVideoStabilizationModes);
+    if (res != OK) return res;
+    if (availableVideoStabilizationModes.count > 1) {
+        mParams->set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+                "true");
+    } else {
+        mParams->set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+                "false");
+    }
+
+    return OK;
+}
 
 } // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 709de0b..4f0fcf0 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -19,6 +19,7 @@
 
 #include "Camera2Device.h"
 #include "CameraService.h"
+#include "camera/CameraParameters.h"
 
 namespace android {
 
@@ -55,17 +56,25 @@
     // Interface used by CameraService
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<ICameraClient>& cameraClient,
-            const sp<Camera2Device>& device,
             int cameraId,
             int cameraFacing,
             int clientPid);
     ~Camera2Client();
 
+    status_t initialize(camera_module_t *module);
+
     virtual status_t dump(int fd, const Vector<String16>& args);
 
 private:
+    CameraParameters *mParams;
+    sp<Camera2Device> mDevice;
 
+    // Convert static camera info from a camera2 device to the
+    // old API parameter map.
+    status_t buildDefaultParameters();
 
+    // Free parameters for mapping from new to old HAL
+    static const unsigned int kNumZoomSteps = 10;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index ff5b057..4b0cfc4 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -22,8 +22,8 @@
 
 namespace android {
 
-Camera2Device::Camera2Device(const char *name):
-        mName(name),
+Camera2Device::Camera2Device(int id):
+        mId(id),
         mDevice(NULL)
 {
 
@@ -35,32 +35,307 @@
         status_t res;
         res = mDevice->common.close(&mDevice->common);
         if (res != OK) {
-            ALOGE("Could not close camera2 %s: %s (%d)",
-                    mName, strerror(-res), res);
+            ALOGE("%s: Could not close camera %d: %s (%d)",
+                    __FUNCTION__,
+                    mId, strerror(-res), res);
         }
+        mDevice = NULL;
     }
 }
 
-status_t Camera2Device::initialize(hw_module_t *module)
+status_t Camera2Device::initialize(camera_module_t *module)
 {
     status_t res;
-    res = module->methods->open(module, mName,
+    char name[10];
+    snprintf(name, sizeof(name), "%d", mId);
+
+    res = module->common.methods->open(&module->common, name,
             reinterpret_cast<hw_device_t**>(&mDevice));
 
     if (res != OK) {
-        ALOGE("Could not open camera %s: %s (%d)", mName, strerror(-res), res);
+        ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
+                mId, strerror(-res), res);
         return res;
     }
 
     if (mDevice->common.version != CAMERA_DEVICE_API_VERSION_2_0) {
-        ALOGE("Could not open camera %s: "
-                "Camera device is not version 2.0, reports %x instead",
-                mName, mDevice->common.version);
+        ALOGE("%s: Could not open camera %d: "
+                "Camera device is not version %x, reports %x instead",
+                __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0,
+                mDevice->common.version);
         return BAD_VALUE;
     }
 
+    camera_info info;
+    res = module->get_camera_info(mId, &info);
+    if (res != OK ) return res;
+
+    if (info.device_version != mDevice->common.version) {
+        ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
+                " and device version (%x).", __FUNCTION__,
+                mDevice->common.version, info.device_version);
+        return BAD_VALUE;
+    }
+
+    mDeviceInfo = info.static_camera_characteristics;
+
+    res = mDevice->ops->set_request_queue_src_ops(mDevice,
+            mRequestQueue.getToConsumerInterface());
+    if (res != OK) return res;
+
+    res = mDevice->ops->set_frame_queue_dst_ops(mDevice,
+            mFrameQueue.getToProducerInterface());
+    if (res != OK) return res;
+
+    res = mDevice->ops->get_metadata_vendor_tag_ops(mDevice, &mVendorTagOps);
+    if (res != OK ) return res;
+
     return OK;
 }
 
+status_t Camera2Device::setStreamingRequest(camera_metadata_t* request)
+{
+    mRequestQueue.setStreamSlot(request);
+    return OK;
+}
+
+/**
+ * Camera2Device::MetadataQueue
+ */
+
+Camera2Device::MetadataQueue::MetadataQueue():
+            mDevice(NULL),
+            mFrameCount(0),
+            mCount(0),
+            mStreamSlotCount(0),
+            mSignalConsumer(true)
+{
+    camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
+    camera2_request_queue_src_ops::request_count = consumer_buffer_count;
+    camera2_request_queue_src_ops::free_request = consumer_free;
+
+    camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue;
+    camera2_frame_queue_dst_ops::cancel_frame = producer_cancel;
+    camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue;
+}
+
+Camera2Device::MetadataQueue::~MetadataQueue() {
+    Mutex::Autolock l(mMutex);
+    freeBuffers(mEntries.begin(), mEntries.end());
+    freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+}
+
+// Interface to camera2 HAL as consumer (input requests/reprocessing)
+const camera2_request_queue_src_ops_t*
+Camera2Device::MetadataQueue::getToConsumerInterface() {
+    return static_cast<camera2_request_queue_src_ops_t*>(this);
+}
+
+void Camera2Device::MetadataQueue::setFromConsumerInterface(camera2_device_t *d) {
+    Mutex::Autolock l(mMutex);
+    mDevice = d;
+}
+
+const camera2_frame_queue_dst_ops_t*
+Camera2Device::MetadataQueue::getToProducerInterface() {
+    return static_cast<camera2_frame_queue_dst_ops_t*>(this);
+}
+
+// Real interfaces
+status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
+    Mutex::Autolock l(mMutex);
+
+    mCount++;
+    mEntries.push_back(buf);
+    notEmpty.signal();
+
+    if (mSignalConsumer && mDevice != NULL) {
+        mSignalConsumer = false;
+
+        mMutex.unlock();
+        ALOGV("%s: Signaling consumer", __FUNCTION__);
+        mDevice->ops->notify_request_queue_not_empty(mDevice);
+        mMutex.lock();
+    }
+    return OK;
+}
+
+int Camera2Device::MetadataQueue::getBufferCount() {
+    Mutex::Autolock l(mMutex);
+    if (mStreamSlotCount > 0) {
+        return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS;
+    }
+    return mCount;
+}
+
+status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
+        bool incrementCount)
+{
+    Mutex::Autolock l(mMutex);
+
+    if (mCount == 0) {
+        if (mStreamSlotCount == 0) {
+            ALOGV("%s: Empty", __FUNCTION__);
+            *buf = NULL;
+            mSignalConsumer = true;
+            return OK;
+        }
+        ALOGV("%s: Streaming %d frames to queue", __FUNCTION__,
+              mStreamSlotCount);
+
+        for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin();
+                slotEntry != mStreamSlot.end();
+                slotEntry++ ) {
+            size_t entries = get_camera_metadata_entry_count(*slotEntry);
+            size_t dataBytes = get_camera_metadata_data_count(*slotEntry);
+
+            camera_metadata_t *copy =
+                    allocate_camera_metadata(entries, dataBytes);
+            append_camera_metadata(copy, *slotEntry);
+            mEntries.push_back(copy);
+        }
+        mCount = mStreamSlotCount;
+    }
+    ALOGV("MetadataQueue: deque (%d buffers)", mCount);
+    camera_metadata_t *b = *(mEntries.begin());
+    mEntries.erase(mEntries.begin());
+
+    if (incrementCount) {
+        add_camera_metadata_entry(b,
+                ANDROID_REQUEST_FRAME_COUNT,
+                (void**)&mFrameCount, 1);
+        mFrameCount++;
+    }
+
+    *buf = b;
+    mCount--;
+
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
+{
+    Mutex::Autolock l(mMutex);
+    status_t res;
+    while (mCount == 0) {
+        res = notEmpty.waitRelative(mMutex,timeout);
+        if (res != OK) return res;
+    }
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
+{
+    Mutex::Autolock l(mMutex);
+    if (buf == NULL) {
+        freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+        mStreamSlotCount = 0;
+        return OK;
+    }
+    if (mStreamSlotCount > 1) {
+        List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
+        freeBuffers(++mStreamSlot.begin(), mStreamSlot.end());
+        mStreamSlotCount = 1;
+    }
+    if (mStreamSlotCount == 1) {
+        free_camera_metadata( *(mStreamSlot.begin()) );
+        *(mStreamSlot.begin()) = buf;
+    } else {
+        mStreamSlot.push_front(buf);
+        mStreamSlotCount = 1;
+    }
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::setStreamSlot(
+        const List<camera_metadata_t*> &bufs)
+{
+    Mutex::Autolock l(mMutex);
+    if (mStreamSlotCount > 0) {
+        freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+    }
+    mStreamSlot = bufs;
+    mStreamSlotCount = mStreamSlot.size();
+
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::freeBuffers(
+        List<camera_metadata_t*>::iterator start,
+        List<camera_metadata_t*>::iterator end)
+{
+    while (start != end) {
+        free_camera_metadata(*start);
+        start = mStreamSlot.erase(start);
+    }
+    return OK;
+}
+
+Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
+        const camera2_request_queue_src_ops_t *q)
+{
+    const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
+    return const_cast<MetadataQueue*>(cmq);
+}
+
+Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
+        const camera2_frame_queue_dst_ops_t *q)
+{
+    const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
+    return const_cast<MetadataQueue*>(cmq);
+}
+
+int Camera2Device::MetadataQueue::consumer_buffer_count(
+        const camera2_request_queue_src_ops_t *q)
+{
+    MetadataQueue *queue = getInstance(q);
+    return queue->getBufferCount();
+}
+
+int Camera2Device::MetadataQueue::consumer_dequeue(
+        const camera2_request_queue_src_ops_t *q,
+        camera_metadata_t **buffer)
+{
+    MetadataQueue *queue = getInstance(q);
+    return queue->dequeue(buffer, true);
+}
+
+int Camera2Device::MetadataQueue::consumer_free(
+        const camera2_request_queue_src_ops_t *q,
+        camera_metadata_t *old_buffer)
+{
+    MetadataQueue *queue = getInstance(q);
+    free_camera_metadata(old_buffer);
+    return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_dequeue(
+        const camera2_frame_queue_dst_ops_t *q,
+        size_t entries, size_t bytes,
+        camera_metadata_t **buffer)
+{
+    camera_metadata_t *new_buffer =
+            allocate_camera_metadata(entries, bytes);
+    if (new_buffer == NULL) return NO_MEMORY;
+    *buffer = new_buffer;
+        return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_cancel(
+        const camera2_frame_queue_dst_ops_t *q,
+        camera_metadata_t *old_buffer)
+{
+    free_camera_metadata(old_buffer);
+    return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_enqueue(
+        const camera2_frame_queue_dst_ops_t *q,
+        camera_metadata_t *filled_buffer)
+{
+    MetadataQueue *queue = getInstance(q);
+    return queue->enqueue(filled_buffer);
+}
+
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 0ce5421..07c5ff7 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -18,6 +18,9 @@
 #define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
 
 #include <utils/RefBase.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
 #include <utils/Errors.h>
 #include "hardware/camera2.h"
 
@@ -25,17 +28,104 @@
 
 class Camera2Device : public virtual RefBase {
   public:
-    Camera2Device(const char *name);
+    Camera2Device(int id);
 
     ~Camera2Device();
 
-    status_t initialize(hw_module_t *module);
+    status_t initialize(camera_module_t *module);
+
+    status_t setStreamingRequest(camera_metadata_t* request);
+
+    camera_metadata_t* info() {
+        return mDeviceInfo;
+    }
+
   private:
 
-    const char *mName;
+    const int mId;
     camera2_device_t *mDevice;
 
-};
+    camera_metadata_t *mDeviceInfo;
+    vendor_tag_query_ops_t *mVendorTagOps;
+
+    /**
+     * Queue class for both sending requests to a camera2 device, and for
+     * receiving frames from a camera2 device.
+     */
+    class MetadataQueue: public camera2_request_queue_src_ops_t,
+                         public camera2_frame_queue_dst_ops_t {
+      public:
+        MetadataQueue();
+        ~MetadataQueue();
+
+        // Interface to camera2 HAL device, either for requests (device is
+        // consumer) or for frames (device is producer)
+        const camera2_request_queue_src_ops_t*   getToConsumerInterface();
+        void setFromConsumerInterface(camera2_device_t *d);
+
+        const camera2_frame_queue_dst_ops_t* getToProducerInterface();
+
+        // Real interfaces. On enqueue, queue takes ownership of buffer pointer
+        // On dequeue, user takes ownership of buffer pointer.
+        status_t enqueue(camera_metadata_t *buf);
+        status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
+        int      getBufferCount();
+        status_t waitForBuffer(nsecs_t timeout);
+
+        // Set repeating buffer(s); if the queue is empty on a dequeue call, the
+        // queue copies the contents of the stream slot into the queue, and then
+        // dequeues the first new entry.
+        status_t setStreamSlot(camera_metadata_t *buf);
+        status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
+
+      private:
+        status_t freeBuffers(List<camera_metadata_t*>::iterator start,
+                List<camera_metadata_t*>::iterator end);
+
+        camera2_device_t *mDevice;
+
+        Mutex mMutex;
+        Condition notEmpty;
+
+        int mFrameCount;
+
+        int mCount;
+        List<camera_metadata_t*> mEntries;
+        int mStreamSlotCount;
+        List<camera_metadata_t*> mStreamSlot;
+
+        bool mSignalConsumer;
+
+        static MetadataQueue* getInstance(
+            const camera2_frame_queue_dst_ops_t *q);
+        static MetadataQueue* getInstance(
+            const camera2_request_queue_src_ops_t *q);
+
+        static int consumer_buffer_count(
+            const camera2_request_queue_src_ops_t *q);
+
+        static int consumer_dequeue(const camera2_request_queue_src_ops_t *q,
+            camera_metadata_t **buffer);
+
+        static int consumer_free(const camera2_request_queue_src_ops_t *q,
+                camera_metadata_t *old_buffer);
+
+        static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q,
+                size_t entries, size_t bytes,
+                camera_metadata_t **buffer);
+
+        static int producer_cancel(const camera2_frame_queue_dst_ops_t *q,
+            camera_metadata_t *old_buffer);
+
+        static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q,
+                camera_metadata_t *filled_buffer);
+
+    }; // class MetadataQueue
+
+    MetadataQueue mRequestQueue;
+    MetadataQueue mFrameQueue;
+
+}; // class Camera2Device
 
 }; // namespace android
 
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
index ce9ee1e..80ccb43 100644
--- a/services/camera/libcameraservice/CameraClient.cpp
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -40,7 +40,6 @@
 
 CameraClient::CameraClient(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
-        const sp<CameraHardwareInterface>& hardware,
         int cameraId, int cameraFacing, int clientPid):
         Client(cameraService, cameraClient,
                 cameraId, cameraFacing, clientPid)
@@ -48,19 +47,11 @@
     int callingPid = getCallingPid();
     LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId);
 
-    mHardware = hardware;
+    mHardware = NULL;
     mMsgEnabled = 0;
     mSurface = 0;
     mPreviewWindow = 0;
     mDestructionStarted = false;
-    mHardware->setCallbacks(notifyCallback,
-                            dataCallback,
-                            dataCallbackTimestamp,
-                            (void *)cameraId);
-
-    // Enable zoom, error, focus, and metadata messages by default
-    enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
-                  CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
 
     // Callback is disabled by default
     mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
@@ -69,6 +60,36 @@
     LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
 }
 
+status_t CameraClient::initialize(camera_module_t *module) {
+    int callingPid = getCallingPid();
+    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
+
+    char camera_device_name[10];
+    status_t res;
+    snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
+
+    mHardware = new CameraHardwareInterface(camera_device_name);
+    res = mHardware->initialize(&module->common);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    mHardware->setCallbacks(notifyCallback,
+            dataCallback,
+            dataCallbackTimestamp,
+            (void *)mCameraId);
+
+    // Enable zoom, error, focus, and metadata messages by default
+    enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
+                  CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
+
+    LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
+    return OK;
+}
+
+
 // tear down the client
 CameraClient::~CameraClient() {
     // this lock should never be NULL
@@ -83,7 +104,6 @@
     // set mClientPid to let disconnet() tear down the hardware
     mClientPid = callingPid;
     disconnect();
-    mCameraService->releaseSound();
     LOG1("CameraClient::~CameraClient X (pid %d, this %p)", callingPid, this);
 }
 
diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h
index d3ff9cf..256298d 100644
--- a/services/camera/libcameraservice/CameraClient.h
+++ b/services/camera/libcameraservice/CameraClient.h
@@ -53,13 +53,14 @@
     // Interface used by CameraService
     CameraClient(const sp<CameraService>& cameraService,
             const sp<ICameraClient>& cameraClient,
-            const sp<CameraHardwareInterface>& hardware,
             int cameraId,
             int cameraFacing,
             int clientPid);
     ~CameraClient();
 
-    virtual status_t dump(int fd, const Vector<String16>& args);
+    status_t initialize(camera_module_t *module);
+
+    status_t dump(int fd, const Vector<String16>& args);
 
 private:
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b273f6f..d01fcf9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -39,9 +39,7 @@
 
 #include "CameraService.h"
 #include "CameraClient.h"
-#include "CameraHardwareInterface.h"
 #include "Camera2Client.h"
-#include "Camera2Device.h"
 
 namespace android {
 
@@ -188,9 +186,6 @@
         return NULL;
     }
 
-    char camera_device_name[10];
-    snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
-
     int deviceVersion;
     if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) {
         deviceVersion = info.device_version;
@@ -199,33 +194,23 @@
     }
 
     switch(deviceVersion) {
-    case CAMERA_DEVICE_API_VERSION_1_0: {
-        sp<CameraHardwareInterface> hardware =
-            new CameraHardwareInterface(camera_device_name);
-        if (hardware->initialize(&mModule->common) != OK) {
-            return NULL;
-        }
-
-        client = new CameraClient(this, cameraClient, hardware, cameraId,
+      case CAMERA_DEVICE_API_VERSION_1_0:
+        client = new CameraClient(this, cameraClient, cameraId,
                 info.facing, callingPid);
         break;
-    }
-    case CAMERA_DEVICE_API_VERSION_2_0: {
-        sp<Camera2Device> hardware =
-            new Camera2Device(camera_device_name);
-        if (hardware->initialize(&mModule->common) != OK) {
-            return NULL;
-        }
-
-        client = new Camera2Client(this, cameraClient, hardware, cameraId,
+      case CAMERA_DEVICE_API_VERSION_2_0:
+        client = new Camera2Client(this, cameraClient, cameraId,
                 info.facing, callingPid);
         break;
-    }
-    default:
+      default:
         ALOGE("Unknown camera device HAL version: %d", deviceVersion);
         return NULL;
     }
 
+    if (client->initialize(mModule) != OK) {
+        return NULL;
+    }
+
     mClient[cameraId] = client;
     LOG1("CameraService::connect X (id %d)", cameraId);
     return client;
@@ -383,6 +368,7 @@
 
 // tear down the client
 CameraService::Client::~Client() {
+    mCameraService->releaseSound();
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 7f8ef6c..630fca7 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -108,6 +108,8 @@
             return mCameraClient;
         }
 
+        virtual status_t initialize(camera_module_t *module) = 0;
+
         virtual status_t dump(int fd, const Vector<String16>& args) = 0;
 
     protected: