Camera: Bump device version to 3.4

Camera devices supporting version 3.4 will be able to receive
session parameters during the stream configuration phase.

Bug: 64450664
Test: Camera CTS
run commandAndExit vts --skip-all-system-status-check
--skip-preconditions --primary-abi-only --module
VtsHalCameraProviderV2_4Target -l INFO

Change-Id: Ifd83bfe0e512fe75b63602b4aba98f4cc1cdeb53
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index d6a04bc..631404e 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -803,6 +803,89 @@
    return dataSpace;
 }
 
+bool CameraDeviceSession::preProcessConfigurationLocked(
+        const StreamConfiguration& requestedConfiguration,
+        camera3_stream_configuration_t *stream_list /*out*/,
+        hidl_vec<camera3_stream_t*> *streams /*out*/) {
+
+    if ((stream_list == nullptr) || (streams == nullptr)) {
+        return false;
+    }
+
+    stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode;
+    stream_list->num_streams = requestedConfiguration.streams.size();
+    streams->resize(stream_list->num_streams);
+    stream_list->streams = streams->data();
+
+    for (uint32_t i = 0; i < stream_list->num_streams; i++) {
+        int id = requestedConfiguration.streams[i].id;
+
+        if (mStreamMap.count(id) == 0) {
+            Camera3Stream stream;
+            convertFromHidl(requestedConfiguration.streams[i], &stream);
+            mStreamMap[id] = stream;
+            mStreamMap[id].data_space = mapToLegacyDataspace(
+                    mStreamMap[id].data_space);
+            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+        } else {
+            // width/height/format must not change, but usage/rotation might need to change
+            if (mStreamMap[id].stream_type !=
+                    (int) requestedConfiguration.streams[i].streamType ||
+                    mStreamMap[id].width != requestedConfiguration.streams[i].width ||
+                    mStreamMap[id].height != requestedConfiguration.streams[i].height ||
+                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
+                    mStreamMap[id].data_space !=
+                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
+                                    requestedConfiguration.streams[i].dataSpace))) {
+                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+                return false;
+            }
+            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
+            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
+        }
+        (*streams)[i] = &mStreamMap[id];
+    }
+
+    return true;
+}
+
+void CameraDeviceSession::postProcessConfigurationLocked(
+        const StreamConfiguration& requestedConfiguration) {
+    // delete unused streams, note we do this after adding new streams to ensure new stream
+    // will not have the same address as deleted stream, and HAL has a chance to reference
+    // the to be deleted stream in configure_streams call
+    for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+        int id = it->first;
+        bool found = false;
+        for (const auto& stream : requestedConfiguration.streams) {
+            if (id == stream.id) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // Unmap all buffers of deleted stream
+            // in case the configuration call succeeds and HAL
+            // is able to release the corresponding resources too.
+            cleanupBuffersLocked(id);
+            it = mStreamMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    // Track video streams
+    mVideoStreamIds.clear();
+    for (const auto& stream : requestedConfiguration.streams) {
+        if (stream.streamType == StreamType::OUTPUT &&
+            stream.usage &
+                graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
+            mVideoStreamIds.push_back(stream.id);
+        }
+    }
+    mResultBatcher.setBatchedStreams(mVideoStreamIds);
+}
+
 Return<void> CameraDeviceSession::configureStreams(
         const StreamConfiguration& requestedConfiguration,
         ICameraDeviceSession::configureStreams_cb _hidl_cb)  {
@@ -840,42 +923,11 @@
         return Void();
     }
 
-    camera3_stream_configuration_t stream_list;
+    camera3_stream_configuration_t stream_list{};
     hidl_vec<camera3_stream_t*> streams;
-
-    stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
-    stream_list.num_streams = requestedConfiguration.streams.size();
-    streams.resize(stream_list.num_streams);
-    stream_list.streams = streams.data();
-
-    for (uint32_t i = 0; i < stream_list.num_streams; i++) {
-        int id = requestedConfiguration.streams[i].id;
-
-        if (mStreamMap.count(id) == 0) {
-            Camera3Stream stream;
-            convertFromHidl(requestedConfiguration.streams[i], &stream);
-            mStreamMap[id] = stream;
-            mStreamMap[id].data_space = mapToLegacyDataspace(
-                    mStreamMap[id].data_space);
-            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
-        } else {
-            // width/height/format must not change, but usage/rotation might need to change
-            if (mStreamMap[id].stream_type !=
-                    (int) requestedConfiguration.streams[i].streamType ||
-                    mStreamMap[id].width != requestedConfiguration.streams[i].width ||
-                    mStreamMap[id].height != requestedConfiguration.streams[i].height ||
-                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
-                    mStreamMap[id].data_space !=
-                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
-                                    requestedConfiguration.streams[i].dataSpace))) {
-                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
-                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-                return Void();
-            }
-            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
-            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
-        }
-        streams[i] = &mStreamMap[id];
+    if (!preProcessConfigurationLocked(requestedConfiguration, &stream_list, &streams)) {
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
     }
 
     ATRACE_BEGIN("camera3->configure_streams");
@@ -885,39 +937,7 @@
     // In case Hal returns error most likely it was not able to release
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
-        // delete unused streams, note we do this after adding new streams to ensure new stream
-        // will not have the same address as deleted stream, and HAL has a chance to reference
-        // the to be deleted stream in configure_streams call
-        for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
-            int id = it->first;
-            bool found = false;
-            for (const auto& stream : requestedConfiguration.streams) {
-                if (id == stream.id) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                // Unmap all buffers of deleted stream
-                // in case the configuration call succeeds and HAL
-                // is able to release the corresponding resources too.
-                cleanupBuffersLocked(id);
-                it = mStreamMap.erase(it);
-            } else {
-                ++it;
-            }
-        }
-
-        // Track video streams
-        mVideoStreamIds.clear();
-        for (const auto& stream : requestedConfiguration.streams) {
-            if (stream.streamType == StreamType::OUTPUT &&
-                stream.usage &
-                    graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
-                mVideoStreamIds.push_back(stream.id);
-            }
-        }
-        mResultBatcher.setBatchedStreams(mVideoStreamIds);
+        postProcessConfigurationLocked(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index 69e2e2c..c5a63c8 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -112,6 +112,12 @@
     Return<Status> flush();
     Return<void> close();
 
+    //Helper methods
+    bool preProcessConfigurationLocked(const StreamConfiguration& requestedConfiguration,
+            camera3_stream_configuration_t *stream_list /*out*/,
+            hidl_vec<camera3_stream_t*> *streams /*out*/);
+    void postProcessConfigurationLocked(const StreamConfiguration& requestedConfiguration);
+
 protected:
 
     // protecting mClosed/mDisconnected/mInitFail
diff --git a/camera/device/3.3/default/CameraDeviceSession.cpp b/camera/device/3.3/default/CameraDeviceSession.cpp
index f877895..d36e9ed 100644
--- a/camera/device/3.3/default/CameraDeviceSession.cpp
+++ b/camera/device/3.3/default/CameraDeviceSession.cpp
@@ -77,42 +77,11 @@
         return Void();
     }
 
-    camera3_stream_configuration_t stream_list;
+    camera3_stream_configuration_t stream_list{};
     hidl_vec<camera3_stream_t*> streams;
-
-    stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
-    stream_list.num_streams = requestedConfiguration.streams.size();
-    streams.resize(stream_list.num_streams);
-    stream_list.streams = streams.data();
-
-    for (uint32_t i = 0; i < stream_list.num_streams; i++) {
-        int id = requestedConfiguration.streams[i].id;
-
-        if (mStreamMap.count(id) == 0) {
-            Camera3Stream stream;
-            V3_2::implementation::convertFromHidl(requestedConfiguration.streams[i], &stream);
-            mStreamMap[id] = stream;
-            mStreamMap[id].data_space = mapToLegacyDataspace(
-                    mStreamMap[id].data_space);
-            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
-        } else {
-            // width/height/format must not change, but usage/rotation might need to change
-            if (mStreamMap[id].stream_type !=
-                    (int) requestedConfiguration.streams[i].streamType ||
-                    mStreamMap[id].width != requestedConfiguration.streams[i].width ||
-                    mStreamMap[id].height != requestedConfiguration.streams[i].height ||
-                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
-                    mStreamMap[id].data_space !=
-                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
-                                    requestedConfiguration.streams[i].dataSpace))) {
-                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
-                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-                return Void();
-            }
-            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
-            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
-        }
-        streams[i] = &mStreamMap[id];
+    if (!preProcessConfigurationLocked(requestedConfiguration, &stream_list, &streams)) {
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
     }
 
     ATRACE_BEGIN("camera3->configure_streams");
@@ -122,39 +91,7 @@
     // In case Hal returns error most likely it was not able to release
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
-        // delete unused streams, note we do this after adding new streams to ensure new stream
-        // will not have the same address as deleted stream, and HAL has a chance to reference
-        // the to be deleted stream in configure_streams call
-        for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
-            int id = it->first;
-            bool found = false;
-            for (const auto& stream : requestedConfiguration.streams) {
-                if (id == stream.id) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                // Unmap all buffers of deleted stream
-                // in case the configuration call succeeds and HAL
-                // is able to release the corresponding resources too.
-                cleanupBuffersLocked(id);
-                it = mStreamMap.erase(it);
-            } else {
-                ++it;
-            }
-        }
-
-        // Track video streams
-        mVideoStreamIds.clear();
-        for (const auto& stream : requestedConfiguration.streams) {
-            if (stream.streamType == V3_2::StreamType::OUTPUT &&
-                stream.usage &
-                    graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
-                mVideoStreamIds.push_back(stream.id);
-            }
-        }
-        mResultBatcher.setBatchedStreams(mVideoStreamIds);
+        postProcessConfigurationLocked(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
new file mode 100644
index 0000000..2523fa8
--- /dev/null
+++ b/camera/device/3.4/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.device@3.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICameraDeviceSession.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.graphics.common@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "StreamConfiguration",
+    ],
+    gen_java: false,
+}
+
diff --git a/camera/device/3.4/ICameraDeviceSession.hal b/camera/device/3.4/ICameraDeviceSession.hal
new file mode 100644
index 0000000..e5693b2
--- /dev/null
+++ b/camera/device/3.4/ICameraDeviceSession.hal
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.hardware.camera.device@3.4;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.3::ICameraDeviceSession;
+import @3.3::HalStreamConfiguration;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.3::ICameraDeviceSession {
+
+    /**
+     * configureStreams_3_4:
+     *
+     * Identical to @3.3::ICameraDeviceSession.configureStreams, except that:
+     *
+     * - The requested configuration includes session parameters.
+     *
+     * @return Status Status code for the operation, one of:
+     *     OK:
+     *          On successful stream configuration.
+     *     INTERNAL_ERROR:
+     *         If there has been a fatal error and the device is no longer
+     *         operational. Only close() can be called successfully by the
+     *         framework after this error is returned.
+     *     ILLEGAL_ARGUMENT:
+     *         If the requested stream configuration is invalid. Some examples
+     *         of invalid stream configurations include:
+     *           - Including more than 1 INPUT stream
+     *           - Not including any OUTPUT streams
+     *           - Including streams with unsupported formats, or an unsupported
+     *             size for that format.
+     *           - Including too many output streams of a certain format.
+     *           - Unsupported rotation configuration
+     *           - Stream sizes/formats don't satisfy the
+     *             camera3_stream_configuration_t->operation_mode requirements
+     *             for non-NORMAL mode, or the requested operation_mode is not
+     *             supported by the HAL.
+     *           - Unsupported usage flag
+     *         The camera service cannot filter out all possible illegal stream
+     *         configurations, since some devices may support more simultaneous
+     *         streams or larger stream resolutions than the minimum required
+     *         for a given camera device hardware level. The HAL must return an
+     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+     *         ready to accept a future valid stream configuration in a later
+     *         configureStreams call.
+     * @return halConfiguration The stream parameters desired by the HAL for
+     *     each stream, including maximum buffers, the usage flags, and the
+     *     override format.
+     */
+    configureStreams_3_4(@3.4::StreamConfiguration requestedConfiguration)
+            generates (Status status,
+                       @3.3::HalStreamConfiguration halConfiguration);
+
+};
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
new file mode 100644
index 0000000..c0ce838
--- /dev/null
+++ b/camera/device/3.4/default/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_library_headers {
+    name: "camera.device@3.4-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/device_v3_4_impl"],
+}
+
+cc_library_shared {
+    name: "camera.device@3.4-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "CameraDevice.cpp",
+        "CameraDeviceSession.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/device_v3_4_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
diff --git a/camera/device/3.4/default/CameraDevice.cpp b/camera/device/3.4/default/CameraDevice.cpp
new file mode 100644
index 0000000..d73833a
--- /dev/null
+++ b/camera/device/3.4/default/CameraDevice.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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 "CamDev@3.4-impl"
+#include <log/log.h>
+
+#include <utils/Vector.h>
+#include <utils/Trace.h>
+#include "CameraDevice_3_4.h"
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::Status;
+using namespace ::android::hardware::camera::device;
+
+CameraDevice::CameraDevice(
+    sp<CameraModule> module, const std::string& cameraId,
+    const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+        V3_2::implementation::CameraDevice(module, cameraId, cameraDeviceNames) {
+}
+
+CameraDevice::~CameraDevice() {
+}
+
+sp<V3_2::implementation::CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device,
+        const camera_metadata_t* deviceInfo,
+        const sp<V3_2::ICameraDeviceCallback>& callback) {
+    sp<CameraDeviceSession> session = new CameraDeviceSession(device, deviceInfo, callback);
+    IF_ALOGV() {
+        session->getInterface()->interfaceChain([](
+            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                ALOGV("Session interface chain:");
+                for (auto iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
+    return session;
+}
+
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..0ae470f
--- /dev/null
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 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 "CamDevSession@3.4-impl"
+#include <android/log.h>
+
+#include <set>
+#include <utils/Trace.h>
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include "CameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+CameraDeviceSession::CameraDeviceSession(
+    camera3_device_t* device,
+    const camera_metadata_t* deviceInfo,
+    const sp<V3_2::ICameraDeviceCallback>& callback) :
+        V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) {
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+}
+
+Return<void> CameraDeviceSession::configureStreams_3_4(
+        const V3_4::StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb)  {
+    Status status = initStatus();
+    HalStreamConfiguration outStreams;
+
+    // hold the inflight lock for entire configureStreams scope since there must not be any
+    // inflight request/results during stream configuration.
+    Mutex::Autolock _l(mInflightLock);
+    if (!mInflightBuffers.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
+                __FUNCTION__, mInflightBuffers.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    if (!mInflightAETriggerOverrides.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight"
+                " trigger overrides!", __FUNCTION__,
+                mInflightAETriggerOverrides.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    if (!mInflightRawBoostPresent.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight"
+                " boost overrides!", __FUNCTION__,
+                mInflightRawBoostPresent.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    if (status != Status::OK) {
+        _hidl_cb(status, outStreams);
+        return Void();
+    }
+
+    const camera_metadata_t *paramBuffer = nullptr;
+    if (0 < requestedConfiguration.sessionParams.size()) {
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
+        V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, &paramBuffer);
+    }
+
+    camera3_stream_configuration_t stream_list{};
+    hidl_vec<camera3_stream_t*> streams;
+    stream_list.session_parameters = paramBuffer;
+    if (!preProcessConfigurationLocked(requestedConfiguration.v3_2, &stream_list, &streams)) {
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    ATRACE_BEGIN("camera3->configure_streams");
+    status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
+    ATRACE_END();
+
+    // In case Hal returns error most likely it was not able to release
+    // the corresponding resources of the deleted streams.
+    if (ret == OK) {
+        postProcessConfigurationLocked(requestedConfiguration.v3_2);
+    }
+
+    if (ret == -EINVAL) {
+        status = Status::ILLEGAL_ARGUMENT;
+    } else if (ret != OK) {
+        status = Status::INTERNAL_ERROR;
+    } else {
+        V3_3::implementation::convertToHidl(stream_list, &outStreams);
+        mFirstRequest = true;
+    }
+
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+} // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/OWNERS b/camera/device/3.4/default/OWNERS
new file mode 100644
index 0000000..18acfee
--- /dev/null
+++ b/camera/device/3.4/default/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
new file mode 100644
index 0000000..bff1734
--- /dev/null
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 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_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <../../3.3/default/CameraDeviceSession.h>
+#include <../../3.3/default/include/convert.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <deque>
+#include <map>
+#include <unordered_map>
+#include "CameraMetadata.h"
+#include "HandleImporter.h"
+#include "hardware/camera3.h"
+#include "hardware/camera_common.h"
+#include "utils/Mutex.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::StreamConfiguration;
+using ::android::hardware::camera::device::V3_3::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraDeviceSession : public V3_3::implementation::CameraDeviceSession {
+
+    CameraDeviceSession(camera3_device_t*,
+            const camera_metadata_t* deviceInfo,
+            const sp<V3_2::ICameraDeviceCallback>&);
+    virtual ~CameraDeviceSession();
+
+    virtual sp<V3_2::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_4(this);
+    }
+
+protected:
+    // Methods from v3.3 and earlier will trampoline to inherited implementation
+
+    // New methods for v3.4
+
+    Return<void> configureStreams_3_4(
+            const V3_4::StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb);
+private:
+
+    struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_4(sp<CameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                V3_2::RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+    private:
+        sp<CameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h
new file mode 100644
index 0000000..95ee20e
--- /dev/null
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraModule.h"
+#include "CameraMetadata.h"
+#include "CameraDeviceSession.h"
+#include <../../3.2/default/CameraDevice_3_2.h>
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct CameraDevice : public V3_2::implementation::CameraDevice {
+
+    // Called by provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    // Delegates nearly all work to CameraDevice_3_2
+    CameraDevice(sp<CameraModule> module,
+                 const std::string& cameraId,
+                 const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+    ~CameraDevice();
+
+protected:
+    virtual sp<V3_2::implementation::CameraDeviceSession> createSession(camera3_device_t*,
+            const camera_metadata_t* deviceInfo,
+            const sp<V3_2::ICameraDeviceCallback>&) override;
+
+};
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE_H
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
new file mode 100644
index 0000000..c822717
--- /dev/null
+++ b/camera/device/3.4/types.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.hardware.camera.device@3.4;
+
+import @3.2::StreamConfiguration;
+import @3.2::types;
+
+/**
+ * StreamConfiguration:
+ *
+ * Identical to @3.2::StreamConfiguration, except that it contains session parameters.
+ */
+struct StreamConfiguration {
+    /**
+     * The definition of StreamConfiguration from the prior version.
+     */
+    @3.2::StreamConfiguration v3_2;
+
+    /**
+     * Session wide camera parameters.
+     *
+     * The session parameters contain the initial values of any request keys that were
+     * made available via ANDROID_REQUEST_AVAILABLE_SESSION_KEYS. The Hal implementation
+     * can advertise any settings that can potentially introduce unexpected delays when
+     * their value changes during active process requests. Typical examples are
+     * parameters that trigger time-consuming HW re-configurations or internal camera
+     * pipeline updates. The field is optional, clients can choose to ignore it and avoid
+     * including any initial settings. If parameters are present, then hal must examine
+     * their values and configure the internal camera pipeline accordingly.
+     */
+    CameraMetadata sessionParams;
+};
diff --git a/camera/device/README.md b/camera/device/README.md
index 9f60781..3709cb8 100644
--- a/camera/device/README.md
+++ b/camera/device/README.md
@@ -87,3 +87,11 @@
     supported in the legacy camera HAL.
 
 Added in Android 8.1.
+
+### ICameraDevice.hal@3.4:
+
+A minor revision to the ICameraDevice.hal@3.3.
+
+  - Adds support for session parameters during stream configuration.
+
+Added in Android 9
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index c0b3591..99c3e92 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -12,9 +12,11 @@
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
         "camera.device@1.0-impl",
         "camera.device@3.2-impl",
         "camera.device@3.3-impl",
+        "camera.device@3.4-impl",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
         "android.hardware.graphics.mapper@2.0",
@@ -22,11 +24,14 @@
         "android.hidl.memory@1.0",
         "liblog",
         "libhardware",
-        "libcamera_metadata"
+        "libcamera_metadata",
+    ],
+    header_libs: [
+        "camera.device@3.4-impl_headers",
     ],
     static_libs: [
-        "android.hardware.camera.common@1.0-helper"
-    ]
+        "android.hardware.camera.common@1.0-helper",
+    ],
 }
 
 cc_binary {
@@ -46,6 +51,7 @@
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
     ],
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index d50168a..ed974a5 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -21,6 +21,7 @@
 #include "CameraProvider.h"
 #include "CameraDevice_1_0.h"
 #include "CameraDevice_3_3.h"
+#include "CameraDevice_3_4.h"
 #include <cutils/properties.h>
 #include <string.h>
 #include <utils/Trace.h>
@@ -39,6 +40,7 @@
 const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
 const char *kHAL3_2 = "3.2";
 const char *kHAL3_3 = "3.3";
+const char *kHAL3_4 = "3.4";
 const char *kHAL1_0 = "1.0";
 const int kMaxCameraDeviceNameLen = 128;
 const int kMaxCameraIdLen = 16;
@@ -159,12 +161,16 @@
     if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 &&
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 &&
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 &&
-            deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) {
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 &&
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_5) {
         return hidl_string("");
     }
     bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0;
     int versionMajor = isV1 ? 1 : 3;
     int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion;
+    if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+        versionMinor = 4;
+    }
     char deviceName[kMaxCameraDeviceNameLen];
     snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s",
             versionMajor, versionMinor, cameraId.c_str());
@@ -220,7 +226,8 @@
             break;
         default:
             ALOGW("Unknown minor camera device HAL version %d in property "
-                    "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3", mPreferredHal3MinorVersion);
+                    "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3",
+                    mPreferredHal3MinorVersion);
             mPreferredHal3MinorVersion = 3;
     }
 
@@ -292,6 +299,7 @@
             case CAMERA_DEVICE_API_VERSION_3_2:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_4:
+            case CAMERA_DEVICE_API_VERSION_3_5:
                 // in support
                 break;
             case CAMERA_DEVICE_API_VERSION_2_0:
@@ -480,10 +488,27 @@
         return Void();
     }
 
+    sp<android::hardware::camera::device::V3_2::ICameraDevice> device;
+    if (deviceVersion == kHAL3_4) {
+        ALOGV("Constructing v3.4 camera device");
+        sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
+            new android::hardware::camera::device::V3_4::implementation::CameraDevice(
+                    mModule, cameraId, mCameraDeviceNames);
+        if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+            ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+            device = nullptr;
+            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+            return Void();
+        }
+
+        device = deviceImpl;
+        _hidl_cb (Status::OK, device);
+        return Void();
+    }
+
     // Since some Treble HAL revisions can map to the same legacy HAL version(s), we default
     // to the newest possible Treble HAL revision, but allow for override if needed via
     // system property.
-    sp<android::hardware::camera::device::V3_2::ICameraDevice> device;
     switch (mPreferredHal3MinorVersion) {
         case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2
             ALOGV("Constructing v3.2 camera device");
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 81d3de1..7bc4253 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -35,6 +35,7 @@
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.mapper@2.0",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index e4cf9af..c8926c4 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -27,6 +27,7 @@
 #include <android/hardware/camera/device/1.0/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
@@ -128,9 +129,11 @@
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_4 = "3.4";
     const char *kHAL3_3 = "3.3";
     const char *kHAL3_2 = "3.2";
     const char *kHAL1_0 = "1.0";
@@ -164,7 +167,9 @@
             return -1;
         }
 
-        if (version.compare(kHAL3_3) == 0) {
+        if (version.compare(kHAL3_4) == 0) {
+            return CAMERA_DEVICE_API_VERSION_3_4;
+        } else if (version.compare(kHAL3_3) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_3;
         } else if (version.compare(kHAL3_2) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_2;
@@ -611,9 +616,11 @@
     void openEmptyDeviceSession(const std::string &name,
             sp<ICameraProvider> provider,
             sp<ICameraDeviceSession> *session /*out*/,
-            sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
             camera_metadata_t **staticMeta /*out*/);
-    void configurePreviewStream(const std::string &name,
+    void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
+            sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
+            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/);
+    void configurePreviewStream(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
             sp<ICameraDeviceSession> *session /*out*/,
@@ -1100,6 +1107,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 Return<void> ret;
@@ -1140,6 +1148,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -1879,6 +1888,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -1943,6 +1953,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -2067,6 +2078,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<ICameraDevice> device3_x;
@@ -2130,6 +2142,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -2152,12 +2165,14 @@
                     session = newSession;
                 });
                 ASSERT_TRUE(ret.isOk());
-                // Ensure that a device labeling itself as 3.3 can have its session interface cast
-                // to the 3.3 interface, and that lower versions can't be cast to it.
-                auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session);
-                ASSERT_TRUE(castResult.isOk());
-                sp<device::V3_3::ICameraDeviceSession> sessionV3_3 = castResult;
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
+                // Ensure that a device labeling itself as 3.3/3.4 can have its session interface
+                // cast the 3.3/3.4 interface, and that lower versions can't be cast to it.
+                sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
+                sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
+                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4);
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
+                    ASSERT_TRUE(sessionV3_4.get() != nullptr);
+                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
                     ASSERT_TRUE(sessionV3_3.get() != nullptr);
                 } else {
                     ASSERT_TRUE(sessionV3_3.get() == nullptr);
@@ -2213,6 +2228,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -2301,66 +2317,69 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
-
-                outputStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
-                ASSERT_NE(0u, outputStreams.size());
-
-                int32_t streamId = 0;
-                for (auto& it : outputStreams) {
-                    Stream stream = {streamId,
-                                     StreamType::OUTPUT,
-                                     static_cast<uint32_t>(it.width),
-                                     static_cast<uint32_t>(it.height),
-                                     static_cast<PixelFormat>(it.format),
-                                     GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                     0,
-                                     StreamRotation::ROTATION_0};
-                    ::android::hardware::hidl_vec<Stream> streams = {stream};
-                    StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                    if (session3_3 == nullptr) {
-                        ret = session->configureStreams(config,
-                                [streamId](Status s, HalStreamConfiguration halConfig) {
-                                    ASSERT_EQ(Status::OK, s);
-                                    ASSERT_EQ(1u, halConfig.streams.size());
-                                    ASSERT_EQ(halConfig.streams[0].id, streamId);
-                                });
-                    } else {
-                        ret = session3_3->configureStreams_3_3(config,
-                                [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                    ASSERT_EQ(Status::OK, s);
-                                    ASSERT_EQ(1u, halConfig.streams.size());
-                                    ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
-                                });
-                    }
-                    ASSERT_TRUE(ret.isOk());
-                    streamId++;
-                }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider,
+                &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t streamId = 0;
+        for (auto& it : outputStreams) {
+            Stream stream = {streamId,
+                             StreamType::OUTPUT,
+                             static_cast<uint32_t>(it.width),
+                             static_cast<uint32_t>(it.height),
+                             static_cast<PixelFormat>(it.format),
+                             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                             0,
+                             StreamRotation::ROTATION_0};
+            ::android::hardware::hidl_vec<Stream> streams = {stream};
+            ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+            config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+            if (session3_4 != nullptr) {
+                ret = session3_4->configureStreams_3_4(config,
+                        [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                        });
+            } else if (session3_3 != nullptr) {
+                ret = session3_3->configureStreams_3_3(config.v3_2,
+                        [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                        });
+            } else {
+                ret = session->configureStreams(config.v3_2,
+                        [streamId](Status s, HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].id, streamId);
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+            streamId++;
+        }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2371,132 +2390,148 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
-
-                outputStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
-                ASSERT_NE(0u, outputStreams.size());
-
-                int32_t streamId = 0;
-                Stream stream = {streamId++,
-                                 StreamType::OUTPUT,
-                                 static_cast<uint32_t>(0),
-                                 static_cast<uint32_t>(0),
-                                 static_cast<PixelFormat>(outputStreams[0].format),
-                                 GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                 0,
-                                 StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {stream};
-                StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                if(session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                        [](Status s, HalStreamConfiguration) {
-                            ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                    (Status::INTERNAL_ERROR == s));
-                        });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                        [](Status s, device::V3_3::HalStreamConfiguration) {
-                            ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                    (Status::INTERNAL_ERROR == s));
-                        });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<PixelFormat>(outputStreams[0].format),
-                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                if(session3_3 == nullptr) {
-                    ret = session->configureStreams(config, [](Status s,
-                                HalStreamConfiguration) {
-                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                        });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config, [](Status s,
-                                device::V3_3::HalStreamConfiguration) {
-                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                        });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                for (auto& it : outputStreams) {
-                    stream = {streamId++,
-                              StreamType::OUTPUT,
-                              static_cast<uint32_t>(it.width),
-                              static_cast<uint32_t>(it.height),
-                              static_cast<PixelFormat>(UINT32_MAX),
-                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                              0,
-                              StreamRotation::ROTATION_0};
-                    streams[0] = stream;
-                    config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                    if(session3_3 == nullptr) {
-                        ret = session->configureStreams(config,
-                                [](Status s, HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    } else {
-                        ret = session3_3->configureStreams_3_3(config,
-                                [](Status s, device::V3_3::HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    }
-                    ASSERT_TRUE(ret.isOk());
-
-                    stream = {streamId++,
-                              StreamType::OUTPUT,
-                              static_cast<uint32_t>(it.width),
-                              static_cast<uint32_t>(it.height),
-                              static_cast<PixelFormat>(it.format),
-                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                              0,
-                              static_cast<StreamRotation>(UINT32_MAX)};
-                    streams[0] = stream;
-                    config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                    if(session3_3 == nullptr) {
-                        ret = session->configureStreams(config,
-                                [](Status s, HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    } else {
-                        ret = session3_3->configureStreams_3_3(config,
-                                [](Status s, device::V3_3::HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    }
-                    ASSERT_TRUE(ret.isOk());
-                }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t streamId = 0;
+        Stream stream = {streamId++,
+                         StreamType::OUTPUT,
+                         static_cast<uint32_t>(0),
+                         static_cast<uint32_t>(0),
+                         static_cast<PixelFormat>(outputStreams[0].format),
+                         GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                         0,
+                         StreamRotation::ROTATION_0};
+        ::android::hardware::hidl_vec<Stream> streams = {stream};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+        config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+        if(session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config,
+                [](Status s, device::V3_3::HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                            (Status::INTERNAL_ERROR == s));
+                });
+        } else if(session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config.v3_2,
+                [](Status s, device::V3_3::HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                            (Status::INTERNAL_ERROR == s));
+                });
+        } else {
+            ret = session->configureStreams(config.v3_2,
+                [](Status s, HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                            (Status::INTERNAL_ERROR == s));
+                });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<PixelFormat>(outputStreams[0].format),
+                  GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+        if(session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config, [](Status s,
+                        device::V3_3::HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        } else if(session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config.v3_2, [](Status s,
+                        device::V3_3::HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        } else {
+            ret = session->configureStreams(config.v3_2, [](Status s,
+                        HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        for (auto& it : outputStreams) {
+            stream = {streamId++,
+                      StreamType::OUTPUT,
+                      static_cast<uint32_t>(it.width),
+                      static_cast<uint32_t>(it.height),
+                      static_cast<PixelFormat>(UINT32_MAX),
+                      GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                      0,
+                      StreamRotation::ROTATION_0};
+            streams[0] = stream;
+            config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+            if(session3_4 != nullptr) {
+                ret = session3_4->configureStreams_3_4(config,
+                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else if(session3_3 != nullptr) {
+                ret = session3_3->configureStreams_3_3(config.v3_2,
+                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else {
+                ret = session->configureStreams(config.v3_2,
+                        [](Status s, HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+
+            stream = {streamId++,
+                      StreamType::OUTPUT,
+                      static_cast<uint32_t>(it.width),
+                      static_cast<uint32_t>(it.height),
+                      static_cast<PixelFormat>(it.format),
+                      GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                      0,
+                      static_cast<StreamRotation>(UINT32_MAX)};
+            streams[0] = stream;
+            config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+            if(session3_4 != nullptr) {
+                ret = session3_4->configureStreams_3_4(config,
+                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else if(session3_3 != nullptr) {
+                ret = session3_3->configureStreams_3_3(config.v3_2,
+                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else {
+                ret = session->configureStreams(config.v3_2,
+                        [](Status s, HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+        }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2509,107 +2544,207 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                Status rc = isZSLModeAvailable(staticMeta);
-                if (Status::METHOD_NOT_SUPPORTED == rc) {
-                    ret = session->close();
-                    ASSERT_TRUE(ret.isOk());
-                    continue;
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        Status rc = isZSLModeAvailable(staticMeta);
+        if (Status::METHOD_NOT_SUPPORTED == rc) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        inputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, inputStreams));
+        ASSERT_NE(0u, inputStreams.size());
+
+        inputOutputMap.clear();
+        ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
+        ASSERT_NE(0u, inputOutputMap.size());
+
+        int32_t streamId = 0;
+        for (auto& inputIter : inputOutputMap) {
+            AvailableStream input;
+            ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat,
+                    input));
+            ASSERT_NE(0u, inputStreams.size());
+
+            AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
+                                               inputIter.outputFormat};
+            std::vector<AvailableStream> outputStreams;
+            ASSERT_EQ(Status::OK,
+                      getAvailableOutputStreams(staticMeta, outputStreams,
+                              &outputThreshold));
+            for (auto& outputIter : outputStreams) {
+                Stream zslStream = {streamId++,
+                                    StreamType::OUTPUT,
+                                    static_cast<uint32_t>(input.width),
+                                    static_cast<uint32_t>(input.height),
+                                    static_cast<PixelFormat>(input.format),
+                                    GRALLOC_USAGE_HW_CAMERA_ZSL,
+                                    0,
+                                    StreamRotation::ROTATION_0};
+                Stream inputStream = {streamId++,
+                                      StreamType::INPUT,
+                                      static_cast<uint32_t>(input.width),
+                                      static_cast<uint32_t>(input.height),
+                                      static_cast<PixelFormat>(input.format),
+                                      0,
+                                      0,
+                                      StreamRotation::ROTATION_0};
+                Stream outputStream = {streamId++,
+                                       StreamType::OUTPUT,
+                                       static_cast<uint32_t>(outputIter.width),
+                                       static_cast<uint32_t>(outputIter.height),
+                                       static_cast<PixelFormat>(outputIter.format),
+                                       GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                                       0,
+                                       StreamRotation::ROTATION_0};
+
+                ::android::hardware::hidl_vec<Stream> streams = {inputStream, zslStream,
+                                                                 outputStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+                config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+                if (session3_4 != nullptr) {
+                    ret = session3_4->configureStreams_3_4(config,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
+                } else if (session3_3 != nullptr) {
+                    ret = session3_3->configureStreams_3_3(config.v3_2,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
+                } else {
+                    ret = session->configureStreams(config.v3_2,
+                            [](Status s, HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
                 }
-                ASSERT_EQ(Status::OK, rc);
-
-                inputStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, inputStreams));
-                ASSERT_NE(0u, inputStreams.size());
-
-                inputOutputMap.clear();
-                ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
-                ASSERT_NE(0u, inputOutputMap.size());
-
-                int32_t streamId = 0;
-                for (auto& inputIter : inputOutputMap) {
-                    AvailableStream input;
-                    ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat,
-                            input));
-                    ASSERT_NE(0u, inputStreams.size());
-
-                    AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
-                                                       inputIter.outputFormat};
-                    std::vector<AvailableStream> outputStreams;
-                    ASSERT_EQ(Status::OK,
-                              getAvailableOutputStreams(staticMeta, outputStreams,
-                                      &outputThreshold));
-                    for (auto& outputIter : outputStreams) {
-                        Stream zslStream = {streamId++,
-                                            StreamType::OUTPUT,
-                                            static_cast<uint32_t>(input.width),
-                                            static_cast<uint32_t>(input.height),
-                                            static_cast<PixelFormat>(input.format),
-                                            GRALLOC_USAGE_HW_CAMERA_ZSL,
-                                            0,
-                                            StreamRotation::ROTATION_0};
-                        Stream inputStream = {streamId++,
-                                              StreamType::INPUT,
-                                              static_cast<uint32_t>(input.width),
-                                              static_cast<uint32_t>(input.height),
-                                              static_cast<PixelFormat>(input.format),
-                                              0,
-                                              0,
-                                              StreamRotation::ROTATION_0};
-                        Stream outputStream = {streamId++,
-                                               StreamType::OUTPUT,
-                                               static_cast<uint32_t>(outputIter.width),
-                                               static_cast<uint32_t>(outputIter.height),
-                                               static_cast<PixelFormat>(outputIter.format),
-                                               GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                               0,
-                                               StreamRotation::ROTATION_0};
-
-                        ::android::hardware::hidl_vec<Stream> streams = {inputStream, zslStream,
-                                                                         outputStream};
-                        StreamConfiguration config = {streams,
-                                                      StreamConfigurationMode::NORMAL_MODE};
-                        if (session3_3 == nullptr) {
-                            ret = session->configureStreams(config,
-                                    [](Status s, HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(3u, halConfig.streams.size());
-                                    });
-                        } else {
-                            ret = session3_3->configureStreams_3_3(config,
-                                    [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(3u, halConfig.streams.size());
-                                    });
-                        }
-                        ASSERT_TRUE(ret.isOk());
-                    }
-                }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
         }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check wehether session parameters are supported. If Hal support for them
+// exist, then try to configure a preview stream using them.
+TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        } else if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+            continue;
+        }
+
+        camera_metadata_t* staticMetaBuffer;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+        ASSERT_NE(session3_4, nullptr);
+
+        const android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+                staticMetaBuffer);
+        camera_metadata_ro_entry availableSessionKeys = staticMeta.find(
+                ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
+        if (availableSessionKeys.count == 0) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings;
+        ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW,
+                [&previewRequestSettings] (auto status, const auto& req) mutable {
+                    ASSERT_EQ(Status::OK, status);
+
+                    const camera_metadata_t *metadata = reinterpret_cast<const camera_metadata_t*> (
+                            req.data());
+                    size_t expectedSize = req.size();
+                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+                    size_t entryCount = get_camera_metadata_entry_count(metadata);
+                    ASSERT_GT(entryCount, 0u);
+                    previewRequestSettings = metadata;
+                    });
+        ASSERT_TRUE(ret.isOk());
+        const android::hardware::camera::common::V1_0::helper::CameraMetadata &constSettings =
+            previewRequestSettings;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
+        for (size_t i = 0; i < availableSessionKeys.count; i++) {
+            camera_metadata_ro_entry entry = constSettings.find(availableSessionKeys.data.i32[i]);
+            if (entry.count > 0) {
+                sessionParams.update(entry);
+            }
+        }
+        if (sessionParams.isEmpty()) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputPreviewStreams,
+                &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        Stream previewStream = {0,
+                                StreamType::OUTPUT,
+                                static_cast<uint32_t>(outputPreviewStreams[0].width),
+                                static_cast<uint32_t>(outputPreviewStreams[0].height),
+                                static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                                GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                                0,
+                                StreamRotation::ROTATION_0};
+        ::android::hardware::hidl_vec<Stream> streams = {previewStream};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+        config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+        const camera_metadata_t *sessionParamsBuffer = sessionParams.getAndLock();
+        config.sessionParams.setToExternal(
+                reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (sessionParamsBuffer)),
+                get_camera_metadata_size(sessionParamsBuffer));
+        ret = session3_4->configureStreams_3_4(config,
+                [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                });
+        ASSERT_TRUE(ret.isOk());
+
+        sessionParams.unlock(sessionParamsBuffer);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2626,82 +2761,82 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                outputBlobStreams.clear();
-                ASSERT_EQ(Status::OK,
-                          getAvailableOutputStreams(staticMeta, outputBlobStreams,
-                                  &blobThreshold));
-                ASSERT_NE(0u, outputBlobStreams.size());
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
 
-                outputPreviewStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
-                        &previewThreshold));
-                ASSERT_NE(0u, outputPreviewStreams.size());
+        outputBlobStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputBlobStreams,
+                          &blobThreshold));
+        ASSERT_NE(0u, outputBlobStreams.size());
 
-                int32_t streamId = 0;
-                for (auto& blobIter : outputBlobStreams) {
-                    for (auto& previewIter : outputPreviewStreams) {
-                        Stream previewStream = {streamId++,
-                                                StreamType::OUTPUT,
-                                                static_cast<uint32_t>(previewIter.width),
-                                                static_cast<uint32_t>(previewIter.height),
-                                                static_cast<PixelFormat>(previewIter.format),
-                                                GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                                0,
-                                                StreamRotation::ROTATION_0};
-                        Stream blobStream = {streamId++,
-                                             StreamType::OUTPUT,
-                                             static_cast<uint32_t>(blobIter.width),
-                                             static_cast<uint32_t>(blobIter.height),
-                                             static_cast<PixelFormat>(blobIter.format),
-                                             GRALLOC1_CONSUMER_USAGE_CPU_READ,
-                                             0,
-                                             StreamRotation::ROTATION_0};
-                        ::android::hardware::hidl_vec<Stream> streams = {previewStream,
-                                                                         blobStream};
-                        StreamConfiguration config = {streams,
-                                                      StreamConfigurationMode::NORMAL_MODE};
-                        if (session3_3 == nullptr) {
-                            ret = session->configureStreams(config,
-                                    [](Status s, HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        } else {
-                            ret = session3_3->configureStreams_3_3(config,
-                                    [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        }
-                        ASSERT_TRUE(ret.isOk());
-                    }
+        outputPreviewStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
+                &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        int32_t streamId = 0;
+        for (auto& blobIter : outputBlobStreams) {
+            for (auto& previewIter : outputPreviewStreams) {
+                Stream previewStream = {streamId++,
+                                        StreamType::OUTPUT,
+                                        static_cast<uint32_t>(previewIter.width),
+                                        static_cast<uint32_t>(previewIter.height),
+                                        static_cast<PixelFormat>(previewIter.format),
+                                        GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                                        0,
+                                        StreamRotation::ROTATION_0};
+                Stream blobStream = {streamId++,
+                                     StreamType::OUTPUT,
+                                     static_cast<uint32_t>(blobIter.width),
+                                     static_cast<uint32_t>(blobIter.height),
+                                     static_cast<PixelFormat>(blobIter.format),
+                                     GRALLOC1_CONSUMER_USAGE_CPU_READ,
+                                     0,
+                                     StreamRotation::ROTATION_0};
+                ::android::hardware::hidl_vec<Stream> streams = {previewStream,
+                                                                 blobStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+                config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+                if (session3_4 != nullptr) {
+                    ret = session3_4->configureStreams_3_4(config,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else if (session3_3 != nullptr) {
+                    ret = session3_3->configureStreams_3_3(config.v3_2,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else {
+                    ret = session->configureStreams(config.v3_2,
+                            [](Status s, HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
                 }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
         }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2713,143 +2848,160 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
-
-                Status rc = isConstrainedModeAvailable(staticMeta);
-                if (Status::METHOD_NOT_SUPPORTED == rc) {
-                    ret = session->close();
-                    ASSERT_TRUE(ret.isOk());
-                    continue;
-                }
-                ASSERT_EQ(Status::OK, rc);
-
-                AvailableStream hfrStream;
-                rc = pickConstrainedModeSize(staticMeta, hfrStream);
-                ASSERT_EQ(Status::OK, rc);
-
-                int32_t streamId = 0;
-                Stream stream = {streamId,
-                                 StreamType::OUTPUT,
-                                 static_cast<uint32_t>(hfrStream.width),
-                                 static_cast<uint32_t>(hfrStream.height),
-                                 static_cast<PixelFormat>(hfrStream.format),
-                                 GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                                 0,
-                                 StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {stream};
-                StreamConfiguration config = {streams,
-                                              StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [streamId](Status s, HalStreamConfiguration halConfig) {
-                                ASSERT_EQ(Status::OK, s);
-                                ASSERT_EQ(1u, halConfig.streams.size());
-                                ASSERT_EQ(halConfig.streams[0].id, streamId);
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                ASSERT_EQ(Status::OK, s);
-                                ASSERT_EQ(1u, halConfig.streams.size());
-                                ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(0),
-                          static_cast<uint32_t>(0),
-                          static_cast<PixelFormat>(hfrStream.format),
-                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [](Status s, HalStreamConfiguration) {
-                                ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                        (Status::INTERNAL_ERROR == s));
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration) {
-                                ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                        (Status::INTERNAL_ERROR == s));
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<PixelFormat>(hfrStream.format),
-                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [](Status s, HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(hfrStream.width),
-                          static_cast<uint32_t>(hfrStream.height),
-                          static_cast<PixelFormat>(UINT32_MAX),
-                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [](Status s, HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        Status rc = isConstrainedModeAvailable(staticMeta);
+        if (Status::METHOD_NOT_SUPPORTED == rc) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        AvailableStream hfrStream;
+        rc = pickConstrainedModeSize(staticMeta, hfrStream);
+        ASSERT_EQ(Status::OK, rc);
+
+        int32_t streamId = 0;
+        Stream stream = {streamId,
+                         StreamType::OUTPUT,
+                         static_cast<uint32_t>(hfrStream.width),
+                         static_cast<uint32_t>(hfrStream.height),
+                         static_cast<PixelFormat>(hfrStream.format),
+                         GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                         0,
+                         StreamRotation::ROTATION_0};
+        ::android::hardware::hidl_vec<Stream> streams = {stream};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config,
+                    [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config.v3_2,
+                    [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                    });
+        } else {
+            ret = session->configureStreams(config.v3_2,
+                    [streamId](Status s, HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].id, streamId);
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(0),
+                  static_cast<uint32_t>(0),
+                  static_cast<PixelFormat>(hfrStream.format),
+                  GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config.v3_2,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        } else {
+            ret = session->configureStreams(config.v3_2,
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<PixelFormat>(hfrStream.format),
+                  GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config.v3_2,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else {
+            ret = session->configureStreams(config.v3_2,
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(hfrStream.width),
+                  static_cast<uint32_t>(hfrStream.height),
+                  static_cast<PixelFormat>(UINT32_MAX),
+                  GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config.v3_2,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else {
+            ret = session->configureStreams(config.v3_2,
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2866,82 +3018,82 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                outputBlobStreams.clear();
-                ASSERT_EQ(Status::OK,
-                          getAvailableOutputStreams(staticMeta, outputBlobStreams,
-                                  &blobThreshold));
-                ASSERT_NE(0u, outputBlobStreams.size());
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
 
-                outputVideoStreams.clear();
-                ASSERT_EQ(Status::OK,
-                          getAvailableOutputStreams(staticMeta, outputVideoStreams,
-                                  &videoThreshold));
-                ASSERT_NE(0u, outputVideoStreams.size());
+        outputBlobStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputBlobStreams,
+                          &blobThreshold));
+        ASSERT_NE(0u, outputBlobStreams.size());
 
-                int32_t streamId = 0;
-                for (auto& blobIter : outputBlobStreams) {
-                    for (auto& videoIter : outputVideoStreams) {
-                        Stream videoStream = {streamId++,
-                                              StreamType::OUTPUT,
-                                              static_cast<uint32_t>(videoIter.width),
-                                              static_cast<uint32_t>(videoIter.height),
-                                              static_cast<PixelFormat>(videoIter.format),
-                                              GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                                              0,
-                                              StreamRotation::ROTATION_0};
-                        Stream blobStream = {streamId++,
-                                             StreamType::OUTPUT,
-                                             static_cast<uint32_t>(blobIter.width),
-                                             static_cast<uint32_t>(blobIter.height),
-                                             static_cast<PixelFormat>(blobIter.format),
-                                             GRALLOC1_CONSUMER_USAGE_CPU_READ,
-                                             0,
-                                             StreamRotation::ROTATION_0};
-                        ::android::hardware::hidl_vec<Stream> streams = {videoStream, blobStream};
-                        StreamConfiguration config = {streams,
-                                                      StreamConfigurationMode::NORMAL_MODE};
-                        if (session3_3 == nullptr) {
-                            ret = session->configureStreams(config,
-                                    [](Status s, HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        } else {
-                            ret = session3_3->configureStreams_3_3(config,
-                                    [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        }
-                        ASSERT_TRUE(ret.isOk());
-                    }
+        outputVideoStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputVideoStreams,
+                          &videoThreshold));
+        ASSERT_NE(0u, outputVideoStreams.size());
+
+        int32_t streamId = 0;
+        for (auto& blobIter : outputBlobStreams) {
+            for (auto& videoIter : outputVideoStreams) {
+                Stream videoStream = {streamId++,
+                                      StreamType::OUTPUT,
+                                      static_cast<uint32_t>(videoIter.width),
+                                      static_cast<uint32_t>(videoIter.height),
+                                      static_cast<PixelFormat>(videoIter.format),
+                                      GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                                      0,
+                                      StreamRotation::ROTATION_0};
+                Stream blobStream = {streamId++,
+                                     StreamType::OUTPUT,
+                                     static_cast<uint32_t>(blobIter.width),
+                                     static_cast<uint32_t>(blobIter.height),
+                                     static_cast<PixelFormat>(blobIter.format),
+                                     GRALLOC1_CONSUMER_USAGE_CPU_READ,
+                                     0,
+                                     StreamRotation::ROTATION_0};
+                ::android::hardware::hidl_vec<Stream> streams = {videoStream, blobStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+                config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+                if (session3_4 != nullptr) {
+                    ret = session3_4->configureStreams_3_4(config,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else if (session3_3 != nullptr) {
+                    ret = session3_3->configureStreams_3_3(config.v3_2,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else {
+                    ret = session->configureStreams(config.v3_2,
+                            [](Status s, HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
                 }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
         }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2956,152 +3108,145 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                std::shared_ptr<ResultMetadataQueue> resultQueue;
-                auto resultQueueRet =
-                    session->getCaptureResultMetadataQueue(
-                        [&resultQueue](const auto& descriptor) {
-                            resultQueue = std::make_shared<ResultMetadataQueue>(
-                                    descriptor);
-                            if (!resultQueue->isValid() ||
-                                    resultQueue->availableToWrite() <= 0) {
-                                ALOGE("%s: HAL returns empty result metadata fmq,"
-                                        " not use it", __func__);
-                                resultQueue = nullptr;
-                                // Don't use the queue onwards.
-                            }
-                        });
-                ASSERT_TRUE(resultQueueRet.isOk());
-
-                InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                                               partialResultCount, resultQueue};
-
-                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-                Return<void> ret;
-                ret = session->constructDefaultRequestSettings(reqTemplate,
-                                                               [&](auto status, const auto& req) {
-                                                                   ASSERT_EQ(Status::OK, status);
-                                                                   settings = req;
-                                                               });
-                ASSERT_TRUE(ret.isOk());
-
-                sp<GraphicBuffer> gb = new GraphicBuffer(
-                    previewStream.width, previewStream.height,
-                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    halStreamConfig.streams[0].consumerUsage));
-                ASSERT_NE(nullptr, gb.get());
-                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                             bufferId,
-                                             hidl_handle(gb->getNativeBuffer()->handle),
-                                             BufferStatus::OK,
-                                             nullptr,
-                                             nullptr};
-                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-                StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                                 nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, outputBuffers};
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    mInflightMap.clear();
-                    mInflightMap.add(frameNumber, &inflightReq);
-                }
-
-                Status status = Status::INTERNAL_ERROR;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                Return<void> returnStatus = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, status);
-                ASSERT_EQ(numRequestProcessed, 1u);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (!inflightReq.errorCodeValid &&
-                           ((0 < inflightReq.numBuffersLeft) ||
-                                   (!inflightReq.haveResultMetadata))) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                       std::chrono::seconds(kStreamBufferTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout,
-                                mResultCondition.wait_until(l, timeout));
-                    }
-
-                    ASSERT_FALSE(inflightReq.errorCodeValid);
-                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                    ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
-
-                    request.frameNumber++;
-                    // Empty settings should be supported after the first call
-                    // for repeating requests.
-                    request.settings.setToExternal(nullptr, 0, true);
-                    // The buffer has been registered to HAL by bufferId, so per
-                    // API contract we should send a null handle for this buffer
-                    request.outputBuffers[0].buffer = nullptr;
-                    mInflightMap.clear();
-                    inflightReq = {1, false, supportsPartialResults, partialResultCount,
-                                   resultQueue};
-                    mInflightMap.add(request.frameNumber, &inflightReq);
-                }
-
-                returnStatus = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, status);
-                ASSERT_EQ(numRequestProcessed, 1u);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (!inflightReq.errorCodeValid &&
-                           ((0 < inflightReq.numBuffersLeft) ||
-                                   (!inflightReq.haveResultMetadata))) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                       std::chrono::seconds(kStreamBufferTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout,
-                                mResultCondition.wait_until(l, timeout));
-                    }
-
-                    ASSERT_FALSE(inflightReq.errorCodeValid);
-                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                    ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
-                }
-
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session->getCaptureResultMetadataQueue(
+                [&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!resultQueue->isValid() ||
+                            resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        InFlightRequest inflightReq = {1, false, supportsPartialResults,
+                                       partialResultCount, resultQueue};
+
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        Return<void> ret;
+        ret = session->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+
+        sp<GraphicBuffer> gb = new GraphicBuffer(
+            previewStream.width, previewStream.height,
+            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                            halStreamConfig.streams[0].consumerUsage));
+        ASSERT_NE(nullptr, gb.get());
+        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                                     bufferId,
+                                     hidl_handle(gb->getNativeBuffer()->handle),
+                                     BufferStatus::OK,
+                                     nullptr,
+                                     nullptr};
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
+                                         nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.add(frameNumber, &inflightReq);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        Return<void> returnStatus = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) ||
+                           (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout,
+                        mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq.errorCodeValid);
+            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+
+            request.frameNumber++;
+            // Empty settings should be supported after the first call
+            // for repeating requests.
+            request.settings.setToExternal(nullptr, 0, true);
+            // The buffer has been registered to HAL by bufferId, so per
+            // API contract we should send a null handle for this buffer
+            request.outputBuffers[0].buffer = nullptr;
+            mInflightMap.clear();
+            inflightReq = {1, false, supportsPartialResults, partialResultCount,
+                           resultQueue};
+            mInflightMap.add(request.frameNumber, &inflightReq);
+        }
+
+        returnStatus = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) ||
+                           (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout,
+                        mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq.errorCodeValid);
+            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+        }
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3118,65 +3263,58 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                sp<GraphicBuffer> gb = new GraphicBuffer(
-                    previewStream.width, previewStream.height,
-                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    halStreamConfig.streams[0].consumerUsage));
-
-                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                             bufferId,
-                                             hidl_handle(gb->getNativeBuffer()->handle),
-                                             BufferStatus::OK,
-                                             nullptr,
-                                             nullptr};
-                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-                StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                                 nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, outputBuffers};
-
-                // Settings were not correctly initialized, we should fail here
-                Status status = Status::OK;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                Return<void> ret = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
-                ASSERT_EQ(numRequestProcessed, 0u);
-
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        sp<GraphicBuffer> gb = new GraphicBuffer(
+            previewStream.width, previewStream.height,
+            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                            halStreamConfig.streams[0].consumerUsage));
+
+        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                                     bufferId,
+                                     hidl_handle(gb->getNativeBuffer()->handle),
+                                     BufferStatus::OK,
+                                     nullptr,
+                                     nullptr};
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
+                                         nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers};
+
+        // Settings were not correctly initialized, we should fail here
+        Status status = Status::OK;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        Return<void> ret = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
+        ASSERT_EQ(numRequestProcessed, 0u);
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3192,62 +3330,55 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-                Return<void> ret;
-                ret = session->constructDefaultRequestSettings(reqTemplate,
-                                                               [&](auto status, const auto& req) {
-                                                                   ASSERT_EQ(Status::OK, status);
-                                                                   settings = req;
-                                                               });
-                ASSERT_TRUE(ret.isOk());
-
-                ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
-                StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                                 nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, emptyOutputBuffers};
-
-                // Output buffers are missing, we should fail here
-                Status status = Status::OK;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                ret = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
-                ASSERT_EQ(numRequestProcessed, 0u);
-
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        Return<void> ret;
+        ret = session->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+
+        ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
+                                         nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, emptyOutputBuffers};
+
+        // Output buffers are missing, we should fail here
+        Status status = Status::OK;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        ret = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
+        ASSERT_EQ(numRequestProcessed, 0u);
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3263,130 +3394,123 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                std::shared_ptr<ResultMetadataQueue> resultQueue;
-                auto resultQueueRet =
-                    session->getCaptureResultMetadataQueue(
-                        [&resultQueue](const auto& descriptor) {
-                            resultQueue = std::make_shared<ResultMetadataQueue>(
-                                    descriptor);
-                            if (!resultQueue->isValid() ||
-                                    resultQueue->availableToWrite() <= 0) {
-                                ALOGE("%s: HAL returns empty result metadata fmq,"
-                                        " not use it", __func__);
-                                resultQueue = nullptr;
-                                // Don't use the queue onwards.
-                            }
-                        });
-                ASSERT_TRUE(resultQueueRet.isOk());
+        Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
 
-                InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                                               partialResultCount, resultQueue};
-                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-                Return<void> ret;
-                ret = session->constructDefaultRequestSettings(reqTemplate,
-                                                               [&](auto status, const auto& req) {
-                                                                   ASSERT_EQ(Status::OK, status);
-                                                                   settings = req;
-                                                               });
-                ASSERT_TRUE(ret.isOk());
-
-                sp<GraphicBuffer> gb = new GraphicBuffer(
-                    previewStream.width, previewStream.height,
-                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    halStreamConfig.streams[0].consumerUsage));
-                ASSERT_NE(nullptr, gb.get());
-                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                             bufferId,
-                                             hidl_handle(gb->getNativeBuffer()->handle),
-                                             BufferStatus::OK,
-                                             nullptr,
-                                             nullptr};
-                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-                const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
-                                                       BufferStatus::ERROR, nullptr, nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, outputBuffers};
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    mInflightMap.clear();
-                    mInflightMap.add(frameNumber, &inflightReq);
-                }
-
-                Status status = Status::INTERNAL_ERROR;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                ret = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(Status::OK, status);
-                ASSERT_EQ(numRequestProcessed, 1u);
-                // Flush before waiting for request to complete.
-                Return<Status> returnStatus = session->flush();
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (!inflightReq.errorCodeValid &&
-                           ((0 < inflightReq.numBuffersLeft) ||
-                                   (!inflightReq.haveResultMetadata))) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                       std::chrono::seconds(kStreamBufferTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l,
-                                timeout));
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session->getCaptureResultMetadataQueue(
+                [&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!resultQueue->isValid() ||
+                            resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
                     }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
 
-                    if (!inflightReq.errorCodeValid) {
-                        ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                        ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
-                    } else {
-                        switch (inflightReq.errorCode) {
-                            case ErrorCode::ERROR_REQUEST:
-                            case ErrorCode::ERROR_RESULT:
-                            case ErrorCode::ERROR_BUFFER:
-                                // Expected
-                                break;
-                            case ErrorCode::ERROR_DEVICE:
-                            default:
-                                FAIL() << "Unexpected error:"
-                                       << static_cast<uint32_t>(inflightReq.errorCode);
-                        }
-                    }
+        InFlightRequest inflightReq = {1, false, supportsPartialResults,
+                                       partialResultCount, resultQueue};
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        Return<void> ret;
+        ret = session->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
 
-                    ret = session->close();
-                    ASSERT_TRUE(ret.isOk());
+        sp<GraphicBuffer> gb = new GraphicBuffer(
+            previewStream.width, previewStream.height,
+            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                            halStreamConfig.streams[0].consumerUsage));
+        ASSERT_NE(nullptr, gb.get());
+        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                                     bufferId,
+                                     hidl_handle(gb->getNativeBuffer()->handle),
+                                     BufferStatus::OK,
+                                     nullptr,
+                                     nullptr};
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+                                               BufferStatus::ERROR, nullptr, nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.add(frameNumber, &inflightReq);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        ret = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+        // Flush before waiting for request to complete.
+        Return<Status> returnStatus = session->flush();
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, returnStatus);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) ||
+                           (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l,
+                        timeout));
+            }
+
+            if (!inflightReq.errorCodeValid) {
+                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+                ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+            } else {
+                switch (inflightReq.errorCode) {
+                    case ErrorCode::ERROR_REQUEST:
+                    case ErrorCode::ERROR_RESULT:
+                    case ErrorCode::ERROR_BUFFER:
+                        // Expected
+                        break;
+                    case ErrorCode::ERROR_DEVICE:
+                    default:
+                        FAIL() << "Unexpected error:"
+                               << static_cast<uint32_t>(inflightReq.errorCode);
                 }
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -3400,44 +3524,37 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                Return<Status> returnStatus = session->flush();
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    auto timeout = std::chrono::system_clock::now() +
-                                   std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
-                    ASSERT_EQ(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
-                }
-
-                Return<void> ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        Return<Status> returnStatus = session->flush();
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, returnStatus);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            auto timeout = std::chrono::system_clock::now() +
+                           std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
+            ASSERT_EQ(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+        }
+
+        Return<void> ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3625,7 +3742,7 @@
 }
 
 // Open a device session and configure a preview stream.
-void CameraHidlTest::configurePreviewStream(const std::string &name,
+void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
         const AvailableStream *previewThreshold,
         sp<ICameraDeviceSession> *session /*out*/,
@@ -3665,9 +3782,9 @@
         });
     ASSERT_TRUE(ret.isOk());
 
-    auto castResult = device::V3_3::ICameraDeviceSession::castFrom(*session);
-    ASSERT_TRUE(castResult.isOk());
-    sp<device::V3_3::ICameraDeviceSession> session3_3 = castResult;
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    sp<device::V3_4::ICameraDeviceSession> session3_4;
+    castSession(*session, deviceVersion, &session3_3, &session3_4);
 
     camera_metadata_t *staticMeta;
     ret = device3_x->getCameraCharacteristics([&] (Status s,
@@ -3700,17 +3817,10 @@
             static_cast<PixelFormat> (outputPreviewStreams[0].format),
             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0};
     ::android::hardware::hidl_vec<Stream> streams = {*previewStream};
-    StreamConfiguration config = {streams,
-            StreamConfigurationMode::NORMAL_MODE};
-    if (session3_3 == nullptr) {
-        ret = (*session)->configureStreams(config,
-                [&] (Status s, HalStreamConfiguration halConfig) {
-                    ASSERT_EQ(Status::OK, s);
-                    ASSERT_EQ(1u, halConfig.streams.size());
-                    *halStreamConfig = halConfig;
-                });
-    } else {
-        ret = session3_3->configureStreams_3_3(config,
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+    config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+    if (session3_4 != nullptr) {
+        ret = session3_4->configureStreams_3_4(config,
                 [&] (Status s, device::V3_3::HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
@@ -3719,15 +3829,57 @@
                         halStreamConfig->streams[i] = halConfig.streams[i].v3_2;
                     }
                 });
+    } else if (session3_3 != nullptr) {
+        ret = session3_3->configureStreams_3_3(config.v3_2,
+                [&] (Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                    halStreamConfig->streams.resize(halConfig.streams.size());
+                    for (size_t i = 0; i < halConfig.streams.size(); i++) {
+                        halStreamConfig->streams[i] = halConfig.streams[i].v3_2;
+                    }
+                });
+    } else {
+        ret = (*session)->configureStreams(config.v3_2,
+                [&] (Status s, HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                    *halStreamConfig = halConfig;
+                });
     }
     ASSERT_TRUE(ret.isOk());
 }
 
+//Cast camera device session to corresponding version
+void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
+        sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
+        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/) {
+    ASSERT_NE(nullptr, session3_3);
+    ASSERT_NE(nullptr, session3_4);
+
+    switch (deviceVersion) {
+        case CAMERA_DEVICE_API_VERSION_3_4: {
+            auto castResult = device::V3_4::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_4 = castResult;
+            break;
+        }
+        case CAMERA_DEVICE_API_VERSION_3_3: {
+            auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_3 = castResult;
+            break;
+        }
+        default:
+            //no-op
+            return;
+    }
+}
+
 // Open a device session with empty callbacks and return static metadata.
 void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
         sp<ICameraProvider> provider,
         sp<ICameraDeviceSession> *session /*out*/,
-        sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
         camera_metadata_t **staticMeta /*out*/) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, staticMeta);
@@ -3763,12 +3915,6 @@
         ASSERT_NE(nullptr, *staticMeta);
     });
     ASSERT_TRUE(ret.isOk());
-
-    if(session3_3 != nullptr) {
-        auto castResult = device::V3_3::ICameraDeviceSession::castFrom(*session);
-        ASSERT_TRUE(castResult.isOk());
-        *session3_3 = castResult;
-    }
 }
 
 // Open a particular camera device.