Camera2: Factor out Camera2Client::Parameters

Move the parameter structure and the various utility methods using it
to its own class. Rename LockedParameters to SharedParameters to match
the Mutex naming convention.

Also move CameraMetadata to camera2 directory for organization.

No functional changes.

Bug: 6243944
Change-Id: Ie60b535936ecfda9bf23361d52604abf515c83d0
diff --git a/services/camera/libcameraservice/camera2/CameraMetadata.cpp b/services/camera/libcameraservice/camera2/CameraMetadata.cpp
new file mode 100644
index 0000000..95377b2
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/CameraMetadata.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "CameraMetadata"
+#include <utils/Log.h>
+#include <utils/Errors.h>
+
+#include "CameraMetadata.h"
+
+namespace android {
+
+namespace camera2 {
+CameraMetadata::CameraMetadata() :
+        mBuffer(NULL) {
+}
+
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity)
+{
+    mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
+}
+
+CameraMetadata::CameraMetadata(const CameraMetadata &other) {
+    mBuffer = clone_camera_metadata(other.mBuffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
+    return operator=(other.mBuffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
+    if (CC_LIKELY(buffer != mBuffer)) {
+        camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
+        clear();
+        mBuffer = newBuffer;
+    }
+    return *this;
+}
+
+CameraMetadata::~CameraMetadata() {
+    clear();
+}
+
+camera_metadata_t* CameraMetadata::release() {
+    camera_metadata_t *released = mBuffer;
+    mBuffer = NULL;
+    return released;
+}
+
+void CameraMetadata::clear() {
+    if (mBuffer) {
+        free_camera_metadata(mBuffer);
+        mBuffer = NULL;
+    }
+}
+
+void CameraMetadata::acquire(camera_metadata_t *buffer) {
+    clear();
+    mBuffer = buffer;
+}
+
+void CameraMetadata::acquire(CameraMetadata &other) {
+    acquire(other.release());
+}
+
+status_t CameraMetadata::append(const CameraMetadata &other) {
+    return append_camera_metadata(mBuffer, other.mBuffer);
+}
+
+size_t CameraMetadata::entryCount() const {
+    return (mBuffer == NULL) ? 0 :
+            get_camera_metadata_entry_count(mBuffer);
+}
+
+status_t CameraMetadata::sort() {
+    return sort_camera_metadata(mBuffer);
+}
+
+status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
+    int tagType = get_camera_metadata_tag_type(tag);
+    if ( CC_UNLIKELY(tagType == -1)) {
+        ALOGE("Update metadata entry: Unknown tag %d", tag);
+        return INVALID_OPERATION;
+    }
+    if ( CC_UNLIKELY(tagType != expectedType) ) {
+        ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
+                "got type %s data instead ",
+                get_camera_metadata_tag_name(tag), tag,
+                camera_metadata_type_names[tagType],
+                camera_metadata_type_names[expectedType]);
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const int32_t *data, size_t data_count) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_INT32)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const uint8_t *data, size_t data_count) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const float *data, size_t data_count) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const int64_t *data, size_t data_count) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_INT64)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const double *data, size_t data_count) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const camera_metadata_rational_t *data, size_t data_count) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const String8 &string) {
+    status_t res;
+    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+        return res;
+    }
+    return update(tag, (const void*)string.string(), string.size());
+}
+
+status_t CameraMetadata::update(uint32_t tag, const void *data,
+        size_t data_count) {
+    status_t res;
+    int type = get_camera_metadata_tag_type(tag);
+    if (type == -1) {
+        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
+        return BAD_VALUE;
+    }
+    size_t data_size = calculate_camera_metadata_entry_data_size(type,
+            data_count);
+
+    res = resizeIfNeeded(1, data_size);
+
+    if (res == OK) {
+        camera_metadata_entry_t entry;
+        res = find_camera_metadata_entry(mBuffer, tag, &entry);
+        if (res == NAME_NOT_FOUND) {
+            res = add_camera_metadata_entry(mBuffer,
+                    tag, data, data_count);
+        } else if (res == OK) {
+            res = update_camera_metadata_entry(mBuffer,
+                    entry.index, data, data_count, NULL);
+        }
+    }
+
+    if (res != OK) {
+        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
+                __FUNCTION__, get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+    }
+    return res;
+}
+
+camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
+    status_t res;
+    camera_metadata_entry entry;
+    res = find_camera_metadata_entry(mBuffer, tag, &entry);
+    if (CC_UNLIKELY( res != OK )) {
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+    return entry;
+}
+
+camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
+    status_t res;
+    camera_metadata_ro_entry entry;
+    res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
+    if (CC_UNLIKELY( res != OK )) {
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+    return entry;
+}
+
+status_t CameraMetadata::erase(uint32_t tag) {
+    camera_metadata_entry_t entry;
+    status_t res;
+    res = find_camera_metadata_entry(mBuffer, tag, &entry);
+    if (res == NAME_NOT_FOUND) {
+        return OK;
+    } else if (res != OK) {
+        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
+                __FUNCTION__,
+                get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+        return res;
+    }
+    res = delete_camera_metadata_entry(mBuffer, entry.index);
+    if (res != OK) {
+        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
+                __FUNCTION__,
+                get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+    }
+    return res;
+}
+
+void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
+    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
+}
+
+status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
+    if (mBuffer == NULL) {
+        mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
+        if (mBuffer == NULL) {
+            ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+            return NO_MEMORY;
+        }
+    } else {
+        size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
+        size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
+        size_t newEntryCount = currentEntryCount +
+                extraEntries;
+        newEntryCount = (newEntryCount > currentEntryCap) ?
+                newEntryCount * 2 : currentEntryCap;
+
+        size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
+        size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
+        size_t newDataCount = currentDataCount +
+                extraData;
+        newDataCount = (newDataCount > currentDataCap) ?
+                newDataCount * 2 : currentDataCap;
+
+        if (newEntryCount > currentEntryCap ||
+                newDataCount > currentDataCap) {
+            camera_metadata_t *oldBuffer = mBuffer;
+            mBuffer = allocate_camera_metadata(newEntryCount,
+                    newDataCount);
+            if (mBuffer == NULL) {
+                ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+                return NO_MEMORY;
+            }
+            append_camera_metadata(mBuffer, oldBuffer);
+            free_camera_metadata(oldBuffer);
+        }
+    }
+    return OK;
+}
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/CameraMetadata.h b/services/camera/libcameraservice/camera2/CameraMetadata.h
new file mode 100644
index 0000000..340414e
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/CameraMetadata.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_SERVERS_CAMERA_CAMERA2METADATA_CPP
+#define ANDROID_SERVERS_CAMERA_CAMERA2METADATA_CPP
+
+#include "system/camera_metadata.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace camera2 {
+
+/**
+ * A convenience wrapper around the C-based camera_metadata_t library.
+ */
+class CameraMetadata {
+  public:
+    /** Creates an empty object; best used when expecting to acquire contents
+     * from elsewhere */
+    CameraMetadata();
+    /** Creates an object with space for entryCapacity entries, with
+     * dataCapacity extra storage */
+    CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
+
+    ~CameraMetadata();
+
+    /** Takes ownership of passed-in buffer */
+    CameraMetadata(camera_metadata_t *buffer);
+    /** Clones the metadata */
+    CameraMetadata(const CameraMetadata &other);
+
+    /**
+     * Assignment clones metadata buffer.
+     */
+    CameraMetadata &operator=(const CameraMetadata &other);
+    CameraMetadata &operator=(const camera_metadata_t *buffer);
+
+    /**
+     * Release a raw metadata buffer to the caller. After this call,
+     * CameraMetadata no longer references the buffer, and the caller takes
+     * responsibility for freeing the raw metadata buffer (using
+     * free_camera_metadata()), or for handing it to another CameraMetadata
+     * instance.
+     */
+    camera_metadata_t* release();
+
+    /**
+     * Clear the metadata buffer and free all storage used by it
+     */
+    void clear();
+
+    /**
+     * Acquire a raw metadata buffer from the caller. After this call,
+     * the caller no longer owns the raw buffer, and must not free or manipulate it.
+     * If CameraMetadata already contains metadata, it is freed.
+     */
+    void acquire(camera_metadata_t* buffer);
+
+    /**
+     * Acquires raw buffer from other CameraMetadata object. After the call, the argument
+     * object no longer has any metadata.
+     */
+    void acquire(CameraMetadata &other);
+
+    /**
+     * Append metadata from another CameraMetadata object.
+     */
+    status_t append(const CameraMetadata &other);
+
+    /**
+     * Number of metadata entries.
+     */
+    size_t entryCount() const;
+
+    /**
+     * Sort metadata buffer for faster find
+     */
+    status_t sort();
+
+    /**
+     * Update metadata entry. Will create entry if it doesn't exist already, and
+     * will reallocate the buffer if insufficient space exists. Overloaded for
+     * the various types of valid data.
+     */
+    status_t update(uint32_t tag,
+            const uint8_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const int32_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const float *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const int64_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const double *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const camera_metadata_rational_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const String8 &string);
+
+    template<typename T>
+    status_t update(uint32_t tag, Vector<T> data) {
+        return update(tag, data.array(), data.size());
+    }
+
+    /**
+     * Get metadata entry by tag id
+     */
+    camera_metadata_entry find(uint32_t tag);
+
+    /**
+     * Get metadata entry by tag id, with no editing
+     */
+    camera_metadata_ro_entry find(uint32_t tag) const;
+
+    /**
+     * Delete metadata entry by tag
+     */
+    status_t erase(uint32_t tag);
+
+    /**
+     * Dump contents into FD for debugging. The verbosity levels are
+     * 0: Tag entry information only, no data values
+     * 1: Level 0 plus at most 16 data values per entry
+     * 2: All information
+     *
+     * The indentation parameter sets the number of spaces to add to the start
+     * each line of output.
+     */
+    void dump(int fd, int verbosity = 1, int indentation = 0) const;
+
+  private:
+    camera_metadata_t *mBuffer;
+
+    /**
+     * Check if tag has a given type
+     */
+    status_t checkType(uint32_t tag, uint8_t expectedType);
+
+    /**
+     * Base update entry method
+     */
+    status_t update(uint32_t tag, const void *data, size_t data_count);
+
+    /**
+     * Resize metadata buffer if needed by reallocating it and copying it over.
+     */
+    status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
+
+};
+
+}; // namespace camera2
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp
new file mode 100644
index 0000000..91c5141
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/Parameters.cpp
@@ -0,0 +1,1627 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "Camera2::Parameters"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "Parameters.h"
+#include "system/camera.h"
+#include "camera/CameraParameters.h"
+
+namespace android {
+namespace camera2 {
+
+Parameters::Parameters(int cameraId,
+        int cameraFacing) :
+        cameraId(cameraId),
+        cameraFacing(cameraFacing),
+        info(NULL) {
+}
+
+Parameters::~Parameters() {
+}
+
+status_t Parameters::initialize(const CameraMetadata *info) {
+    status_t res;
+
+    if (info->entryCount() == 0) {
+        ALOGE("%s: No static information provided!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    Parameters::info = info;
+
+    res = buildFastInfo();
+    if (res != OK) return res;
+
+    CameraParameters params;
+
+    camera_metadata_ro_entry_t availableProcessedSizes =
+        staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, 2);
+    if (!availableProcessedSizes.count) return NO_INIT;
+
+    // TODO: Pick more intelligently
+    previewWidth = availableProcessedSizes.data.i32[0];
+    previewHeight = availableProcessedSizes.data.i32[1];
+    videoWidth = previewWidth;
+    videoHeight = previewHeight;
+
+    params.setPreviewSize(previewWidth, previewHeight);
+    params.setVideoSize(videoWidth, videoHeight);
+    params.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]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
+                supportedPreviewSizes);
+        params.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
+                supportedPreviewSizes);
+    }
+
+    camera_metadata_ro_entry_t availableFpsRanges =
+        staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+    if (!availableFpsRanges.count) return NO_INIT;
+
+    previewFpsRange[0] = availableFpsRanges.data.i32[0];
+    previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
+    params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+            String8::format("%d,%d",
+                    previewFpsRange[0],
+                    previewFpsRange[1]));
+
+    {
+        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]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+                supportedPreviewFpsRange);
+    }
+
+    previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+    params.set(CameraParameters::KEY_PREVIEW_FORMAT,
+            formatEnumToString(previewFormat)); // NV21
+
+    previewTransform = degToTransform(0,
+            cameraFacing == CAMERA_FACING_FRONT);
+
+    camera_metadata_ro_entry_t availableFormats =
+        staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+
+    {
+        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 +=
+                    CameraParameters::PIXEL_FORMAT_YUV422SP;
+                break;
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV420SP;
+                break;
+            case HAL_PIXEL_FORMAT_YCbCr_422_I:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV422I;
+                break;
+            case HAL_PIXEL_FORMAT_YV12:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV420P;
+                break;
+            case HAL_PIXEL_FORMAT_RGB_565:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_RGB565;
+                break;
+            case HAL_PIXEL_FORMAT_RGBA_8888:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_RGBA8888;
+                break;
+            // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+            case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            case HAL_PIXEL_FORMAT_BLOB:
+                addComma = false;
+                break;
+
+            default:
+                ALOGW("%s: Camera %d: Unknown preview format: %x",
+                        __FUNCTION__, cameraId, availableFormats.data.i32[i]);
+                addComma = false;
+                break;
+            }
+        }
+        params.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
+
+    params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
+            previewFpsRange[0]);
+
+    {
+        String8 supportedPreviewFrameRates;
+        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+            if (i != 0) supportedPreviewFrameRates += ",";
+            supportedPreviewFrameRates += String8::format("%d",
+                    availableFpsRanges.data.i32[i]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
+                supportedPreviewFrameRates);
+    }
+
+    camera_metadata_ro_entry_t availableJpegSizes =
+        staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, 2);
+    if (!availableJpegSizes.count) return NO_INIT;
+
+    // TODO: Pick maximum
+    pictureWidth = availableJpegSizes.data.i32[0];
+    pictureHeight = availableJpegSizes.data.i32[1];
+
+    params.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]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
+                supportedPictureSizes);
+    }
+
+    params.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
+    params.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
+            CameraParameters::PIXEL_FORMAT_JPEG);
+
+    camera_metadata_ro_entry_t availableJpegThumbnailSizes =
+        staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 2);
+    if (!availableJpegThumbnailSizes.count) return NO_INIT;
+
+    // TODO: Pick default thumbnail size sensibly
+    jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0];
+    jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1];
+
+    params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+            jpegThumbSize[0]);
+    params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+            jpegThumbSize[1]);
+
+    {
+        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]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES,
+                supportedJpegThumbSizes);
+    }
+
+    jpegThumbQuality = 90;
+    params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
+            jpegThumbQuality);
+    jpegQuality = 90;
+    params.set(CameraParameters::KEY_JPEG_QUALITY,
+            jpegQuality);
+    jpegRotation = 0;
+    params.set(CameraParameters::KEY_ROTATION,
+            jpegRotation);
+
+    gpsEnabled = false;
+    gpsProcessingMethod = "unknown";
+    // GPS fields in CameraParameters are not set by implementation
+
+    wbMode = ANDROID_CONTROL_AWB_AUTO;
+    params.set(CameraParameters::KEY_WHITE_BALANCE,
+            CameraParameters::WHITE_BALANCE_AUTO);
+
+    camera_metadata_ro_entry_t availableWhiteBalanceModes =
+        staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+    {
+        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 +=
+                    CameraParameters::WHITE_BALANCE_AUTO;
+                break;
+            case ANDROID_CONTROL_AWB_INCANDESCENT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_INCANDESCENT;
+                break;
+            case ANDROID_CONTROL_AWB_FLUORESCENT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_FLUORESCENT;
+                break;
+            case ANDROID_CONTROL_AWB_WARM_FLUORESCENT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT;
+                break;
+            case ANDROID_CONTROL_AWB_DAYLIGHT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_DAYLIGHT;
+                break;
+            case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT;
+                break;
+            case ANDROID_CONTROL_AWB_TWILIGHT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_TWILIGHT;
+                break;
+            case ANDROID_CONTROL_AWB_SHADE:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_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__, cameraId,
+                        availableWhiteBalanceModes.data.u8[i]);
+                addComma = false;
+                break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+                supportedWhiteBalance);
+    }
+
+    effectMode = ANDROID_CONTROL_EFFECT_OFF;
+    params.set(CameraParameters::KEY_EFFECT,
+            CameraParameters::EFFECT_NONE);
+
+    camera_metadata_ro_entry_t availableEffects =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+    if (!availableEffects.count) return NO_INIT;
+    {
+        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 +=
+                        CameraParameters::EFFECT_NONE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_MONO:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_MONO;
+                    break;
+                case ANDROID_CONTROL_EFFECT_NEGATIVE:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_NEGATIVE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_SOLARIZE:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_SOLARIZE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_SEPIA:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_SEPIA;
+                    break;
+                case ANDROID_CONTROL_EFFECT_POSTERIZE:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_POSTERIZE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_WHITEBOARD:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_WHITEBOARD;
+                    break;
+                case ANDROID_CONTROL_EFFECT_BLACKBOARD:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_BLACKBOARD;
+                    break;
+                case ANDROID_CONTROL_EFFECT_AQUA:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_AQUA;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown effect value: %d",
+                        __FUNCTION__, cameraId, availableEffects.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_EFFECTS, supportedEffects);
+    }
+
+    antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_AUTO;
+    params.set(CameraParameters::KEY_ANTIBANDING,
+            CameraParameters::ANTIBANDING_AUTO);
+
+    camera_metadata_ro_entry_t availableAntibandingModes =
+        staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+    if (!availableAntibandingModes.count) return NO_INIT;
+    {
+        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 +=
+                        CameraParameters::ANTIBANDING_OFF;
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_50HZ:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_50HZ;
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_60HZ:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_60HZ;
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_AUTO:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_AUTO;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown antibanding value: %d",
+                        __FUNCTION__, cameraId,
+                            availableAntibandingModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+                supportedAntibanding);
+    }
+
+    sceneMode = ANDROID_CONTROL_OFF;
+    params.set(CameraParameters::KEY_SCENE_MODE,
+            CameraParameters::SCENE_MODE_AUTO);
+
+    camera_metadata_ro_entry_t availableSceneModes =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+    if (!availableSceneModes.count) return NO_INIT;
+    {
+        String8 supportedSceneModes(CameraParameters::SCENE_MODE_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 +=
+                        CameraParameters::SCENE_MODE_ACTION;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_PORTRAIT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_PORTRAIT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_LANDSCAPE:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_LANDSCAPE;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_NIGHT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_NIGHT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_NIGHT_PORTRAIT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_THEATRE:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_THEATRE;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_BEACH:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_BEACH;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SNOW:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_SNOW;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SUNSET:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_SUNSET;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_STEADYPHOTO;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_FIREWORKS:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_FIREWORKS;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SPORTS:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_SPORTS;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_PARTY:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_PARTY;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_CANDLELIGHT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_BARCODE:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_BARCODE;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown scene mode value: %d",
+                        __FUNCTION__, cameraId,
+                            availableSceneModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        if (!noSceneModes) {
+            params.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES,
+                    supportedSceneModes);
+        }
+    }
+
+    camera_metadata_ro_entry_t flashAvailable =
+        staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
+    if (!flashAvailable.count) return NO_INIT;
+
+    camera_metadata_ro_entry_t availableAeModes =
+        staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+    if (!availableAeModes.count) return NO_INIT;
+
+    if (flashAvailable.data.u8[0]) {
+        flashMode = Parameters::FLASH_MODE_AUTO;
+        params.set(CameraParameters::KEY_FLASH_MODE,
+                CameraParameters::FLASH_MODE_AUTO);
+
+        String8 supportedFlashModes(CameraParameters::FLASH_MODE_OFF);
+        supportedFlashModes = supportedFlashModes +
+            "," + CameraParameters::FLASH_MODE_AUTO +
+            "," + CameraParameters::FLASH_MODE_ON +
+            "," + CameraParameters::FLASH_MODE_TORCH;
+        for (size_t i=0; i < availableAeModes.count; i++) {
+            if (availableAeModes.data.u8[i] ==
+                    ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE) {
+                supportedFlashModes = supportedFlashModes + "," +
+                    CameraParameters::FLASH_MODE_RED_EYE;
+                break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+                supportedFlashModes);
+    } else {
+        flashMode = Parameters::FLASH_MODE_OFF;
+        params.set(CameraParameters::KEY_FLASH_MODE,
+                CameraParameters::FLASH_MODE_OFF);
+        params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+                CameraParameters::FLASH_MODE_OFF);
+    }
+
+    camera_metadata_ro_entry_t minFocusDistance =
+        staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE, 1, 1);
+    if (!minFocusDistance.count) return NO_INIT;
+
+    camera_metadata_ro_entry_t availableAfModes =
+        staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+    if (!availableAfModes.count) return NO_INIT;
+
+    if (minFocusDistance.data.f[0] == 0) {
+        // Fixed-focus lens
+        focusMode = Parameters::FOCUS_MODE_FIXED;
+        params.set(CameraParameters::KEY_FOCUS_MODE,
+                CameraParameters::FOCUS_MODE_FIXED);
+        params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+                CameraParameters::FOCUS_MODE_FIXED);
+    } else {
+        focusMode = Parameters::FOCUS_MODE_AUTO;
+        params.set(CameraParameters::KEY_FOCUS_MODE,
+                CameraParameters::FOCUS_MODE_AUTO);
+        String8 supportedFocusModes(CameraParameters::FOCUS_MODE_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 +=
+                        CameraParameters::FOCUS_MODE_AUTO;
+                    break;
+                case ANDROID_CONTROL_AF_MACRO:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_MACRO;
+                    break;
+                case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO;
+                    break;
+                case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE;
+                    break;
+                case ANDROID_CONTROL_AF_EDOF:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_EDOF;
+                    break;
+                // Not supported in old API
+                case ANDROID_CONTROL_AF_OFF:
+                    addComma = false;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown AF mode value: %d",
+                        __FUNCTION__, cameraId, availableAfModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+                supportedFocusModes);
+    }
+
+    camera_metadata_ro_entry_t max3aRegions =
+        staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
+    if (!max3aRegions.count) return NO_INIT;
+
+    params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS,
+            max3aRegions.data.i32[0]);
+    params.set(CameraParameters::KEY_FOCUS_AREAS,
+            "(0,0,0,0,0)");
+    focusingAreas.clear();
+    focusingAreas.add(Parameters::Area(0,0,0,0,0));
+
+    camera_metadata_ro_entry_t availableFocalLengths =
+        staticInfo(ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS);
+    if (!availableFocalLengths.count) return NO_INIT;
+
+    float minFocalLength = availableFocalLengths.data.f[0];
+    params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+
+    camera_metadata_ro_entry_t sensorSize =
+        staticInfo(ANDROID_SENSOR_PHYSICAL_SIZE, 2, 2);
+    if (!sensorSize.count) return NO_INIT;
+
+    // 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));
+    params.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, horizFov);
+    params.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, vertFov);
+
+    exposureCompensation = 0;
+    params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION,
+                exposureCompensation);
+
+    camera_metadata_ro_entry_t exposureCompensationRange =
+        staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE, 2, 2);
+    if (!exposureCompensationRange.count) return NO_INIT;
+
+    params.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION,
+            exposureCompensationRange.data.i32[1]);
+    params.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION,
+            exposureCompensationRange.data.i32[0]);
+
+    camera_metadata_ro_entry_t exposureCompensationStep =
+        staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_STEP, 1, 1);
+    if (!exposureCompensationStep.count) return NO_INIT;
+
+    params.setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP,
+            (float)exposureCompensationStep.data.r[0].numerator /
+            exposureCompensationStep.data.r[0].denominator);
+
+    autoExposureLock = false;
+    params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK,
+            CameraParameters::FALSE);
+    params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED,
+            CameraParameters::TRUE);
+
+    autoWhiteBalanceLock = false;
+    params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK,
+            CameraParameters::FALSE);
+    params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED,
+            CameraParameters::TRUE);
+
+    meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
+    params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
+            max3aRegions.data.i32[0]);
+    params.set(CameraParameters::KEY_METERING_AREAS,
+            "(0,0,0,0,0)");
+
+    zoom = 0;
+    params.set(CameraParameters::KEY_ZOOM, zoom);
+    params.set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
+
+    camera_metadata_ro_entry_t maxDigitalZoom =
+        staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM, 1, 1);
+    if (!maxDigitalZoom.count) return NO_INIT;
+
+    {
+        String8 zoomRatios;
+        float zoom = 1.f;
+        float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
+                (NUM_ZOOM_STEPS-1);
+        bool addComma = false;
+        for (size_t i=0; i < NUM_ZOOM_STEPS; i++) {
+            if (addComma) zoomRatios += ",";
+            addComma = true;
+            zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
+            zoom += zoomIncrement;
+        }
+        params.set(CameraParameters::KEY_ZOOM_RATIOS, zoomRatios);
+    }
+
+    params.set(CameraParameters::KEY_ZOOM_SUPPORTED,
+            CameraParameters::TRUE);
+    params.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED,
+            CameraParameters::TRUE);
+
+    params.set(CameraParameters::KEY_FOCUS_DISTANCES,
+            "Infinity,Infinity,Infinity");
+
+    params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
+            fastInfo.maxFaces);
+    params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
+            0);
+
+    params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
+            CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE);
+
+    params.set(CameraParameters::KEY_RECORDING_HINT,
+            CameraParameters::FALSE);
+
+    params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED,
+            CameraParameters::TRUE);
+
+    params.set(CameraParameters::KEY_VIDEO_STABILIZATION,
+            CameraParameters::FALSE);
+
+    camera_metadata_ro_entry_t availableVideoStabilizationModes =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+    if (!availableVideoStabilizationModes.count) return NO_INIT;
+
+    if (availableVideoStabilizationModes.count > 1) {
+        params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+                CameraParameters::TRUE);
+    } else {
+        params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+                CameraParameters::FALSE);
+    }
+
+    // Set up initial state for non-Camera.Parameters state variables
+
+    storeMetadataInBuffers = true;
+    playShutterSound = true;
+    enableFaceDetect = false;
+
+    enableFocusMoveMessages = false;
+    afTriggerCounter = 0;
+    currentAfTriggerId = -1;
+
+    previewCallbackFlags = 0;
+
+    state = STOPPED;
+
+    paramsFlattened = params.flatten();
+
+    return OK;
+}
+
+status_t Parameters::buildFastInfo() {
+
+    camera_metadata_ro_entry_t activeArraySize =
+        staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
+    if (!activeArraySize.count) return NO_INIT;
+    int32_t arrayWidth = activeArraySize.data.i32[0];
+    int32_t arrayHeight = activeArraySize.data.i32[1];
+
+    camera_metadata_ro_entry_t availableFaceDetectModes =
+        staticInfo(ANDROID_STATS_AVAILABLE_FACE_DETECT_MODES);
+    if (!availableFaceDetectModes.count) return NO_INIT;
+
+    uint8_t bestFaceDetectMode =
+        ANDROID_STATS_FACE_DETECTION_OFF;
+    for (size_t i = 0 ; i < availableFaceDetectModes.count; i++) {
+        switch (availableFaceDetectModes.data.u8[i]) {
+            case ANDROID_STATS_FACE_DETECTION_OFF:
+                break;
+            case ANDROID_STATS_FACE_DETECTION_SIMPLE:
+                if (bestFaceDetectMode !=
+                        ANDROID_STATS_FACE_DETECTION_FULL) {
+                    bestFaceDetectMode =
+                        ANDROID_STATS_FACE_DETECTION_SIMPLE;
+                }
+                break;
+            case ANDROID_STATS_FACE_DETECTION_FULL:
+                bestFaceDetectMode =
+                    ANDROID_STATS_FACE_DETECTION_FULL;
+                break;
+            default:
+                ALOGE("%s: Camera %d: Unknown face detect mode %d:",
+                        __FUNCTION__, cameraId,
+                        availableFaceDetectModes.data.u8[i]);
+                return NO_INIT;
+        }
+    }
+
+    camera_metadata_ro_entry_t maxFacesDetected =
+        staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
+    if (!maxFacesDetected.count) return NO_INIT;
+
+    int32_t maxFaces = maxFacesDetected.data.i32[0];
+
+    fastInfo.arrayWidth = arrayWidth;
+    fastInfo.arrayHeight = arrayHeight;
+    fastInfo.bestFaceDetectMode = bestFaceDetectMode;
+    fastInfo.maxFaces = maxFaces;
+    return OK;
+}
+
+camera_metadata_ro_entry_t Parameters::staticInfo(uint32_t tag,
+        size_t minCount, size_t maxCount) const {
+    status_t res;
+    camera_metadata_ro_entry_t entry = info->find(tag);
+
+    if (CC_UNLIKELY( entry.count == 0 )) {
+        const char* tagSection = get_camera_metadata_section_name(tag);
+        if (tagSection == NULL) tagSection = "<unknown>";
+        const char* tagName = get_camera_metadata_tag_name(tag);
+        if (tagName == NULL) tagName = "<unknown>";
+
+        ALOGE("Error finding static metadata entry '%s.%s' (%x)",
+                tagSection, tagName, tag);
+    } else if (CC_UNLIKELY(
+            (minCount != 0 && entry.count < minCount) ||
+            (maxCount != 0 && entry.count > maxCount) ) ) {
+        const char* tagSection = get_camera_metadata_section_name(tag);
+        if (tagSection == NULL) tagSection = "<unknown>";
+        const char* tagName = get_camera_metadata_tag_name(tag);
+        if (tagName == NULL) tagName = "<unknown>";
+        ALOGE("Malformed static metadata entry '%s.%s' (%x):"
+                "Expected between %d and %d values, but got %d values",
+                tagSection, tagName, tag, minCount, maxCount, entry.count);
+    }
+
+    return entry;
+}
+
+status_t Parameters::set(const String8& params) {
+    status_t res;
+
+    CameraParameters newParams(params);
+
+    // TODO: Currently ignoring any changes to supposedly read-only parameters
+    // such as supported preview sizes, etc. Should probably produce an error if
+    // they're changed.
+
+    /** Extract and verify new parameters */
+
+    size_t i;
+
+    Parameters validatedParams(*this);
+
+    // PREVIEW_SIZE
+    newParams.getPreviewSize(&validatedParams.previewWidth,
+            &validatedParams.previewHeight);
+
+    if (validatedParams.previewWidth != previewWidth ||
+            validatedParams.previewHeight != previewHeight) {
+        if (state >= PREVIEW) {
+            ALOGE("%s: Preview size cannot be updated when preview "
+                    "is active! (Currently %d x %d, requested %d x %d",
+                    __FUNCTION__,
+                    previewWidth, previewHeight,
+                    validatedParams.previewWidth, validatedParams.previewHeight);
+            return BAD_VALUE;
+        }
+        camera_metadata_ro_entry_t availablePreviewSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+        for (i = 0; i < availablePreviewSizes.count; i += 2 ) {
+            if ((availablePreviewSizes.data.i32[i] ==
+                    validatedParams.previewWidth) &&
+                (availablePreviewSizes.data.i32[i+1] ==
+                    validatedParams.previewHeight)) break;
+        }
+        if (i == availablePreviewSizes.count) {
+            ALOGE("%s: Requested preview size %d x %d is not supported",
+                    __FUNCTION__, validatedParams.previewWidth,
+                    validatedParams.previewHeight);
+            return BAD_VALUE;
+        }
+    }
+
+    // PREVIEW_FPS_RANGE
+    bool fpsRangeChanged = false;
+    newParams.getPreviewFpsRange(&validatedParams.previewFpsRange[0],
+            &validatedParams.previewFpsRange[1]);
+    if (validatedParams.previewFpsRange[0] != previewFpsRange[0] ||
+            validatedParams.previewFpsRange[1] != previewFpsRange[1]) {
+        fpsRangeChanged = true;
+        camera_metadata_ro_entry_t availablePreviewFpsRanges =
+            staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+        for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
+            if ((availablePreviewFpsRanges.data.i32[i] ==
+                    validatedParams.previewFpsRange[0]) &&
+                (availablePreviewFpsRanges.data.i32[i+1] ==
+                    validatedParams.previewFpsRange[1]) ) {
+                break;
+            }
+        }
+        if (i == availablePreviewFpsRanges.count) {
+            ALOGE("%s: Requested preview FPS range %d - %d is not supported",
+                __FUNCTION__, validatedParams.previewFpsRange[0],
+                    validatedParams.previewFpsRange[1]);
+            return BAD_VALUE;
+        }
+        validatedParams.previewFps = validatedParams.previewFpsRange[0];
+    }
+
+    // PREVIEW_FORMAT
+    validatedParams.previewFormat =
+            formatStringToEnum(newParams.getPreviewFormat());
+    if (validatedParams.previewFormat != previewFormat) {
+        if (state >= PREVIEW) {
+            ALOGE("%s: Preview format cannot be updated when preview "
+                    "is active!", __FUNCTION__);
+            return BAD_VALUE;
+        }
+        camera_metadata_ro_entry_t availableFormats =
+            staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+        for (i = 0; i < availableFormats.count; i++) {
+            if (availableFormats.data.i32[i] == validatedParams.previewFormat)
+                break;
+        }
+        if (i == availableFormats.count) {
+            ALOGE("%s: Requested preview format %s (0x%x) is not supported",
+                    __FUNCTION__, newParams.getPreviewFormat(),
+                    validatedParams.previewFormat);
+            return BAD_VALUE;
+        }
+    }
+
+    // PREVIEW_FRAME_RATE
+    // Deprecated, only use if the preview fps range is unchanged this time.
+    // The single-value FPS is the same as the minimum of the range.
+    if (!fpsRangeChanged) {
+        validatedParams.previewFps = newParams.getPreviewFrameRate();
+        if (validatedParams.previewFps != previewFps) {
+            camera_metadata_ro_entry_t availableFrameRates =
+                staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+            for (i = 0; i < availableFrameRates.count; i+=2) {
+                if (availableFrameRates.data.i32[i] ==
+                        validatedParams.previewFps) break;
+            }
+            if (i == availableFrameRates.count) {
+                ALOGE("%s: Requested preview frame rate %d is not supported",
+                        __FUNCTION__, validatedParams.previewFps);
+                return BAD_VALUE;
+            }
+            validatedParams.previewFpsRange[0] =
+                    availableFrameRates.data.i32[i];
+            validatedParams.previewFpsRange[1] =
+                    availableFrameRates.data.i32[i+1];
+        }
+    }
+
+    // PICTURE_SIZE
+    newParams.getPictureSize(&validatedParams.pictureWidth,
+            &validatedParams.pictureHeight);
+    if (validatedParams.pictureWidth == pictureWidth ||
+            validatedParams.pictureHeight == pictureHeight) {
+        camera_metadata_ro_entry_t availablePictureSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+        for (i = 0; i < availablePictureSizes.count; i+=2) {
+            if ((availablePictureSizes.data.i32[i] ==
+                    validatedParams.pictureWidth) &&
+                (availablePictureSizes.data.i32[i+1] ==
+                    validatedParams.pictureHeight)) break;
+        }
+        if (i == availablePictureSizes.count) {
+            ALOGE("%s: Requested picture size %d x %d is not supported",
+                    __FUNCTION__, validatedParams.pictureWidth,
+                    validatedParams.pictureHeight);
+            return BAD_VALUE;
+        }
+    }
+
+    // JPEG_THUMBNAIL_WIDTH/HEIGHT
+    validatedParams.jpegThumbSize[0] =
+            newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
+    validatedParams.jpegThumbSize[1] =
+            newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
+    if (validatedParams.jpegThumbSize[0] != jpegThumbSize[0] ||
+            validatedParams.jpegThumbSize[1] != jpegThumbSize[1]) {
+        camera_metadata_ro_entry_t availableJpegThumbSizes =
+            staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+        for (i = 0; i < availableJpegThumbSizes.count; i+=2) {
+            if ((availableJpegThumbSizes.data.i32[i] ==
+                    validatedParams.jpegThumbSize[0]) &&
+                (availableJpegThumbSizes.data.i32[i+1] ==
+                    validatedParams.jpegThumbSize[1])) break;
+        }
+        if (i == availableJpegThumbSizes.count) {
+            ALOGE("%s: Requested JPEG thumbnail size %d x %d is not supported",
+                    __FUNCTION__, validatedParams.jpegThumbSize[0],
+                    validatedParams.jpegThumbSize[1]);
+            return BAD_VALUE;
+        }
+    }
+
+    // JPEG_THUMBNAIL_QUALITY
+    validatedParams.jpegThumbQuality =
+            newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+    if (validatedParams.jpegThumbQuality < 0 ||
+            validatedParams.jpegThumbQuality > 100) {
+        ALOGE("%s: Requested JPEG thumbnail quality %d is not supported",
+                __FUNCTION__, validatedParams.jpegThumbQuality);
+        return BAD_VALUE;
+    }
+
+    // JPEG_QUALITY
+    validatedParams.jpegQuality =
+            newParams.getInt(CameraParameters::KEY_JPEG_QUALITY);
+    if (validatedParams.jpegQuality < 0 || validatedParams.jpegQuality > 100) {
+        ALOGE("%s: Requested JPEG quality %d is not supported",
+                __FUNCTION__, validatedParams.jpegQuality);
+        return BAD_VALUE;
+    }
+
+    // ROTATION
+    validatedParams.jpegRotation =
+            newParams.getInt(CameraParameters::KEY_ROTATION);
+    if (validatedParams.jpegRotation != 0 &&
+            validatedParams.jpegRotation != 90 &&
+            validatedParams.jpegRotation != 180 &&
+            validatedParams.jpegRotation != 270) {
+        ALOGE("%s: Requested picture rotation angle %d is not supported",
+                __FUNCTION__, validatedParams.jpegRotation);
+        return BAD_VALUE;
+    }
+
+    // GPS
+
+    const char *gpsLatStr =
+            newParams.get(CameraParameters::KEY_GPS_LATITUDE);
+    if (gpsLatStr != NULL) {
+        const char *gpsLongStr =
+                newParams.get(CameraParameters::KEY_GPS_LONGITUDE);
+        const char *gpsAltitudeStr =
+                newParams.get(CameraParameters::KEY_GPS_ALTITUDE);
+        const char *gpsTimeStr =
+                newParams.get(CameraParameters::KEY_GPS_TIMESTAMP);
+        const char *gpsProcMethodStr =
+                newParams.get(CameraParameters::KEY_GPS_PROCESSING_METHOD);
+        if (gpsLongStr == NULL ||
+                gpsAltitudeStr == NULL ||
+                gpsTimeStr == NULL ||
+                gpsProcMethodStr == NULL) {
+            ALOGE("%s: Incomplete set of GPS parameters provided",
+                    __FUNCTION__);
+            return BAD_VALUE;
+        }
+        char *endPtr;
+        errno = 0;
+        validatedParams.gpsCoordinates[0] = strtod(gpsLatStr, &endPtr);
+        if (errno || endPtr == gpsLatStr) {
+            ALOGE("%s: Malformed GPS latitude: %s", __FUNCTION__, gpsLatStr);
+            return BAD_VALUE;
+        }
+        errno = 0;
+        validatedParams.gpsCoordinates[1] = strtod(gpsLongStr, &endPtr);
+        if (errno || endPtr == gpsLongStr) {
+            ALOGE("%s: Malformed GPS longitude: %s", __FUNCTION__, gpsLongStr);
+            return BAD_VALUE;
+        }
+        errno = 0;
+        validatedParams.gpsCoordinates[2] = strtod(gpsAltitudeStr, &endPtr);
+        if (errno || endPtr == gpsAltitudeStr) {
+            ALOGE("%s: Malformed GPS altitude: %s", __FUNCTION__,
+                    gpsAltitudeStr);
+            return BAD_VALUE;
+        }
+        errno = 0;
+        validatedParams.gpsTimestamp = strtoll(gpsTimeStr, &endPtr, 10);
+        if (errno || endPtr == gpsTimeStr) {
+            ALOGE("%s: Malformed GPS timestamp: %s", __FUNCTION__, gpsTimeStr);
+            return BAD_VALUE;
+        }
+        validatedParams.gpsProcessingMethod = gpsProcMethodStr;
+
+        validatedParams.gpsEnabled = true;
+    } else {
+        validatedParams.gpsEnabled = false;
+    }
+
+    // WHITE_BALANCE
+    validatedParams.wbMode = wbModeStringToEnum(
+        newParams.get(CameraParameters::KEY_WHITE_BALANCE) );
+    if (validatedParams.wbMode != wbMode) {
+        camera_metadata_ro_entry_t availableWbModes =
+            staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+        for (i = 0; i < availableWbModes.count; i++) {
+            if (validatedParams.wbMode == availableWbModes.data.u8[i]) break;
+        }
+        if (i == availableWbModes.count) {
+            ALOGE("%s: Requested white balance mode %s is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_WHITE_BALANCE));
+            return BAD_VALUE;
+        }
+    }
+
+    // EFFECT
+    validatedParams.effectMode = effectModeStringToEnum(
+        newParams.get(CameraParameters::KEY_EFFECT) );
+    if (validatedParams.effectMode != effectMode) {
+        camera_metadata_ro_entry_t availableEffectModes =
+            staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+        for (i = 0; i < availableEffectModes.count; i++) {
+            if (validatedParams.effectMode == availableEffectModes.data.u8[i]) break;
+        }
+        if (i == availableEffectModes.count) {
+            ALOGE("%s: Requested effect mode \"%s\" is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_EFFECT) );
+            return BAD_VALUE;
+        }
+    }
+
+    // ANTIBANDING
+    validatedParams.antibandingMode = abModeStringToEnum(
+        newParams.get(CameraParameters::KEY_ANTIBANDING) );
+    if (validatedParams.antibandingMode != antibandingMode) {
+        camera_metadata_ro_entry_t availableAbModes =
+            staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+        for (i = 0; i < availableAbModes.count; i++) {
+            if (validatedParams.antibandingMode == availableAbModes.data.u8[i])
+                break;
+        }
+        if (i == availableAbModes.count) {
+            ALOGE("%s: Requested antibanding mode \"%s\" is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_ANTIBANDING));
+            return BAD_VALUE;
+        }
+    }
+
+    // SCENE_MODE
+    validatedParams.sceneMode = sceneModeStringToEnum(
+        newParams.get(CameraParameters::KEY_SCENE_MODE) );
+    if (validatedParams.sceneMode != sceneMode &&
+            validatedParams.sceneMode !=
+            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) {
+        camera_metadata_ro_entry_t availableSceneModes =
+            staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+        for (i = 0; i < availableSceneModes.count; i++) {
+            if (validatedParams.sceneMode == availableSceneModes.data.u8[i])
+                break;
+        }
+        if (i == availableSceneModes.count) {
+            ALOGE("%s: Requested scene mode \"%s\" is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_SCENE_MODE));
+            return BAD_VALUE;
+        }
+    }
+
+    // FLASH_MODE
+    validatedParams.flashMode = flashModeStringToEnum(
+        newParams.get(CameraParameters::KEY_FLASH_MODE) );
+    if (validatedParams.flashMode != flashMode) {
+        camera_metadata_ro_entry_t flashAvailable =
+            staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
+        if (!flashAvailable.data.u8[0] &&
+                validatedParams.flashMode != Parameters::FLASH_MODE_OFF) {
+            ALOGE("%s: Requested flash mode \"%s\" is not supported: "
+                    "No flash on device", __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_FLASH_MODE));
+            return BAD_VALUE;
+        } else if (validatedParams.flashMode == Parameters::FLASH_MODE_RED_EYE) {
+            camera_metadata_ro_entry_t availableAeModes =
+                staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+            for (i = 0; i < availableAeModes.count; i++) {
+                if (validatedParams.flashMode == availableAeModes.data.u8[i])
+                    break;
+            }
+            if (i == availableAeModes.count) {
+                ALOGE("%s: Requested flash mode \"%s\" is not supported",
+                        __FUNCTION__,
+                        newParams.get(CameraParameters::KEY_FLASH_MODE));
+                return BAD_VALUE;
+            }
+        } else if (validatedParams.flashMode == -1) {
+            ALOGE("%s: Requested flash mode \"%s\" is unknown",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_FLASH_MODE));
+            return BAD_VALUE;
+        }
+    }
+
+    // FOCUS_MODE
+    validatedParams.focusMode = focusModeStringToEnum(
+        newParams.get(CameraParameters::KEY_FOCUS_MODE));
+    if (validatedParams.focusMode != focusMode) {
+        validatedParams.currentAfTriggerId = -1;
+        if (validatedParams.focusMode != Parameters::FOCUS_MODE_FIXED) {
+            camera_metadata_ro_entry_t minFocusDistance =
+                staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE);
+            if (minFocusDistance.data.f[0] == 0) {
+                ALOGE("%s: Requested focus mode \"%s\" is not available: "
+                        "fixed focus lens",
+                        __FUNCTION__,
+                        newParams.get(CameraParameters::KEY_FOCUS_MODE));
+                return BAD_VALUE;
+            } else if (validatedParams.focusMode !=
+                    Parameters::FOCUS_MODE_INFINITY) {
+                camera_metadata_ro_entry_t availableFocusModes =
+                    staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+                for (i = 0; i < availableFocusModes.count; i++) {
+                    if (validatedParams.focusMode ==
+                            availableFocusModes.data.u8[i]) break;
+                }
+                if (i == availableFocusModes.count) {
+                    ALOGE("%s: Requested focus mode \"%s\" is not supported",
+                            __FUNCTION__,
+                            newParams.get(CameraParameters::KEY_FOCUS_MODE));
+                    return BAD_VALUE;
+                }
+            }
+        }
+    } else {
+        validatedParams.currentAfTriggerId = currentAfTriggerId;
+    }
+
+    // FOCUS_AREAS
+    res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
+            &validatedParams.focusingAreas);
+    size_t max3aRegions =
+        (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+    if (res == OK) res = validateAreas(validatedParams.focusingAreas,
+            max3aRegions);
+    if (res != OK) {
+        ALOGE("%s: Requested focus areas are malformed: %s",
+                __FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
+        return BAD_VALUE;
+    }
+
+    // EXPOSURE_COMPENSATION
+    validatedParams.exposureCompensation =
+        newParams.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION);
+    camera_metadata_ro_entry_t exposureCompensationRange =
+        staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE);
+    if ((validatedParams.exposureCompensation <
+            exposureCompensationRange.data.i32[0]) ||
+        (validatedParams.exposureCompensation >
+            exposureCompensationRange.data.i32[1])) {
+        ALOGE("%s: Requested exposure compensation index is out of bounds: %d",
+                __FUNCTION__, validatedParams.exposureCompensation);
+        return BAD_VALUE;
+    }
+
+    // AUTO_EXPOSURE_LOCK (always supported)
+    validatedParams.autoExposureLock = boolFromString(
+        newParams.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK));
+
+    // AUTO_WHITEBALANCE_LOCK (always supported)
+    validatedParams.autoWhiteBalanceLock = boolFromString(
+        newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
+
+    // METERING_AREAS
+    res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
+            &validatedParams.meteringAreas);
+    if (res == OK) {
+        res = validateAreas(validatedParams.meteringAreas, max3aRegions);
+    }
+    if (res != OK) {
+        ALOGE("%s: Requested metering areas are malformed: %s",
+                __FUNCTION__,
+                newParams.get(CameraParameters::KEY_METERING_AREAS));
+        return BAD_VALUE;
+    }
+
+    // ZOOM
+    validatedParams.zoom = newParams.getInt(CameraParameters::KEY_ZOOM);
+    if (validatedParams.zoom < 0 || validatedParams.zoom > (int)NUM_ZOOM_STEPS) {
+        ALOGE("%s: Requested zoom level %d is not supported",
+                __FUNCTION__, validatedParams.zoom);
+        return BAD_VALUE;
+    }
+
+    // VIDEO_SIZE
+    newParams.getVideoSize(&validatedParams.videoWidth,
+            &validatedParams.videoHeight);
+    if (validatedParams.videoWidth != videoWidth ||
+            validatedParams.videoHeight != videoHeight) {
+        if (state == RECORD) {
+            ALOGE("%s: Video size cannot be updated when recording is active!",
+                    __FUNCTION__);
+            return BAD_VALUE;
+        }
+        camera_metadata_ro_entry_t availableVideoSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+        for (i = 0; i < availableVideoSizes.count; i += 2 ) {
+            if ((availableVideoSizes.data.i32[i] ==
+                    validatedParams.videoWidth) &&
+                (availableVideoSizes.data.i32[i+1] ==
+                    validatedParams.videoHeight)) break;
+        }
+        if (i == availableVideoSizes.count) {
+            ALOGE("%s: Requested video size %d x %d is not supported",
+                    __FUNCTION__, validatedParams.videoWidth,
+                    validatedParams.videoHeight);
+            return BAD_VALUE;
+        }
+    }
+
+    // RECORDING_HINT (always supported)
+    validatedParams.recordingHint = boolFromString(
+        newParams.get(CameraParameters::KEY_RECORDING_HINT) );
+
+    // VIDEO_STABILIZATION
+    validatedParams.videoStabilization = boolFromString(
+        newParams.get(CameraParameters::KEY_VIDEO_STABILIZATION) );
+    camera_metadata_ro_entry_t availableVideoStabilizationModes =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+    if (validatedParams.videoStabilization &&
+            availableVideoStabilizationModes.count == 1) {
+        ALOGE("%s: Video stabilization not supported", __FUNCTION__);
+    }
+
+    /** Update internal parameters */
+
+    validatedParams.paramsFlattened = params;
+    *this = validatedParams;
+
+    return OK;
+}
+
+const char* Parameters::getStateName(State state) {
+#define CASE_ENUM_TO_CHAR(x) case x: return(#x); break;
+    switch(state) {
+        CASE_ENUM_TO_CHAR(DISCONNECTED)
+        CASE_ENUM_TO_CHAR(STOPPED)
+        CASE_ENUM_TO_CHAR(WAITING_FOR_PREVIEW_WINDOW)
+        CASE_ENUM_TO_CHAR(PREVIEW)
+        CASE_ENUM_TO_CHAR(RECORD)
+        CASE_ENUM_TO_CHAR(STILL_CAPTURE)
+        CASE_ENUM_TO_CHAR(VIDEO_SNAPSHOT)
+        default:
+            return "Unknown state!";
+            break;
+    }
+#undef CASE_ENUM_TO_CHAR
+}
+
+int Parameters::formatStringToEnum(const char *format) {
+    return
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
+            HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) ?
+            HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) ?
+            HAL_PIXEL_FORMAT_YCbCr_422_I :  // YUY2
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420P) ?
+            HAL_PIXEL_FORMAT_YV12 :         // YV12
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_RGB565) ?
+            HAL_PIXEL_FORMAT_RGB_565 :      // RGB565
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_RGBA8888) ?
+            HAL_PIXEL_FORMAT_RGBA_8888 :    // RGB8888
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ?
+            HAL_PIXEL_FORMAT_RAW_SENSOR :   // Raw sensor data
+        -1;
+}
+
+const char* Parameters::formatEnumToString(int format) {
+    const char *fmt;
+    switch(format) {
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP: // NV16
+            fmt = CameraParameters::PIXEL_FORMAT_YUV422SP;
+            break;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
+            fmt = CameraParameters::PIXEL_FORMAT_YUV420SP;
+            break;
+        case HAL_PIXEL_FORMAT_YCbCr_422_I: // YUY2
+            fmt = CameraParameters::PIXEL_FORMAT_YUV422I;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:        // YV12
+            fmt = CameraParameters::PIXEL_FORMAT_YUV420P;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_565:     // RGB565
+            fmt = CameraParameters::PIXEL_FORMAT_RGB565;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:   // RGBA8888
+            fmt = CameraParameters::PIXEL_FORMAT_RGBA8888;
+            break;
+        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            ALOGW("Raw sensor preview format requested.");
+            fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
+            break;
+        default:
+            ALOGE("%s: Unknown preview format: %x",
+                    __FUNCTION__,  format);
+            fmt = NULL;
+            break;
+    }
+    return fmt;
+}
+
+int Parameters::wbModeStringToEnum(const char *wbMode) {
+    return
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_AUTO) ?
+            ANDROID_CONTROL_AWB_AUTO :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_INCANDESCENT) ?
+            ANDROID_CONTROL_AWB_INCANDESCENT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_FLUORESCENT) ?
+            ANDROID_CONTROL_AWB_FLUORESCENT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT) ?
+            ANDROID_CONTROL_AWB_WARM_FLUORESCENT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_DAYLIGHT) ?
+            ANDROID_CONTROL_AWB_DAYLIGHT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT) ?
+            ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_TWILIGHT) ?
+            ANDROID_CONTROL_AWB_TWILIGHT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_SHADE) ?
+            ANDROID_CONTROL_AWB_SHADE :
+        -1;
+}
+
+int Parameters::effectModeStringToEnum(const char *effectMode) {
+    return
+        !strcmp(effectMode, CameraParameters::EFFECT_NONE) ?
+            ANDROID_CONTROL_EFFECT_OFF :
+        !strcmp(effectMode, CameraParameters::EFFECT_MONO) ?
+            ANDROID_CONTROL_EFFECT_MONO :
+        !strcmp(effectMode, CameraParameters::EFFECT_NEGATIVE) ?
+            ANDROID_CONTROL_EFFECT_NEGATIVE :
+        !strcmp(effectMode, CameraParameters::EFFECT_SOLARIZE) ?
+            ANDROID_CONTROL_EFFECT_SOLARIZE :
+        !strcmp(effectMode, CameraParameters::EFFECT_SEPIA) ?
+            ANDROID_CONTROL_EFFECT_SEPIA :
+        !strcmp(effectMode, CameraParameters::EFFECT_POSTERIZE) ?
+            ANDROID_CONTROL_EFFECT_POSTERIZE :
+        !strcmp(effectMode, CameraParameters::EFFECT_WHITEBOARD) ?
+            ANDROID_CONTROL_EFFECT_WHITEBOARD :
+        !strcmp(effectMode, CameraParameters::EFFECT_BLACKBOARD) ?
+            ANDROID_CONTROL_EFFECT_BLACKBOARD :
+        !strcmp(effectMode, CameraParameters::EFFECT_AQUA) ?
+            ANDROID_CONTROL_EFFECT_AQUA :
+        -1;
+}
+
+int Parameters::abModeStringToEnum(const char *abMode) {
+    return
+        !strcmp(abMode, CameraParameters::ANTIBANDING_AUTO) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_AUTO :
+        !strcmp(abMode, CameraParameters::ANTIBANDING_OFF) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_OFF :
+        !strcmp(abMode, CameraParameters::ANTIBANDING_50HZ) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_50HZ :
+        !strcmp(abMode, CameraParameters::ANTIBANDING_60HZ) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_60HZ :
+        -1;
+}
+
+int Parameters::sceneModeStringToEnum(const char *sceneMode) {
+    return
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_AUTO) ?
+            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_ACTION) ?
+            ANDROID_CONTROL_SCENE_MODE_ACTION :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_PORTRAIT) ?
+            ANDROID_CONTROL_SCENE_MODE_PORTRAIT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_LANDSCAPE) ?
+            ANDROID_CONTROL_SCENE_MODE_LANDSCAPE :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT) ?
+            ANDROID_CONTROL_SCENE_MODE_NIGHT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT_PORTRAIT) ?
+            ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_THEATRE) ?
+            ANDROID_CONTROL_SCENE_MODE_THEATRE :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_BEACH) ?
+            ANDROID_CONTROL_SCENE_MODE_BEACH :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_SNOW) ?
+            ANDROID_CONTROL_SCENE_MODE_SNOW :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_SUNSET) ?
+            ANDROID_CONTROL_SCENE_MODE_SUNSET :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_STEADYPHOTO) ?
+            ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_FIREWORKS) ?
+            ANDROID_CONTROL_SCENE_MODE_FIREWORKS :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_SPORTS) ?
+            ANDROID_CONTROL_SCENE_MODE_SPORTS :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_PARTY) ?
+            ANDROID_CONTROL_SCENE_MODE_PARTY :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_CANDLELIGHT) ?
+            ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_BARCODE) ?
+            ANDROID_CONTROL_SCENE_MODE_BARCODE:
+        -1;
+}
+
+Parameters::Parameters::flashMode_t Parameters::flashModeStringToEnum(
+        const char *flashMode) {
+    return
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_OFF) ?
+            Parameters::FLASH_MODE_OFF :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_AUTO) ?
+            Parameters::FLASH_MODE_AUTO :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_ON) ?
+            Parameters::FLASH_MODE_ON :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_RED_EYE) ?
+            Parameters::FLASH_MODE_RED_EYE :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_TORCH) ?
+            Parameters::FLASH_MODE_TORCH :
+        Parameters::FLASH_MODE_INVALID;
+}
+
+Parameters::Parameters::focusMode_t Parameters::focusModeStringToEnum(
+        const char *focusMode) {
+    return
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_AUTO) ?
+            Parameters::FOCUS_MODE_AUTO :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_INFINITY) ?
+            Parameters::FOCUS_MODE_INFINITY :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_MACRO) ?
+            Parameters::FOCUS_MODE_MACRO :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_FIXED) ?
+            Parameters::FOCUS_MODE_FIXED :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_EDOF) ?
+            Parameters::FOCUS_MODE_EDOF :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO) ?
+            Parameters::FOCUS_MODE_CONTINUOUS_VIDEO :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE) ?
+            Parameters::FOCUS_MODE_CONTINUOUS_PICTURE :
+        Parameters::FOCUS_MODE_INVALID;
+}
+
+status_t Parameters::parseAreas(const char *areasCStr,
+        Vector<Parameters::Area> *areas) {
+    static const size_t NUM_FIELDS = 5;
+    areas->clear();
+    if (areasCStr == NULL) {
+        // If no key exists, use default (0,0,0,0,0)
+        areas->push();
+        return OK;
+    }
+    String8 areasStr(areasCStr);
+    ssize_t areaStart = areasStr.find("(", 0) + 1;
+    while (areaStart != 0) {
+        const char* area = areasStr.string() + areaStart;
+        char *numEnd;
+        int vals[NUM_FIELDS];
+        for (size_t i = 0; i < NUM_FIELDS; i++) {
+            errno = 0;
+            vals[i] = strtol(area, &numEnd, 10);
+            if (errno || numEnd == area) return BAD_VALUE;
+            area = numEnd + 1;
+        }
+        areas->push(Parameters::Area(
+            vals[0], vals[1], vals[2], vals[3], vals[4]) );
+        areaStart = areasStr.find("(", areaStart) + 1;
+    }
+    return OK;
+}
+
+status_t Parameters::validateAreas(const Vector<Parameters::Area> &areas,
+                                      size_t maxRegions) {
+    // Definition of valid area can be found in
+    // include/camera/CameraParameters.h
+    if (areas.size() == 0) return BAD_VALUE;
+    if (areas.size() == 1) {
+        if (areas[0].left == 0 &&
+                areas[0].top == 0 &&
+                areas[0].right == 0 &&
+                areas[0].bottom == 0 &&
+                areas[0].weight == 0) {
+            // Single (0,0,0,0,0) entry is always valid (== driver decides)
+            return OK;
+        }
+    }
+    if (areas.size() > maxRegions) {
+        ALOGE("%s: Too many areas requested: %d",
+                __FUNCTION__, areas.size());
+        return BAD_VALUE;
+    }
+
+    for (Vector<Parameters::Area>::const_iterator a = areas.begin();
+         a != areas.end(); a++) {
+        if (a->weight < 1 || a->weight > 1000) return BAD_VALUE;
+        if (a->left < -1000 || a->left > 1000) return BAD_VALUE;
+        if (a->top < -1000 || a->top > 1000) return BAD_VALUE;
+        if (a->right < -1000 || a->right > 1000) return BAD_VALUE;
+        if (a->bottom < -1000 || a->bottom > 1000) return BAD_VALUE;
+        if (a->left >= a->right) return BAD_VALUE;
+        if (a->top >= a->bottom) return BAD_VALUE;
+    }
+    return OK;
+}
+
+bool Parameters::boolFromString(const char *boolStr) {
+    return !boolStr ? false :
+        !strcmp(boolStr, CameraParameters::TRUE) ? true :
+        false;
+}
+
+int Parameters::degToTransform(int degrees, bool mirror) {
+    if (!mirror) {
+        if (degrees == 0) return 0;
+        else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+        else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+        else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+    } else {  // Do mirror (horizontal flip)
+        if (degrees == 0) {           // FLIP_H and ROT_0
+            return HAL_TRANSFORM_FLIP_H;
+        } else if (degrees == 90) {   // FLIP_H and ROT_90
+            return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+        } else if (degrees == 180) {  // FLIP_H and ROT_180
+            return HAL_TRANSFORM_FLIP_V;
+        } else if (degrees == 270) {  // FLIP_H and ROT_270
+            return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+        }
+    }
+    ALOGE("%s: Bad input: %d", __FUNCTION__, degrees);
+    return -1;
+}
+
+int Parameters::arrayXToNormalized(int width) const {
+    return width * 2000 / (fastInfo.arrayWidth - 1) - 1000;
+}
+
+int Parameters::arrayYToNormalized(int height) const {
+    return height * 2000 / (fastInfo.arrayHeight - 1) - 1000;
+}
+
+int Parameters::normalizedXToArray(int x) const {
+    return (x + 1000) * (fastInfo.arrayWidth - 1) / 2000;
+}
+
+int Parameters::normalizedYToArray(int y) const {
+    return (y + 1000) * (fastInfo.arrayHeight - 1) / 2000;
+}
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/Parameters.h b/services/camera/libcameraservice/camera2/Parameters.h
new file mode 100644
index 0000000..817d001
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/Parameters.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_SERVERS_CAMERA_CAMERA2PARAMETERS_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2PARAMETERS_H
+
+#include <system/graphics.h>
+
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace camera2 {
+
+// Current camera state; this is the full state of the Camera under the old
+// camera API (contents of the CameraParameters object in a more-efficient
+// format, plus other state). The enum values are mostly based off the
+// corresponding camera2 enums, not the camera1 strings. A few are defined here
+// if they don't cleanly map to camera2 values.
+struct Parameters {
+    int cameraId;
+    int cameraFacing;
+
+    int previewWidth, previewHeight;
+    int32_t previewFpsRange[2];
+    int previewFps; // deprecated, here only for tracking changes
+    int previewFormat;
+
+    int previewTransform; // set by CAMERA_CMD_SET_DISPLAY_ORIENTATION
+
+    int pictureWidth, pictureHeight;
+
+    int32_t jpegThumbSize[2];
+    int32_t jpegQuality, jpegThumbQuality;
+    int32_t jpegRotation;
+
+    bool gpsEnabled;
+    double gpsCoordinates[3];
+    int64_t gpsTimestamp;
+    String8 gpsProcessingMethod;
+
+    uint8_t wbMode;
+    uint8_t effectMode;
+    uint8_t antibandingMode;
+    uint8_t sceneMode;
+
+    enum flashMode_t {
+        FLASH_MODE_OFF = 0,
+        FLASH_MODE_AUTO,
+        FLASH_MODE_ON,
+        FLASH_MODE_TORCH,
+        FLASH_MODE_RED_EYE = ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE,
+        FLASH_MODE_INVALID = -1
+    } flashMode;
+
+    enum focusMode_t {
+        FOCUS_MODE_AUTO = ANDROID_CONTROL_AF_AUTO,
+        FOCUS_MODE_MACRO = ANDROID_CONTROL_AF_MACRO,
+        FOCUS_MODE_CONTINUOUS_VIDEO = ANDROID_CONTROL_AF_CONTINUOUS_VIDEO,
+        FOCUS_MODE_CONTINUOUS_PICTURE = ANDROID_CONTROL_AF_CONTINUOUS_PICTURE,
+        FOCUS_MODE_EDOF = ANDROID_CONTROL_AF_EDOF,
+        FOCUS_MODE_INFINITY,
+        FOCUS_MODE_FIXED,
+        FOCUS_MODE_INVALID = -1
+    } focusMode;
+
+    struct Area {
+        int left, top, right, bottom;
+        int weight;
+        Area() {}
+        Area(int left, int top, int right, int bottom, int weight):
+                left(left), top(top), right(right), bottom(bottom),
+                weight(weight) {}
+    };
+    Vector<Area> focusingAreas;
+
+    int32_t exposureCompensation;
+    bool autoExposureLock;
+    bool autoWhiteBalanceLock;
+
+    Vector<Area> meteringAreas;
+
+    int zoom;
+
+    int videoWidth, videoHeight;
+
+    bool recordingHint;
+    bool videoStabilization;
+
+    String8 paramsFlattened;
+
+    // These parameters are also part of the camera API-visible state, but not
+    // directly listed in Camera.Parameters
+    bool storeMetadataInBuffers;
+    bool playShutterSound;
+    bool enableFaceDetect;
+
+    bool enableFocusMoveMessages;
+    int afTriggerCounter;
+    int currentAfTriggerId;
+    bool afInMotion;
+
+    uint32_t previewCallbackFlags;
+    bool previewCallbackOneShot;
+
+    // Overall camera state
+    enum State {
+        DISCONNECTED,
+        STOPPED,
+        WAITING_FOR_PREVIEW_WINDOW,
+        PREVIEW,
+        RECORD,
+        STILL_CAPTURE,
+        VIDEO_SNAPSHOT
+    } state;
+
+    // Number of zoom steps to simulate
+    static const unsigned int NUM_ZOOM_STEPS = 10;
+
+    // Full static camera info, object owned by someone else, such as
+    // Camera2Device.
+    const CameraMetadata *info;
+
+    // Fast-access static device information; this is a subset of the
+    // information available through the staticInfo() method, used for
+    // frequently-accessed values or values that have to be calculated from the
+    // static information.
+    struct DeviceInfo {
+        int32_t arrayWidth;
+        int32_t arrayHeight;
+        uint8_t bestFaceDetectMode;
+        int32_t maxFaces;
+    } fastInfo;
+
+    // Parameter manipulation and setup methods
+
+    Parameters(int cameraId, int cameraFacing);
+    ~Parameters();
+
+    // Sets up default parameters
+    status_t initialize(const CameraMetadata *info);
+
+    // Build fast device info
+    status_t buildFastInfo();
+
+    // Get entry from camera static characteristics information. min/maxCount
+    // are used for error checking the number of values in the entry. 0 for
+    // max/minCount means to do no bounds check in that direction. In case of
+    // error, the entry data pointer is null and the count is 0.
+    camera_metadata_ro_entry_t staticInfo(uint32_t tag,
+            size_t minCount=0, size_t maxCount=0) const;
+
+    // Validate and update camera parameters based on new settings
+    status_t set(const String8 &params);
+
+    // Static methods for debugging and converting between camera1 and camera2
+    // parameters
+
+    static const char *getStateName(State state);
+
+    static int formatStringToEnum(const char *format);
+    static const char *formatEnumToString(int format);
+
+    static int wbModeStringToEnum(const char *wbMode);
+    static int effectModeStringToEnum(const char *effectMode);
+    static int abModeStringToEnum(const char *abMode);
+    static int sceneModeStringToEnum(const char *sceneMode);
+    static flashMode_t flashModeStringToEnum(const char *flashMode);
+    static focusMode_t focusModeStringToEnum(const char *focusMode);
+    static status_t parseAreas(const char *areasCStr,
+            Vector<Area> *areas);
+    static status_t validateAreas(const Vector<Area> &areas,
+                                  size_t maxRegions);
+    static bool boolFromString(const char *boolStr);
+
+    // Map from camera orientation + facing to gralloc transform enum
+    static int degToTransform(int degrees, bool mirror);
+
+    // Transform between (-1000,-1000)-(1000,1000) normalized coords from camera
+    // API and HAL2 (0,0)-(activePixelArray.width/height) coordinates
+    int arrayXToNormalized(int width) const;
+    int arrayYToNormalized(int height) const;
+    int normalizedXToArray(int x) const;
+    int normalizedYToArray(int y) const;
+
+};
+
+// This class encapsulates the Parameters class so that it can only be accessed
+// by constructing a Lock object, which locks the SharedParameter's mutex.
+class SharedParameters {
+  public:
+    SharedParameters(int cameraId, int cameraFacing):
+            mParameters(cameraId, cameraFacing) {
+    }
+
+    template<typename S, typename P>
+    class BaseLock {
+      public:
+        BaseLock(S &p):
+                mParameters(p.mParameters),
+                mSharedParameters(p) {
+            mSharedParameters.mLock.lock();
+        }
+
+        ~BaseLock() {
+            mSharedParameters.mLock.unlock();
+        }
+        P &mParameters;
+      private:
+        // Disallow copying, default construction
+        BaseLock();
+        BaseLock(const BaseLock &);
+        BaseLock &operator=(const BaseLock &);
+        S &mSharedParameters;
+    };
+    typedef BaseLock<SharedParameters, Parameters> Lock;
+    typedef BaseLock<const SharedParameters, const Parameters> ReadLock;
+
+    // Access static info, read-only and immutable, so no lock needed
+    camera_metadata_ro_entry_t staticInfo(uint32_t tag,
+            size_t minCount=0, size_t maxCount=0) const {
+        return mParameters.staticInfo(tag, minCount, maxCount);
+    }
+
+    // Only use for dumping or other debugging
+    const Parameters &unsafeAccess() {
+        return mParameters;
+    }
+  private:
+    Parameters mParameters;
+    mutable Mutex mLock;
+};
+
+
+}; // namespace camera2
+}; // namespace android
+
+#endif