Merge cherrypicks of [3365569, 3365570, 3366860, 3366878, 3365571, 3365572, 3366918, 3365573, 3365589, 3365590, 3366938, 3366902, 3365574, 3365575, 3365576, 3365577, 3366958, 3365824, 3365591, 3366959, 3366960, 3366961, 3366962, 3366963, 3366964, 3366965, 3366919, 3366966, 3366967, 3366968, 3366969, 3366970, 3367018, 3367019, 3365592, 3365593, 3366985, 3365825, 3366988, 3366989, 3366990, 3366991, 3366992, 3366993, 3366994, 3367004, 3367005, 3367006, 3367007, 3367008, 3367009, 3367010, 3367011, 3367012, 3367013, 3367014, 3367015, 3367016, 3367017, 3367038, 3367039, 3367040, 3367041, 3367042, 3367044, 3367045, 3367046, 3367049, 3367050, 3367052, 3367053, 3367054, 3367055, 3367056, 3366920, 3366921, 3366922, 3367079] into oc-mr1-release

Change-Id: I10e3e1c9ba6057523c71ad89f8fdc9810de38571
diff --git a/msm8998/QCamera2/Android.mk b/msm8998/QCamera2/Android.mk
index e8a6811..184d9bc 100755
--- a/msm8998/QCamera2/Android.mk
+++ b/msm8998/QCamera2/Android.mk
@@ -30,6 +30,7 @@
 
 #HAL 3.0 source
 LOCAL_SRC_FILES += \
+        HAL3/QCamera3HdrPlusListenerThread.cpp \
         HAL3/QCamera3HWI.cpp \
         HAL3/QCamera3Mem.cpp \
         HAL3/QCamera3Stream.cpp \
diff --git a/msm8998/QCamera2/HAL3/QCamera3Channel.cpp b/msm8998/QCamera2/HAL3/QCamera3Channel.cpp
index bb12822..cf9fe4a 100644
--- a/msm8998/QCamera2/HAL3/QCamera3Channel.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3Channel.cpp
@@ -4034,8 +4034,8 @@
     const uint32_t *ldafCalib = hal_obj->getLdafCalib();
     const char *easelFwVersion = hal_obj->getEaselFwVersion();
     if ((eepromVersion && strlen(eepromVersion)) ||
-            ldafCalib) {
-        int len = 0;
+            ldafCalib || easelFwVersion) {
+        uint32_t len = 0;
         settings->image_desc_valid = true;
         if (eepromVersion && strlen(eepromVersion)) {
             len = snprintf(settings->image_desc, sizeof(settings->image_desc),
@@ -4048,8 +4048,12 @@
         }
         if (easelFwVersion) {
             ALOGD("%s: Easel FW version %s", __FUNCTION__, easelFwVersion);
+            if (len > 0 && len < sizeof(settings->image_desc)) {
+                settings->image_desc[len] = ',';
+                len++;
+            }
             len += snprintf(settings->image_desc + len,
-                            sizeof(settings->image_desc) - len, ":%s", easelFwVersion);
+                            sizeof(settings->image_desc) - len, "E-ver:%s", easelFwVersion);
         }
     }
 
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
index fe1fe8d..771d35b 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
@@ -147,6 +147,7 @@
 // The following Easel related variables must be protected by gHdrPlusClientLock.
 std::unique_ptr<EaselManagerClient> gEaselManagerClient;
 bool EaselManagerClientOpened = false; // If gEaselManagerClient is opened.
+int32_t gActiveEaselClient = 0; // The number of active cameras on Easel.
 std::unique_ptr<HdrPlusClient> gHdrPlusClient = nullptr;
 bool gHdrPlusClientOpening = false; // If HDR+ client is being opened.
 std::condition_variable gHdrPlusClientOpenCond; // Used to synchronize HDR+ client opening.
@@ -909,12 +910,24 @@
         std::unique_lock<std::mutex> l(gHdrPlusClientLock);
         if (gEaselManagerClient != nullptr && gEaselManagerClient->isEaselPresentOnDevice()) {
             logEaselEvent("EASEL_STARTUP_LATENCY", "Resume");
-            rc = gEaselManagerClient->resume(this);
-            if (rc != 0) {
-                ALOGE("%s: Resuming Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+            if (gActiveEaselClient == 0) {
+                rc = gEaselManagerClient->resume(this);
+                if (rc != 0) {
+                    ALOGE("%s: Resuming Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+                    return rc;
+                }
+                mEaselFwUpdated = false;
+            }
+
+            gActiveEaselClient++;
+
+            mQCamera3HdrPlusListenerThread = new QCamera3HdrPlusListenerThread(this);
+            rc = mQCamera3HdrPlusListenerThread->run("QCamera3HdrPlusListenerThread");
+            if (rc != OK) {
+                ALOGE("%s: Starting HDR+ client listener thread failed: %s (%d)", __FUNCTION__,
+                        strerror(-rc), rc);
                 return rc;
             }
-            mEaselFwUpdated = false;
         }
     }
 
@@ -928,12 +941,19 @@
         {
             std::unique_lock<std::mutex> l(gHdrPlusClientLock);
             if (gEaselManagerClient != nullptr && gEaselManagerClient->isEaselPresentOnDevice()) {
-                status_t suspendErr = gEaselManagerClient->suspend();
-                if (suspendErr != 0) {
-                    ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__,
-                            strerror(-suspendErr), suspendErr);
+                if (gActiveEaselClient == 1) {
+                    status_t suspendErr = gEaselManagerClient->suspend();
+                    if (suspendErr != 0) {
+                        ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__,
+                                strerror(-suspendErr), suspendErr);
+                    }
                 }
+                gActiveEaselClient--;
             }
+
+            mQCamera3HdrPlusListenerThread->requestExit();
+            mQCamera3HdrPlusListenerThread->join();
+            mQCamera3HdrPlusListenerThread = nullptr;
         }
     }
 
@@ -1124,11 +1144,18 @@
     {
         std::unique_lock<std::mutex> l(gHdrPlusClientLock);
         if (EaselManagerClientOpened) {
-            rc = gEaselManagerClient->suspend();
-            if (rc != 0) {
-                ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+            if (gActiveEaselClient == 1) {
+                rc = gEaselManagerClient->suspend();
+                if (rc != 0) {
+                    ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+                }
             }
+            gActiveEaselClient--;
         }
+
+        mQCamera3HdrPlusListenerThread->requestExit();
+        mQCamera3HdrPlusListenerThread->join();
+        mQCamera3HdrPlusListenerThread = nullptr;
     }
 
     return rc;
@@ -6430,6 +6457,7 @@
                 return rc;
             }
         }
+        mFirstPreviewIntentSeen = false;
     }
     pthread_mutex_unlock(&mMutex);
 
@@ -10918,7 +10946,7 @@
         if (eepromLength + sizeof(easelInfo) < MAX_EEPROM_VERSION_INFO_LEN) {
             eepromLength += sizeof(easelInfo);
             strlcat(eepromInfo, ((gEaselManagerClient != nullptr &&
-                    gEaselManagerClient->isEaselPresentOnDevice()) ? ",E-ver" : ",E:N"),
+                    gEaselManagerClient->isEaselPresentOnDevice()) ? ",E-Y" : ",E:N"),
                     MAX_EEPROM_VERSION_INFO_LEN);
         }
         staticInfo.update(NEXUS_EXPERIMENTAL_2017_EEPROM_VERSION_INFO,
@@ -11177,7 +11205,7 @@
             ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-res), res);
         }
 
-        gEaselBypassOnly = !property_get_bool("persist.camera.hdrplus.enable", false);
+        gEaselBypassOnly = property_get_bool("persist.camera.hdrplus.disable", false);
         gEaselProfilingEnabled = property_get_bool("persist.camera.hdrplus.profiling", false);
 
         // Expose enableZsl key only when HDR+ mode is enabled.
@@ -15189,7 +15217,7 @@
         return OK;
     }
 
-    status_t res = gEaselManagerClient->openHdrPlusClientAsync(this);
+    status_t res = gEaselManagerClient->openHdrPlusClientAsync(mQCamera3HdrPlusListenerThread.get());
     if (res != OK) {
         ALOGE("%s: Opening HDR+ client asynchronously failed: %s (%d)", __FUNCTION__,
                 strerror(-res), res);
@@ -15354,6 +15382,13 @@
 
 void QCamera3HardwareInterface::handleEaselFatalError()
 {
+    {
+        std::unique_lock<std::mutex> l(gHdrPlusClientLock);
+        if (gHdrPlusClient != nullptr) {
+            gHdrPlusClient->nofityEaselFatalError();
+        }
+    }
+
     pthread_mutex_lock(&mMutex);
     mState = ERROR;
     pthread_mutex_unlock(&mMutex);
@@ -15765,25 +15800,20 @@
             streamBuffer.acquire_fence = -1;
             streamBuffer.release_fence = -1;
 
-            streamBuffers.push_back(streamBuffer);
-
             // Send out error buffer event.
             camera3_notify_msg_t notify_msg = {};
             notify_msg.type = CAMERA3_MSG_ERROR;
             notify_msg.message.error.frame_number = pendingBuffers->frame_number;
-            notify_msg.message.error.error_code = CAMERA3_MSG_ERROR_BUFFER;
+            notify_msg.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
             notify_msg.message.error.error_stream = buffer.stream;
 
             orchestrateNotify(&notify_msg);
+            mOutputBufferDispatcher.markBufferReady(pendingBuffers->frame_number, streamBuffer);
         }
 
-        camera3_capture_result_t result = {};
-        result.frame_number = pendingBuffers->frame_number;
-        result.num_output_buffers = streamBuffers.size();
-        result.output_buffers = &streamBuffers[0];
+        mShutterDispatcher.clear(pendingBuffers->frame_number);
 
-        // Send out result with buffer errors.
-        orchestrateResult(&result);
+
 
         // Remove pending buffers.
         mPendingBuffersMap.mPendingBuffersInRequest.erase(pendingBuffers);
@@ -15802,7 +15832,6 @@
     pthread_mutex_unlock(&mMutex);
 }
 
-
 ShutterDispatcher::ShutterDispatcher(QCamera3HardwareInterface *parent) :
         mParent(parent) {}
 
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.h b/msm8998/QCamera2/HAL3/QCamera3HWI.h
index 4eaf8a8..c10c724 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.h
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.h
@@ -47,6 +47,7 @@
 #include "QCameraCommon.h"
 #include "QCamera3VendorTags.h"
 #include "QCameraDualCamSettings.h"
+#include "QCamera3HdrPlusListenerThread.h"
 
 #include "EaselManagerClient.h"
 #include "HdrPlusClient.h"
@@ -894,6 +895,9 @@
     int32_t mSceneDistance;
 
     std::future<void> mEaselErrorFuture;
+
+    // Thread to handle callbacks from HDR+ client. Protected by gHdrPlusClientLock.
+    sp<QCamera3HdrPlusListenerThread> mQCamera3HdrPlusListenerThread;
 };
 
 }; // namespace qcamera
diff --git a/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp
new file mode 100644
index 0000000..355d970
--- /dev/null
+++ b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright 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.
+ */
+
+#include "QCamera3HdrPlusListenerThread.h"
+
+
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using namespace android;
+
+namespace qcamera {
+
+QCamera3HdrPlusListenerThread::QCamera3HdrPlusListenerThread(
+        HdrPlusClientListener *listener) : mListener(listener), mExitRequested(false),
+        mFatalError(false)
+{
+}
+
+QCamera3HdrPlusListenerThread::~QCamera3HdrPlusListenerThread()
+{
+    requestExit();
+}
+
+void QCamera3HdrPlusListenerThread::onOpened(std::unique_ptr<HdrPlusClient> client)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    if (mClient != nullptr) {
+        ALOGW("%s: An old client exists and will be destroyed.", __FUNCTION__);
+    }
+    mClient = std::move(client);
+    mPendingCallbacks.push(CALLBACK_TYPE_OPENED);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onOpenFailed(status_t err)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    if (mOpenError != OK) {
+        ALOGW("%s: An old open failure exists and will be ignored: %s (%d)", __FUNCTION__,
+                strerror(-mOpenError), mOpenError);
+    }
+    mOpenError = err;
+    mPendingCallbacks.push(CALLBACK_TYPE_OPENFAILED);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onFatalError()
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    if (mFatalError) {
+        ALOGW("%s: An old fatal failure exists.", __FUNCTION__);
+    }
+    mFatalError = true;
+    mPendingCallbacks.push(CALLBACK_TYPE_FATAL_ERROR);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onCaptureResult(pbcamera::CaptureResult *result,
+            const camera_metadata_t &resultMetadata)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    PendingResult pendingResult = {};
+    pendingResult.result = *result;
+    pendingResult.metadata = clone_camera_metadata(&resultMetadata);
+    pendingResult.isFailed = false;
+    mResults.push(pendingResult);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_CAPTURE_RESULT);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onFailedCaptureResult(pbcamera::CaptureResult *failedResult)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    PendingResult result = {};
+    result.result = *failedResult;
+    result.metadata = nullptr;
+    result.isFailed = true;
+    mResults.push(result);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_CAPTURE_RESULT);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onShutter(uint32_t requestId, int64_t apSensorTimestampNs)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    std::pair<uint32_t, int64_t> shutter(requestId, apSensorTimestampNs);
+    mShutters.push(shutter);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_SHUTTER);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onNextCaptureReady(uint32_t requestId)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    mNextCaptureReadyIds.push(requestId);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_NEXT_CAPTURE_READY);
+    mCallbackCond.notify_one();
+
+}
+
+void QCamera3HdrPlusListenerThread::onPostview(uint32_t requestId,
+        std::unique_ptr<std::vector<uint8_t>> postview, uint32_t width, uint32_t height,
+        uint32_t stride, int32_t format)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    PendingPostview pendingPostview = {};
+    pendingPostview.requestId = requestId;
+    pendingPostview.postview = std::move(postview);
+    pendingPostview.width = width;
+    pendingPostview.height = height;
+    pendingPostview.stride = stride;
+    pendingPostview.format = format;
+    mPostviews.push(std::move(pendingPostview));
+
+    mPendingCallbacks.push(CALLBACK_TYPE_POSTVIEW);
+    mCallbackCond.notify_one();
+
+}
+
+void QCamera3HdrPlusListenerThread::requestExit()
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    mExitRequested = true;
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::handleFatalError()
+{
+    bool fatalError;
+    {
+        std::unique_lock<std::mutex> lock(mCallbackLock);
+        if (!mFatalError) {
+            ALOGW("%s: There is no fatal error.", __FUNCTION__);
+            return;
+        }
+
+        fatalError = mFatalError;
+    }
+
+    mListener->onFatalError();
+}
+
+void QCamera3HdrPlusListenerThread::handlePendingClient()
+{
+    std::unique_ptr<HdrPlusClient> client;
+    {
+        std::unique_lock<std::mutex> lock(mCallbackLock);
+        if (mClient == nullptr) {
+            ALOGW("%s: There is no pending client.", __FUNCTION__);
+            return;
+        }
+
+        client = std::move(mClient);
+    }
+
+    mListener->onOpened(std::move(client));
+}
+
+void QCamera3HdrPlusListenerThread::handleOpenError()
+{
+    status_t err = OK;
+    {
+        std::unique_lock<std::mutex> lock(mCallbackLock);
+        if (mOpenError == OK) {
+            ALOGW("%s: There is no pending open failure.", __FUNCTION__);
+            return;
+        }
+
+        err = mOpenError;
+        mOpenError = OK;
+    }
+
+    mListener->onOpenFailed(err);
+}
+
+void QCamera3HdrPlusListenerThread::handleNextCaptureReady()
+{
+    uint32_t requestId = 0;
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mNextCaptureReadyIds.size() == 0) {
+            ALOGW("%s: There is no NextCaptureReady.", __FUNCTION__);
+            return;
+        }
+        requestId = mNextCaptureReadyIds.front();
+        mNextCaptureReadyIds.pop();
+    }
+    mListener->onNextCaptureReady(requestId);
+}
+
+void QCamera3HdrPlusListenerThread::handleCaptureResult()
+{
+    PendingResult result = {};
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mResults.size() == 0) {
+            ALOGW("%s: There is no capture result.", __FUNCTION__);
+            return;
+        }
+        result = mResults.front();
+        mResults.pop();
+    }
+
+    if (result.isFailed) {
+        mListener->onFailedCaptureResult(&result.result);
+    } else {
+        mListener->onCaptureResult(&result.result, *result.metadata);
+    }
+}
+
+void QCamera3HdrPlusListenerThread::handleShutter()
+{
+    uint32_t requestId;
+    int64_t apSensorTimestampNs;
+
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mShutters.size() == 0) {
+            ALOGW("%s: There is no shutter.", __FUNCTION__);
+            return;;
+        }
+
+        auto shutter = mShutters.front();
+        requestId = shutter.first;
+        apSensorTimestampNs = shutter.second;
+        mShutters.pop();
+    }
+
+    mListener->onShutter(requestId, apSensorTimestampNs);
+}
+
+void QCamera3HdrPlusListenerThread::handlePostview()
+{
+    PendingPostview postview = {};
+
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mPostviews.size() == 0) {
+            ALOGW("%s: There is no postview.", __FUNCTION__);
+            return;;
+        }
+
+        postview = std::move(mPostviews.front());
+        mPostviews.pop();
+    }
+
+    mListener->onPostview(postview.requestId, std::move(postview.postview), postview.width,
+            postview.height, postview.stride, postview.format);
+}
+
+bool QCamera3HdrPlusListenerThread::threadLoop()
+{
+    if (mListener == nullptr) {
+        ALOGE("%s: mListener is nullptr.", __FUNCTION__);
+        return false;
+    }
+
+    while (1) {
+        CallbackType nextCallback;
+
+        {
+            std::unique_lock<std::mutex> lock(mCallbackLock);
+            if (!mExitRequested && mPendingCallbacks.size() == 0) {
+                mCallbackCond.wait(lock,
+                        [&] { return mExitRequested || mPendingCallbacks.size() > 0; });
+            }
+
+            if (mExitRequested) {
+                return false;
+            } else {
+                nextCallback = mPendingCallbacks.front();
+                mPendingCallbacks.pop();
+            }
+        }
+
+        switch (nextCallback) {
+            case CALLBACK_TYPE_OPENED:
+                handlePendingClient();
+                break;
+            case CALLBACK_TYPE_OPENFAILED:
+                handleOpenError();
+                break;
+            case CALLBACK_TYPE_FATAL_ERROR:
+                handleFatalError();
+                break;
+            case CALLBACK_TYPE_CAPTURE_RESULT:
+                handleCaptureResult();
+                break;
+            case CALLBACK_TYPE_SHUTTER:
+                handleShutter();
+                break;
+            case CALLBACK_TYPE_NEXT_CAPTURE_READY:
+                handleNextCaptureReady();
+                break;
+            case CALLBACK_TYPE_POSTVIEW:
+                handlePostview();
+                break;
+            default:
+                ALOGE("%s: Unknown callback type %d", __FUNCTION__, nextCallback);
+                break;
+        }
+    }
+
+    return false;
+}
+
+}; // namespace qcamera
diff --git a/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h
new file mode 100644
index 0000000..e64de36
--- /dev/null
+++ b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 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 __HDRPLUSCLIENTLISTENERHANDLERTHREAD__
+#define __HDRPLUSCLIENTLISTENERHANDLERTHREAD__
+
+// System dependencies
+#include <utils/Thread.h>
+#include <queue>
+
+#include "EaselManagerClient.h"
+#include "HdrPlusClient.h"
+
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using namespace android;
+
+namespace qcamera {
+
+/*
+ * A thread to handle callbacks from HDR+ client. When a callback from HDR+ client is invoked,
+ * HDR+ client callback thread will return and the threadloop of QCamera3HdrPlusListenerThread
+ * will call the callback handlers in QCamera3HWI, to avoid deadlock in HDR+ client callback thread.
+ */
+class QCamera3HdrPlusListenerThread : public HdrPlusClientListener, public Thread
+{
+public:
+    // listener is an HdrPlusClientListener to forward the callbacks in the thread loop.
+    QCamera3HdrPlusListenerThread(HdrPlusClientListener *listener);
+    virtual ~QCamera3HdrPlusListenerThread();
+
+    // Request the thread to exit.
+    void requestExit() override;
+
+private:
+    // HDR+ client callbacks.
+    void onOpened(std::unique_ptr<HdrPlusClient> client) override;
+    void onOpenFailed(status_t err) override;
+    void onFatalError() override;
+    void onCaptureResult(pbcamera::CaptureResult *result,
+            const camera_metadata_t &resultMetadata) override;
+    void onFailedCaptureResult(pbcamera::CaptureResult *failedResult) override;
+    void onShutter(uint32_t requestId, int64_t apSensorTimestampNs) override;
+    void onNextCaptureReady(uint32_t requestId) override;
+    void onPostview(uint32_t requestId, std::unique_ptr<std::vector<uint8_t>> postview,
+            uint32_t width, uint32_t height, uint32_t stride, int32_t format) override;
+
+    bool threadLoop() override;
+
+    // The following functions handle the pending callbacks by calling the callback handlers
+    // in QCamera3HWI.
+    bool hasPendingEventsLocked();
+    void handlePendingClient();
+    void handleNextCaptureReady();
+    void handleCaptureResult();
+    void handleFatalError();
+    void handleOpenError();
+    void handleShutter();
+    void handlePostview();
+
+    struct PendingResult {
+        pbcamera::CaptureResult result;
+        camera_metadata_t *metadata;
+        bool isFailed;
+    };
+
+    struct PendingPostview {
+        uint32_t requestId;
+        std::unique_ptr<std::vector<uint8_t>> postview;
+        uint32_t width;
+        uint32_t height;
+        uint32_t stride;
+        int32_t format;
+    };
+
+    enum CallbackType {
+        CALLBACK_TYPE_OPENED = 0,
+        CALLBACK_TYPE_OPENFAILED,
+        CALLBACK_TYPE_FATAL_ERROR,
+        CALLBACK_TYPE_CAPTURE_RESULT,
+        CALLBACK_TYPE_SHUTTER,
+        CALLBACK_TYPE_NEXT_CAPTURE_READY,
+        CALLBACK_TYPE_POSTVIEW,
+    };
+
+    HdrPlusClientListener *mListener;
+
+    std::mutex mCallbackLock;
+
+    // Condition for a new callback. Protected by mCallbackLock.
+    std::condition_variable mCallbackCond;
+    // If exit has been requested. Protected by mCallbackLock.
+    bool mExitRequested;
+
+    // The following variables store pending callbacks. Protected by mCallbackLock.
+    std::unique_ptr<HdrPlusClient> mClient;
+    std::queue<uint32_t> mNextCaptureReadyIds;
+    std::queue<PendingResult> mResults;
+    bool mFatalError;
+    status_t mOpenError;
+    std::queue<std::pair<uint32_t, int64_t>> mShutters;
+    std::queue<PendingPostview> mPostviews;
+
+    // A queue of pending callback types, in the same order as invoked by HDR+ client.
+    // Protected by mCallbackLock.
+    std::queue<CallbackType> mPendingCallbacks;
+};
+
+}; // namespace qcamera
+
+#endif /* __HDRPLUSCLIENTLISTENERHANDLERTHREAD__ */
\ No newline at end of file