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/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