Camera2: get stream configs by device verison

Starting from device version 3.2, the following tags:
    ANDROID_SCALER_AVAILABLE_FORMATS
    ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS
    ANDROID_SCALER_AVAILABLE_JPEG_SIZES
    ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
    ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES
    ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS
    ANDROID_SCALER_AVAILABLE_RAW_SIZES

are deprecated and replaced by:
    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS

Change-Id: Iadc34af0ea985a16a25759d7a9a3eb4845c486fd
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 109b891..648e82c 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -689,8 +689,7 @@
           case CAMERA_DEVICE_API_VERSION_3_2:
             client = new Camera2Client(this, cameraClient,
                     clientPackageName, cameraId,
-                    facing, callingPid, clientUid, getpid(),
-                    deviceVersion);
+                    facing, callingPid, clientUid, getpid());
             break;
           case -1:
             ALOGE("Invalid camera id %d", cameraId);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 0447979..a6f5a6c 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -53,12 +53,10 @@
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
-        int servicePid,
-        int deviceVersion):
+        int servicePid):
         Camera2ClientBase(cameraService, cameraClient, clientPackageName,
                 cameraId, cameraFacing, clientPid, clientUid, servicePid),
-        mParameters(cameraId, cameraFacing),
-        mDeviceVersion(deviceVersion)
+        mParameters(cameraId, cameraFacing)
 {
     ATRACE_CALL();
 
@@ -80,7 +78,7 @@
     {
         SharedParameters::Lock l(mParameters);
 
-        res = l.mParameters.initialize(&(mDevice->info()));
+        res = l.mParameters.initialize(&(mDevice->info()), mDeviceVersion);
         if (res != OK) {
             ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
                     __FUNCTION__, mCameraId, strerror(-res), res);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index fe0bf74..0e06195 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -89,8 +89,7 @@
             int cameraFacing,
             int clientPid,
             uid_t clientUid,
-            int servicePid,
-            int deviceVersion);
+            int servicePid);
 
     virtual ~Camera2Client();
 
@@ -170,7 +169,6 @@
 
     void     setPreviewCallbackFlagL(Parameters &params, int flag);
     status_t updateRequests(Parameters &params);
-    int mDeviceVersion;
 
     // Used with stream IDs
     static const int NO_STREAM = -1;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 51b1980..6459300 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -29,6 +29,7 @@
 
 #include "Parameters.h"
 #include "system/camera.h"
+#include "hardware/camera_common.h"
 #include <media/MediaProfiles.h>
 #include <media/mediarecorder.h>
 
@@ -45,7 +46,7 @@
 Parameters::~Parameters() {
 }
 
-status_t Parameters::initialize(const CameraMetadata *info) {
+status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
     status_t res;
 
     if (info->entryCount() == 0) {
@@ -53,6 +54,7 @@
         return BAD_VALUE;
     }
     Parameters::info = info;
+    mDeviceVersion = deviceVersion;
 
     res = buildFastInfo();
     if (res != OK) return res;
@@ -140,16 +142,14 @@
     previewTransform = degToTransform(0,
             cameraFacing == CAMERA_FACING_FRONT);
 
-    camera_metadata_ro_entry_t availableFormats =
-        staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
-
     {
         String8 supportedPreviewFormats;
+        SortedVector<int32_t> outputFormats = getAvailableOutputFormats();
         bool addComma = false;
-        for (size_t i=0; i < availableFormats.count; i++) {
+        for (size_t i=0; i < outputFormats.size(); i++) {
             if (addComma) supportedPreviewFormats += ",";
             addComma = true;
-            switch (availableFormats.data.i32[i]) {
+            switch (outputFormats[i]) {
             case HAL_PIXEL_FORMAT_YCbCr_422_SP:
                 supportedPreviewFormats +=
                     CameraParameters::PIXEL_FORMAT_YUV422SP;
@@ -191,7 +191,7 @@
 
             default:
                 ALOGW("%s: Camera %d: Unknown preview format: %x",
-                        __FUNCTION__, cameraId, availableFormats.data.i32[i]);
+                        __FUNCTION__, cameraId, outputFormats[i]);
                 addComma = false;
                 break;
             }
@@ -239,24 +239,23 @@
                 supportedPreviewFrameRates);
     }
 
-    camera_metadata_ro_entry_t availableJpegSizes =
-        staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, 2);
-    if (!availableJpegSizes.count) return NO_INIT;
+    Vector<Size> availableJpegSizes = getAvailableJpegSizes();
+    if (!availableJpegSizes.size()) return NO_INIT;
 
     // TODO: Pick maximum
-    pictureWidth = availableJpegSizes.data.i32[0];
-    pictureHeight = availableJpegSizes.data.i32[1];
+    pictureWidth = availableJpegSizes[0].width;
+    pictureHeight = availableJpegSizes[0].height;
 
     params.setPictureSize(pictureWidth,
             pictureHeight);
 
     {
         String8 supportedPictureSizes;
-        for (size_t i=0; i < availableJpegSizes.count; i += 2) {
+        for (size_t i=0; i < availableJpegSizes.size(); i++) {
             if (i != 0) supportedPictureSizes += ",";
             supportedPictureSizes += String8::format("%dx%d",
-                    availableJpegSizes.data.i32[i],
-                    availableJpegSizes.data.i32[i+1]);
+                    availableJpegSizes[i].width,
+                    availableJpegSizes[i].height);
         }
         params.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
                 supportedPictureSizes);
@@ -952,9 +951,8 @@
         staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
     if (!availableFocalLengths.count) return NO_INIT;
 
-    camera_metadata_ro_entry_t availableFormats =
-        staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
-    if (!availableFormats.count) return NO_INIT;
+    SortedVector<int32_t> availableFormats = getAvailableOutputFormats();
+    if (!availableFormats.size()) return NO_INIT;
 
 
     if (sceneModeOverrides.count > 0) {
@@ -1038,8 +1036,8 @@
 
     // Check if the HAL supports HAL_PIXEL_FORMAT_YCbCr_420_888
     fastInfo.useFlexibleYuv = false;
-    for (size_t i = 0; i < availableFormats.count; i++) {
-        if (availableFormats.data.i32[i] == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+    for (size_t i = 0; i < availableFormats.size(); i++) {
+        if (availableFormats[i] == HAL_PIXEL_FORMAT_YCbCr_420_888) {
             fastInfo.useFlexibleYuv = true;
             break;
         }
@@ -1198,8 +1196,7 @@
                     "is active!", __FUNCTION__);
             return BAD_VALUE;
         }
-        camera_metadata_ro_entry_t availableFormats =
-            staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+        SortedVector<int32_t> availableFormats = getAvailableOutputFormats();
         // If using flexible YUV, always support NV21/YV12. Otherwise, check
         // HAL's list.
         if (! (fastInfo.useFlexibleYuv &&
@@ -1208,11 +1205,10 @@
                  validatedParams.previewFormat ==
                         HAL_PIXEL_FORMAT_YV12) ) ) {
             // Not using flexible YUV format, so check explicitly
-            for (i = 0; i < availableFormats.count; i++) {
-                if (availableFormats.data.i32[i] ==
-                        validatedParams.previewFormat) break;
+            for (i = 0; i < availableFormats.size(); i++) {
+                if (availableFormats[i] == validatedParams.previewFormat) break;
             }
-            if (i == availableFormats.count) {
+            if (i == availableFormats.size()) {
                 ALOGE("%s: Requested preview format %s (0x%x) is not supported",
                         __FUNCTION__, newParams.getPreviewFormat(),
                         validatedParams.previewFormat);
@@ -1302,15 +1298,14 @@
             &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] ==
+        Vector<Size> availablePictureSizes = getAvailableJpegSizes();
+        for (i = 0; i < availablePictureSizes.size(); i++) {
+            if ((availablePictureSizes[i].width ==
                     validatedParams.pictureWidth) &&
-                (availablePictureSizes.data.i32[i+1] ==
+                (availablePictureSizes[i].height ==
                     validatedParams.pictureHeight)) break;
         }
-        if (i == availablePictureSizes.count) {
+        if (i == availablePictureSizes.size()) {
             ALOGE("%s: Requested picture size %d x %d is not supported",
                     __FUNCTION__, validatedParams.pictureWidth,
                     validatedParams.pictureHeight);
@@ -2527,22 +2522,37 @@
         ALOGE("%s: Input size is null", __FUNCTION__);
         return BAD_VALUE;
     }
+    sizes->clear();
 
-    const size_t SIZE_COUNT = sizeof(Size) / sizeof(int);
-    camera_metadata_ro_entry_t availableProcessedSizes =
-        staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, SIZE_COUNT);
-    if (availableProcessedSizes.count < SIZE_COUNT) return BAD_VALUE;
-
-    Size filteredSize;
-    for (size_t i = 0; i < availableProcessedSizes.count; i += SIZE_COUNT) {
-        filteredSize.width = availableProcessedSizes.data.i32[i];
-        filteredSize.height = availableProcessedSizes.data.i32[i+1];
-            // Need skip the preview sizes that are too large.
-            if (filteredSize.width <= limit.width &&
-                    filteredSize.height <= limit.height) {
-                sizes->push(filteredSize);
+    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+        Vector<StreamConfiguration> scs = getStreamConfigurations();
+        for (size_t i=0; i < scs.size(); i++) {
+            const StreamConfiguration &sc = scs[i];
+            if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
+                    sc.width <= limit.width && sc.height <= limit.height) {
+                Size sz = {sc.width, sc.height};
+                sizes->push(sz);
             }
+        }
+    } else {
+        const size_t SIZE_COUNT = sizeof(Size) / sizeof(int);
+        camera_metadata_ro_entry_t availableProcessedSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, SIZE_COUNT);
+        if (availableProcessedSizes.count < SIZE_COUNT) return BAD_VALUE;
+
+        Size filteredSize;
+        for (size_t i = 0; i < availableProcessedSizes.count; i += SIZE_COUNT) {
+            filteredSize.width = availableProcessedSizes.data.i32[i];
+            filteredSize.height = availableProcessedSizes.data.i32[i+1];
+                // Need skip the preview sizes that are too large.
+                if (filteredSize.width <= limit.width &&
+                        filteredSize.height <= limit.height) {
+                    sizes->push(filteredSize);
+                }
+        }
     }
+
     if (sizes->isEmpty()) {
         ALOGE("generated preview size list is empty!!");
         return BAD_VALUE;
@@ -2576,6 +2586,78 @@
     return maxSize;
 }
 
+Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {
+    const int STREAM_CONFIGURATION_SIZE = 4;
+    const int STREAM_FORMAT_OFFSET = 0;
+    const int STREAM_WIDTH_OFFSET = 1;
+    const int STREAM_HEIGHT_OFFSET = 2;
+    const int STREAM_IS_INPUT_OFFSET = 3;
+    Vector<StreamConfiguration> scs;
+    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+        ALOGE("StreamConfiguration is only valid after device HAL 3.2!");
+        return scs;
+    }
+
+    camera_metadata_ro_entry_t availableStreamConfigs =
+                staticInfo(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+    for (size_t i=0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {
+        int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
+        int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
+        int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
+        int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
+        StreamConfiguration sc = {format, width, height, isInput};
+        scs.add(sc);
+    }
+    return scs;
+}
+
+SortedVector<int32_t> Parameters::getAvailableOutputFormats() {
+    SortedVector<int32_t> outputFormats; // Non-duplicated output formats
+    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+        Vector<StreamConfiguration> scs = getStreamConfigurations();
+        for (size_t i=0; i < scs.size(); i++) {
+            const StreamConfiguration &sc = scs[i];
+            if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
+                outputFormats.add(sc.format);
+            }
+        }
+    } else {
+        camera_metadata_ro_entry_t availableFormats = staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+        for (size_t i=0; i < availableFormats.count; i++) {
+            outputFormats.add(availableFormats.data.i32[i]);
+        }
+    }
+    return outputFormats;
+}
+
+Vector<Parameters::Size> Parameters::getAvailableJpegSizes() {
+    Vector<Parameters::Size> jpegSizes;
+    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+        Vector<StreamConfiguration> scs = getStreamConfigurations();
+        for (size_t i=0; i < scs.size(); i++) {
+            const StreamConfiguration &sc = scs[i];
+            if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    sc.format == HAL_PIXEL_FORMAT_BLOB) {
+                Size sz = {sc.width, sc.height};
+                jpegSizes.add(sz);
+            }
+        }
+    } else {
+        const int JPEG_SIZE_ENTRY_COUNT = 2;
+        const int WIDTH_OFFSET = 0;
+        const int HEIGHT_OFFSET = 1;
+        camera_metadata_ro_entry_t availableJpegSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+        for (size_t i=0; i < availableJpegSizes.count; i+= JPEG_SIZE_ENTRY_COUNT) {
+            int width = availableJpegSizes.data.i32[i + WIDTH_OFFSET];
+            int height = availableJpegSizes.data.i32[i + HEIGHT_OFFSET];
+            Size sz = {width, height};
+            jpegSizes.add(sz);
+        }
+    }
+    return jpegSizes;
+}
+
 Parameters::CropRegion Parameters::calculateCropRegion(
                             Parameters::CropRegion::Outputs outputs) const {
 
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 28dd788..f95c69a 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -226,7 +226,7 @@
     ~Parameters();
 
     // Sets up default parameters
-    status_t initialize(const CameraMetadata *info);
+    status_t initialize(const CameraMetadata *info, int deviceVersion);
 
     // Build fast-access device static info from static info
     status_t buildFastInfo();
@@ -346,6 +346,24 @@
     status_t getFilteredSizes(Size limit, Vector<Size> *sizes);
     // Get max size (from the size array) that matches the given aspect ratio.
     Size getMaxSizeForRatio(float ratio, const int32_t* sizeArray, size_t count);
+
+    struct StreamConfiguration {
+        int32_t format;
+        int32_t width;
+        int32_t height;
+        int32_t isInput;
+    };
+    // Helper function extract available stream configuration
+    // Only valid since device HAL version 3.2
+    // returns an empty Vector if device HAL version does support it
+    Vector<StreamConfiguration> getStreamConfigurations();
+
+    // Helper function to get non-duplicated available output formats
+    SortedVector<int32_t> getAvailableOutputFormats();
+    // Helper function to get available output jpeg sizes
+    Vector<Size> getAvailableJpegSizes();
+
+    int mDeviceVersion;
 };
 
 // This class encapsulates the Parameters class so that it can only be accessed
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 19efd30..13c9f48 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -54,7 +54,8 @@
         int servicePid):
         TClientBase(cameraService, remoteCallback, clientPackageName,
                 cameraId, cameraFacing, clientPid, clientUid, servicePid),
-        mSharedCameraCallbacks(remoteCallback)
+        mSharedCameraCallbacks(remoteCallback),
+        mDeviceVersion(cameraService->getDeviceVersion(cameraId))
 {
     ALOGI("Camera %d: Opened", cameraId);
 
@@ -280,6 +281,11 @@
 }
 
 template <typename TClientBase>
+int Camera2ClientBase<TClientBase>::getCameraDeviceVersion() const {
+    return mDeviceVersion;
+}
+
+template <typename TClientBase>
 const sp<CameraDeviceBase>& Camera2ClientBase<TClientBase>::getCameraDevice() {
     return mDevice;
 }
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 9feca93..f57d204 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -76,6 +76,7 @@
     int                   getCameraId() const;
     const sp<CameraDeviceBase>&
                           getCameraDevice();
+    int                   getCameraDeviceVersion() const;
     const sp<CameraService>&
                           getCameraService();
 
@@ -122,6 +123,7 @@
 
     /** CameraDeviceBase instance wrapping HAL2+ entry */
 
+    const int mDeviceVersion;
     sp<CameraDeviceBase>  mDevice;
 
     /** Utility members */
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a5839ae..24df819 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -113,7 +113,6 @@
     }
 
     /** Cross-check device version */
-
     if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) {
         SET_ERR_L("Could not open camera: "
                 "Camera device should be at least %x, reports %x instead",
@@ -173,6 +172,7 @@
 
     /** Everything is good to go */
 
+    mDeviceVersion = device->common.version;
     mDeviceInfo = info.static_camera_characteristics;
     mHal3Device = device;
     mStatus = STATUS_UNCONFIGURED;
@@ -284,42 +284,74 @@
     return gotLock;
 }
 
+Camera3Device::Size Camera3Device::getMaxJpegResolution() const {
+    int32_t maxJpegWidth = 0, maxJpegHeight = 0;
+    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+        const int STREAM_CONFIGURATION_SIZE = 4;
+        const int STREAM_FORMAT_OFFSET = 0;
+        const int STREAM_WIDTH_OFFSET = 1;
+        const int STREAM_HEIGHT_OFFSET = 2;
+        const int STREAM_IS_INPUT_OFFSET = 3;
+        camera_metadata_ro_entry_t availableStreamConfigs =
+                mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+        if (availableStreamConfigs.count == 0 ||
+                availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) {
+            return Size(0, 0);
+        }
+
+        // Get max jpeg size (area-wise).
+        for (size_t i=0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {
+            int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
+            int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
+            int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
+            int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
+                    && format == HAL_PIXEL_FORMAT_BLOB &&
+                    (width * height > maxJpegWidth * maxJpegHeight)) {
+                maxJpegWidth = width;
+                maxJpegHeight = height;
+            }
+        }
+    } else {
+        camera_metadata_ro_entry availableJpegSizes =
+                mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+        if (availableJpegSizes.count == 0 || availableJpegSizes.count % 2 != 0) {
+            return Size(0, 0);
+        }
+
+        // Get max jpeg size (area-wise).
+        for (size_t i = 0; i < availableJpegSizes.count; i += 2) {
+            if ((availableJpegSizes.data.i32[i] * availableJpegSizes.data.i32[i + 1])
+                    > (maxJpegWidth * maxJpegHeight)) {
+                maxJpegWidth = availableJpegSizes.data.i32[i];
+                maxJpegHeight = availableJpegSizes.data.i32[i + 1];
+            }
+        }
+    }
+    return Size(maxJpegWidth, maxJpegHeight);
+}
+
 ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
-    // TODO: replace below with availableStreamConfiguration for HAL3.2+.
-    camera_metadata_ro_entry availableJpegSizes =
-            mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
-    if (availableJpegSizes.count == 0 || availableJpegSizes.count % 2 != 0) {
+    // Get max jpeg size (area-wise).
+    Size maxJpegResolution = getMaxJpegResolution();
+    if (maxJpegResolution.width == 0) {
         ALOGE("%s: Camera %d: Can't find find valid available jpeg sizes in static metadata!",
                 __FUNCTION__, mId);
         return BAD_VALUE;
     }
 
-    // Get max jpeg size (area-wise).
-    int32_t maxJpegWidth = 0, maxJpegHeight = 0;
-    bool foundMax = false;
-    for (size_t i = 0; i < availableJpegSizes.count; i += 2) {
-        if ((availableJpegSizes.data.i32[i] * availableJpegSizes.data.i32[i + 1])
-                > (maxJpegWidth * maxJpegHeight)) {
-            maxJpegWidth = availableJpegSizes.data.i32[i];
-            maxJpegHeight = availableJpegSizes.data.i32[i + 1];
-            foundMax = true;
-        }
-    }
-    if (!foundMax) {
-        return BAD_VALUE;
-    }
-
     // Get max jpeg buffer size
     ssize_t maxJpegBufferSize = 0;
-    camera_metadata_ro_entry jpegMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
-    if (jpegMaxSize.count == 0) {
+    camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
+    if (jpegBufMaxSize.count == 0) {
         ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
         return BAD_VALUE;
     }
-    maxJpegBufferSize = jpegMaxSize.data.i32[0];
+    maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
 
     // Calculate final jpeg buffer size for the given resolution.
-    float scaleFactor = ((float) (width * height)) / (maxJpegWidth * maxJpegHeight);
+    float scaleFactor = ((float) (width * height)) /
+            (maxJpegResolution.width * maxJpegResolution.height);
     ssize_t jpegBufferSize = scaleFactor * maxJpegBufferSize;
     // Bound the buffer size to [MIN_JPEG_BUFFER_SIZE, maxJpegBufferSize].
     if (jpegBufferSize > maxJpegBufferSize) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 8e238e5..61e6572 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -168,6 +168,8 @@
 
     CameraMetadata             mDeviceInfo;
 
+    int                        mDeviceVersion;
+
     enum Status {
         STATUS_ERROR,
         STATUS_UNINITIALIZED,
@@ -297,6 +299,18 @@
      */
     bool               tryLockSpinRightRound(Mutex& lock);
 
+    struct Size {
+        int width;
+        int height;
+        Size(int w, int h) : width(w), height(h){}
+    };
+
+    /**
+     * Helper function to get the largest Jpeg resolution (in area)
+     * Return Size(0, 0) if static metatdata is invalid
+     */
+    Size getMaxJpegResolution() const;
+
     /**
      * Get Jpeg buffer size for a given jpeg resolution.
      * Negative values are error codes.