Camera2: Enable LED in ZSL

If LED Flash needs to be fired for ZSL capture, prepareSnapshot
needs to be called for AEC estimation with Flash on to take place.
Add a new state in the state machine to handle this case.

Change-Id: I5882e568cb2bf84b9a4944023a9927e8ff3063cb
diff --git a/QCamera2/HAL/QCamera2HWI.cpp b/QCamera2/HAL/QCamera2HWI.cpp
index 1f2f8b9..056344c 100644
--- a/QCamera2/HAL/QCamera2HWI.cpp
+++ b/QCamera2/HAL/QCamera2HWI.cpp
@@ -577,14 +577,28 @@
         ALOGE("NULL camera device");
         return BAD_VALUE;
     }
+
     hw->lockAPI();
+
+    /* Prepare snapshot in case LED needs to be flashed */
+    ret = hw->processAPI(QCAMERA_SM_EVT_PREPARE_SNAPSHOT, NULL);
+    if (ret == NO_ERROR) {
+        hw->waitAPIResult(QCAMERA_SM_EVT_PREPARE_SNAPSHOT);
+        ret = hw->m_apiResult.status;
+    }
+
+    /* Regardless what the result value for prepare_snapshot,
+     * go ahead with capture anyway. Just like the way autofocus
+     * is handled in capture case. */
+
+    /* capture */
     ret = hw->processAPI(QCAMERA_SM_EVT_TAKE_PICTURE, NULL);
     if (ret == NO_ERROR) {
         hw->waitAPIResult(QCAMERA_SM_EVT_TAKE_PICTURE);
         ret = hw->m_apiResult.status;
     }
-    hw->unlockAPI();
 
+    hw->unlockAPI();
     return ret;
 }
 
@@ -904,6 +918,7 @@
       m_cbNotifier(this),
       m_bShutterSoundPlayed(false),
       m_bAutoFocusRunning(false),
+      m_bStartZSLSnapshotCalled(false),
       m_pPowerModule(NULL)
 {
     mCameraDevice.common.tag = HARDWARE_DEVICE_TAG;
@@ -1792,9 +1807,6 @@
         }
     } else {
         // normal capture case
-        // prepare snapshot, e.g LED
-        prepareHardwareForSnapshot( );
-
         // need to stop preview channel
         stopChannel(QCAMERA_CH_TYPE_PREVIEW);
         delChannel(QCAMERA_CH_TYPE_PREVIEW);
@@ -1860,6 +1872,11 @@
         QCameraPicChannel *pZSLChannel =
             (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL];
         if (NULL != pZSLChannel) {
+            if (m_bStartZSLSnapshotCalled) {
+                mCameraHandle->ops->stop_zsl_snapshot(
+                        mCameraHandle->camera_handle);
+                m_bStartZSLSnapshotCalled = false;
+            }
             pZSLChannel->cancelPicture();
         }
     } else {
@@ -2370,6 +2387,39 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : processPrepSnapshotDone
+ *
+ * DESCRIPTION: process prep snapshot done event
+ *
+ * PARAMETERS :
+ *   @prep_snapshot_state  : state of prepare snapshot done. In other words,
+ *                           i.e. whether need future frames for capture.
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera2HardwareInterface::processPrepSnapshotDoneEvent(
+                        cam_prep_snapshot_state_t prep_snapshot_state)
+{
+    int32_t ret = NO_ERROR;
+
+    if (m_channels[QCAMERA_CH_TYPE_ZSL] &&
+        prep_snapshot_state == NEED_FUTURE_FRAME) {
+
+        ret = mCameraHandle->ops->start_zsl_snapshot(
+                            mCameraHandle->camera_handle);
+        if (ret < 0) {
+            ALOGE("%s: start_led_zsl_capture failed %d",
+                            __func__, ret);
+            return ret;
+        }
+        m_bStartZSLSnapshotCalled = true;
+    }
+    return ret;
+}
+
+/*===========================================================================
  * FUNCTION   : processJpegNotify
  *
  * DESCRIPTION: process jpeg event
diff --git a/QCamera2/HAL/QCamera2HWI.h b/QCamera2/HAL/QCamera2HWI.h
index 31393e1..316c2a4 100644
--- a/QCamera2/HAL/QCamera2HWI.h
+++ b/QCamera2/HAL/QCamera2HWI.h
@@ -266,6 +266,7 @@
 
     int32_t processAutoFocusEvent(cam_auto_focus_data_t &focus_data);
     int32_t processZoomEvent(cam_crop_data_t &crop_info);
+    int32_t processPrepSnapshotDoneEvent(cam_prep_snapshot_state_t prep_snapshot_state);
     int32_t processJpegNotify(qcamera_jpeg_evt_payload_t *jpeg_job);
 
     int32_t sendEvtNotify(int32_t msg_type, int32_t ext1, int32_t ext2);
@@ -389,6 +390,9 @@
     // of whether lens is moving or not.
     bool m_bAutoFocusRunning;
 
+    // If start_zsl_snapshot is called to notify camera daemon about zsl snapshot
+    bool m_bStartZSLSnapshotCalled;
+
     power_module_t *m_pPowerModule;   // power module
 
 };
diff --git a/QCamera2/HAL/QCamera2HWICallbacks.cpp b/QCamera2/HAL/QCamera2HWICallbacks.cpp
index 1db83c2..c7a52ba 100644
--- a/QCamera2/HAL/QCamera2HWICallbacks.cpp
+++ b/QCamera2/HAL/QCamera2HWICallbacks.cpp
@@ -714,6 +714,25 @@
         pme->processZoomEvent(pMetaData->crop_data);
     }
 
+    if (pMetaData->is_prep_snapshot_done_valid) {
+        qcamera_sm_internal_evt_payload_t *payload =
+            (qcamera_sm_internal_evt_payload_t *)malloc(sizeof(qcamera_sm_internal_evt_payload_t));
+        if (NULL != payload) {
+            memset(payload, 0, sizeof(qcamera_sm_internal_evt_payload_t));
+            payload->evt_type = QCAMERA_INTERNAL_EVT_PREP_SNAPSHOT_DONE;
+            payload->prep_snapshot_state = pMetaData->prep_snapshot_done_state;
+            int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
+            if (rc != NO_ERROR) {
+                ALOGE("%s: processEVt failed", __func__);
+                free(payload);
+                payload = NULL;
+
+            }
+        } else {
+            ALOGE("%s: No memory for qcamera_sm_internal_evt_payload_t", __func__);
+        }
+    }
+
     stream->bufDone(frame->buf_idx);
     free(super_frame);
 
diff --git a/QCamera2/HAL/QCameraStateMachine.cpp b/QCamera2/HAL/QCameraStateMachine.cpp
index 904130c..1c8b1e3 100644
--- a/QCamera2/HAL/QCameraStateMachine.cpp
+++ b/QCamera2/HAL/QCameraStateMachine.cpp
@@ -253,6 +253,9 @@
     case QCAMERA_SM_STATE_PREVIEWING:
         rc = procEvtPreviewingState(evt, payload);
         break;
+    case QCAMERA_SM_STATE_PREPARE_SNAPSHOT:
+        rc = procEvtPrepareSnapshotState(evt, payload);
+        break;
     case QCAMERA_SM_STATE_PIC_TAKING:
         rc = procEvtPicTakingState(evt, payload);
         break;
@@ -486,6 +489,7 @@
     case QCAMERA_SM_EVT_START_RECORDING:
     case QCAMERA_SM_EVT_STOP_RECORDING:
     case QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME:
+    case QCAMERA_SM_EVT_PREPARE_SNAPSHOT:
     case QCAMERA_SM_EVT_TAKE_PICTURE:
     case QCAMERA_SM_EVT_START_AUTO_FOCUS:
         {
@@ -773,6 +777,7 @@
     case QCAMERA_SM_EVT_START_NODISPLAY_PREVIEW:
     case QCAMERA_SM_EVT_START_RECORDING:
     case QCAMERA_SM_EVT_STOP_RECORDING:
+    case QCAMERA_SM_EVT_PREPARE_SNAPSHOT:
     case QCAMERA_SM_EVT_TAKE_PICTURE:
     case QCAMERA_SM_EVT_CANCEL_PICTURE:
     case QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME:
@@ -1017,16 +1022,35 @@
             m_parent->signalAPIResult(&result);
         }
         break;
-    case QCAMERA_SM_EVT_TAKE_PICTURE:
+    case QCAMERA_SM_EVT_PREPARE_SNAPSHOT:
         {
-            rc = m_parent->takePicture();
+            rc = m_parent->prepareHardwareForSnapshot();
             if (rc == NO_ERROR) {
-                // move state to picture taking state
-                if (m_parent->isZSLMode()) {
-                    m_state = QCAMERA_SM_STATE_PREVIEW_PIC_TAKING;
-                } else {
-                    m_state = QCAMERA_SM_STATE_PIC_TAKING;
-                }
+                // Do not signal API result in this case.
+                // Need to wait for snapshot done in metadta.
+                m_state = QCAMERA_SM_STATE_PREPARE_SNAPSHOT;
+            } else {
+                // Do not change state in this case.
+                ALOGE("%s: prepareHardwareForSnapshot failed %d",
+                    __func__, rc);
+
+                result.status = rc;
+                result.request_api = evt;
+                result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+                m_parent->signalAPIResult(&result);
+            }
+        }
+        break;
+    case QCAMERA_SM_EVT_TAKE_PICTURE:
+       {
+           rc = m_parent->takePicture();
+           if (rc == NO_ERROR) {
+               // move state to picture taking state
+               if (m_parent->isZSLMode()) {
+                   m_state = QCAMERA_SM_STATE_PREVIEW_PIC_TAKING;
+               } else {
+                   m_state = QCAMERA_SM_STATE_PIC_TAKING;
+               }
             } else {
                 // move state to preview stopped state
                 m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
@@ -1087,6 +1111,8 @@
                 rc = m_parent->processAutoFocusEvent(internal_evt->focus_data);
                 break;
             default:
+                ALOGE("%s: Invalid internal event %d in state(%d)",
+                            __func__, internal_evt->evt_type, m_state);
                 break;
             }
         }
@@ -1119,6 +1145,96 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : procEvtPrepareSnapshotState
+ *
+ * DESCRIPTION: finite state machine function to handle event in state of
+ *              QCAMERA_SM_STATE_PREPARE_SNAPSHOT.
+ *
+ * PARAMETERS :
+ *   @evt      : event to be processed
+ *   @payload  : event payload. Can be NULL if not needed.
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCameraStateMachine::procEvtPrepareSnapshotState(qcamera_sm_evt_enum_t evt,
+                                                    void *payload)
+{
+    int32_t rc = NO_ERROR;
+    qcamera_api_result_t result;
+    memset(&result, 0, sizeof(qcamera_api_result_t));
+
+    switch (evt) {
+    case QCAMERA_SM_EVT_SET_PREVIEW_WINDOW:
+    case QCAMERA_SM_EVT_SET_CALLBACKS:
+    case QCAMERA_SM_EVT_ENABLE_MSG_TYPE:
+    case QCAMERA_SM_EVT_DISABLE_MSG_TYPE:
+    case QCAMERA_SM_EVT_MSG_TYPE_ENABLED:
+    case QCAMERA_SM_EVT_SET_PARAMS:
+    case QCAMERA_SM_EVT_GET_PARAMS:
+    case QCAMERA_SM_EVT_PUT_PARAMS:
+    case QCAMERA_SM_EVT_START_PREVIEW:
+    case QCAMERA_SM_EVT_START_NODISPLAY_PREVIEW:
+    case QCAMERA_SM_EVT_STOP_PREVIEW:
+    case QCAMERA_SM_EVT_PREVIEW_ENABLED:
+    case QCAMERA_SM_EVT_RECORDING_ENABLED:
+    case QCAMERA_SM_EVT_STORE_METADATA_IN_BUFS:
+    case QCAMERA_SM_EVT_DUMP:
+    case QCAMERA_SM_EVT_START_AUTO_FOCUS:
+    case QCAMERA_SM_EVT_STOP_AUTO_FOCUS:
+    case QCAMERA_SM_EVT_START_RECORDING:
+    case QCAMERA_SM_EVT_TAKE_PICTURE:
+    case QCAMERA_SM_EVT_SEND_COMMAND:
+    case QCAMERA_SM_EVT_CANCEL_PICTURE:
+    case QCAMERA_SM_EVT_STOP_RECORDING:
+    case QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME:
+    case QCAMERA_SM_EVT_RELEASE:
+        {
+            ALOGE("%s: cannot handle evt(%d) in state(%d)", __func__, evt, m_state);
+            rc = INVALID_OPERATION;
+            result.status = rc;
+            result.request_api = evt;
+            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+            m_parent->signalAPIResult(&result);
+        }
+        break;
+    case QCAMERA_SM_EVT_EVT_INTERNAL:
+        {
+            qcamera_sm_internal_evt_payload_t *internal_evt =
+                (qcamera_sm_internal_evt_payload_t *)payload;
+            switch (internal_evt->evt_type) {
+            case QCAMERA_INTERNAL_EVT_PREP_SNAPSHOT_DONE:
+                ALOGI("%s: Received QCAMERA_INTERNAL_EVT_PREP_SNAPSHOT_DONE event",
+                    __func__);
+                m_parent->processPrepSnapshotDoneEvent(internal_evt->prep_snapshot_state);
+                m_state = QCAMERA_SM_STATE_PREVIEWING;
+
+                result.status = NO_ERROR;
+                result.request_api = QCAMERA_SM_EVT_PREPARE_SNAPSHOT;
+                result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+                m_parent->signalAPIResult(&result);
+                break;
+            default:
+                ALOGE("%s: Invalid internal event %d in state(%d)",
+                            __func__, internal_evt->evt_type, m_state);
+                break;
+            }
+        }
+        break;
+    case QCAMERA_SM_EVT_EVT_NOTIFY:
+    case QCAMERA_SM_EVT_THERMAL_NOTIFY:
+    case QCAMERA_SM_EVT_JPEG_EVT_NOTIFY:
+    case QCAMERA_SM_EVT_SNAPSHOT_DONE:
+    default:
+        ALOGE("%s: cannot handle evt(%d) in state(%d)", __func__, evt, m_state);
+        break;
+    }
+
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : procEvtPicTakingState
  *
  * DESCRIPTION: finite state machine function to handle event in state of
@@ -1635,6 +1751,15 @@
             m_parent->signalAPIResult(&result);
         }
         break;
+    case QCAMERA_SM_EVT_PREPARE_SNAPSHOT:
+        {
+            //In Video snapshot, prepare hardware is a no-op.
+            result.status = NO_ERROR;
+            result.request_api = evt;
+            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+            m_parent->signalAPIResult(&result);
+        }
+        break;
     case QCAMERA_SM_EVT_CANCEL_PICTURE:
     case QCAMERA_SM_EVT_START_PREVIEW:
     case QCAMERA_SM_EVT_START_NODISPLAY_PREVIEW:
@@ -2179,7 +2304,11 @@
         break;
     case QCAMERA_SM_EVT_CANCEL_PICTURE:
         {
-            rc = m_parent->cancelLiveSnapshot();
+            if (m_parent->isZSLMode()) {
+                rc = m_parent->cancelPicture();
+            } else {
+                rc = m_parent->cancelLiveSnapshot();
+            }
             m_state = QCAMERA_SM_STATE_PREVIEWING;
             result.status = rc;
             result.request_api = evt;
@@ -2275,7 +2404,11 @@
         break;
     case QCAMERA_SM_EVT_SNAPSHOT_DONE:
         {
-            rc = m_parent->cancelLiveSnapshot();
+            if (m_parent->isZSLMode()) {
+                rc = m_parent->cancelPicture();
+            } else {
+                rc = m_parent->cancelLiveSnapshot();
+            }
             m_state = QCAMERA_SM_STATE_PREVIEWING;
         }
         break;
diff --git a/QCamera2/HAL/QCameraStateMachine.h b/QCamera2/HAL/QCameraStateMachine.h
index 527597e..66eb63b 100644
--- a/QCamera2/HAL/QCameraStateMachine.h
+++ b/QCamera2/HAL/QCameraStateMachine.h
@@ -67,6 +67,7 @@
     QCAMERA_SM_EVT_RECORDING_ENABLED,        // query if recording is running
     QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME,  // release recording frame
 
+    QCAMERA_SM_EVT_PREPARE_SNAPSHOT,         // prepare snapshot in case LED needs to be flashed
     QCAMERA_SM_EVT_TAKE_PICTURE,             // take picutre (zsl, regualr capture, live snapshot
     QCAMERA_SM_EVT_CANCEL_PICTURE,           // cancel picture
 
@@ -129,7 +130,8 @@
 } qcamera_sm_evt_reg_face_payload_t;
 
 typedef enum {
-    QCAMERA_INTERNAL_EVT_FOCUS_UPDATE,       // internal event for focus updating
+    QCAMERA_INTERNAL_EVT_FOCUS_UPDATE,       // focus updating result
+    QCAMERA_INTERNAL_EVT_PREP_SNAPSHOT_DONE, // prepare snapshot done
     QCAMERA_INTERNAL_EVT_MAX
 } qcamera_internal_evt_type_t;
 
@@ -137,6 +139,7 @@
     qcamera_internal_evt_type_t evt_type;
     union {
         cam_auto_focus_data_t focus_data;
+        cam_prep_snapshot_state_t prep_snapshot_state;
     };
 } qcamera_sm_internal_evt_payload_t;
 
@@ -155,6 +158,8 @@
         QCAMERA_SM_STATE_PREVIEW_STOPPED,          // preview is stopped
         QCAMERA_SM_STATE_PREVIEW_READY,            // preview started but preview window is not set yet
         QCAMERA_SM_STATE_PREVIEWING,               // previewing
+        QCAMERA_SM_STATE_PREPARE_SNAPSHOT,         // prepare snapshot in case aec estimation is
+                                                   // needed for LED flash
         QCAMERA_SM_STATE_PIC_TAKING,               // taking picture (preview stopped)
         QCAMERA_SM_STATE_RECORDING,                // recording (preview running)
         QCAMERA_SM_STATE_VIDEO_PIC_TAKING,         // taking live snapshot during recording (preview running)
@@ -179,6 +184,7 @@
     int32_t procEvtPreviewStoppedState(qcamera_sm_evt_enum_t evt, void *payload);
     int32_t procEvtPreviewReadyState(qcamera_sm_evt_enum_t evt, void *payload);
     int32_t procEvtPreviewingState(qcamera_sm_evt_enum_t evt, void *payload);
+    int32_t procEvtPrepareSnapshotState(qcamera_sm_evt_enum_t evt, void *payload);
     int32_t procEvtPicTakingState(qcamera_sm_evt_enum_t evt, void *payload);
     int32_t procEvtRecordingState(qcamera_sm_evt_enum_t evt, void *payload);
     int32_t procEvtVideoPicTakingState(qcamera_sm_evt_enum_t evt, void *payload);
diff --git a/QCamera2/stack/common/mm_camera_interface.h b/QCamera2/stack/common/mm_camera_interface.h
index 23bb957..ae0732f 100755
--- a/QCamera2/stack/common/mm_camera_interface.h
+++ b/QCamera2/stack/common/mm_camera_interface.h
@@ -366,6 +366,22 @@
      **/
     int32_t (*prepare_snapshot) (uint32_t camera_handle);
 
+    /** start_zsl_snapshot: function definition for starting
+     *                    zsl snapshot.
+     *    @camera_handle : camer handler
+     *  Return value: 0 -- success
+     *                -1 -- failure
+     **/
+    int32_t (*start_zsl_snapshot) (uint32_t camera_handle);
+
+    /** stop_zsl_snapshot: function definition for stopping
+     *                    zsl snapshot.
+     *    @camera_handle : camer handler
+     *  Return value: 0 -- success
+     *                -1 -- failure
+     **/
+    int32_t (*stop_zsl_snapshot) (uint32_t camera_handle);
+
     /** add_channel: fucntion definition for adding a channel
      *    @camera_handle : camer handler
      *    @ch_id : channel handler
@@ -573,15 +589,18 @@
     int32_t (*cancel_super_buf_request) (uint32_t camera_handle,
                                          uint32_t ch_id);
 
-    /** flush_super_buf_queue: fucntion definition for flushing out
-     *                     all frames in the superbuf queue
+    /** flush_super_buf_queue: function definition for flushing out
+     *                     all frames in the superbuf queue up to frame_idx,
+     *                     even if frames with frame_idx come in later than
+     *                     this call.
      *    @camera_handle : camer handler
      *    @ch_id : channel handler
+     *    @frame_idx : frame index up until which all superbufs are flushed
      *  Return value: 0 -- success
      *                -1 -- failure
      **/
     int32_t (*flush_super_buf_queue) (uint32_t camera_handle,
-                                      uint32_t ch_id);
+                                      uint32_t ch_id, uint32_t frame_idx);
 } mm_camera_ops_t;
 
 /** mm_camera_vtbl_t: virtual table for camera operations
diff --git a/QCamera2/stack/mm-camera-interface/inc/mm_camera.h b/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
index 73d7d58..e41753b 100755
--- a/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
+++ b/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
@@ -88,6 +88,7 @@
         mm_camera_event_t evt;       /* evt if evtCB */
         mm_camera_super_buf_t superbuf; /* superbuf if superbuf dataCB*/
         mm_camera_req_buf_t req_buf; /* num of buf requested */
+        uint32_t frame_idx; /* frame idx boundary for flush superbuf queue*/
     } u;
 } mm_camera_cmdcb_t;
 
@@ -427,6 +428,8 @@
                                         cam_autofocus_cycle_t sweep_mode);
 extern cam_autofocus_state_t mm_camera_cancel_auto_focus(mm_camera_obj_t *my_obj);
 extern int32_t mm_camera_prepare_snapshot(mm_camera_obj_t *my_obj);
+extern int32_t mm_camera_start_zsl_snapshot(mm_camera_obj_t *my_obj);
+extern int32_t mm_camera_stop_zsl_snapshot(mm_camera_obj_t *my_obj);
 extern uint32_t mm_camera_add_channel(mm_camera_obj_t *my_obj,
                                       mm_camera_channel_attr_t *attr,
                                       mm_camera_buf_notify_t channel_cb,
@@ -455,7 +458,8 @@
 extern int32_t mm_camera_cancel_super_buf_request(mm_camera_obj_t *my_obj,
                                                   uint32_t ch_id);
 extern int32_t mm_camera_flush_super_buf_queue(mm_camera_obj_t *my_obj,
-                                               uint32_t ch_id);
+                                               uint32_t ch_id,
+                                               uint32_t frame_idx);
 extern int32_t mm_camera_set_stream_parms(mm_camera_obj_t *my_obj,
                                           uint32_t ch_id,
                                           uint32_t s_id,
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera.c b/QCamera2/stack/mm-camera-interface/src/mm_camera.c
index 3cfa2bf..c95beb6 100755
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera.c
@@ -655,6 +655,52 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_camera_start_zsl_snapshot
+ *
+ * DESCRIPTION: start zsl snapshot
+ *
+ * PARAMETERS :
+ *   @my_obj       : camera object
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+int32_t mm_camera_start_zsl_snapshot(mm_camera_obj_t *my_obj)
+{
+    int32_t rc = -1;
+    int32_t value = 0;
+
+    rc = mm_camera_util_s_ctrl(my_obj->ctrl_fd,
+             CAM_PRIV_START_ZSL_SNAPSHOT, &value);
+
+    pthread_mutex_unlock(&my_obj->cam_lock);
+    return rc;
+}
+
+/*===========================================================================
+ * FUNCTION   : mm_camera_stop_zsl_snapshot
+ *
+ * DESCRIPTION: stop zsl capture
+ *
+ * PARAMETERS :
+ *   @my_obj       : camera object
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+int32_t mm_camera_stop_zsl_snapshot(mm_camera_obj_t *my_obj)
+{
+    int32_t rc = -1;
+    int32_t value;
+    rc = mm_camera_util_s_ctrl(my_obj->ctrl_fd,
+             CAM_PRIV_STOP_ZSL_SNAPSHOT, &value);
+    pthread_mutex_unlock(&my_obj->cam_lock);
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : mm_camera_add_channel
  *
  * DESCRIPTION: add a channel
@@ -1053,7 +1099,8 @@
  *              0  -- success
  *              -1 -- failure
  *==========================================================================*/
-int32_t mm_camera_flush_super_buf_queue(mm_camera_obj_t *my_obj, uint32_t ch_id)
+int32_t mm_camera_flush_super_buf_queue(mm_camera_obj_t *my_obj, uint32_t ch_id,
+                                                             uint32_t frame_idx)
 {
     int32_t rc = -1;
     mm_channel_t * ch_obj =
@@ -1065,7 +1112,7 @@
 
         rc = mm_channel_fsm_fn(ch_obj,
                                MM_CHANNEL_EVT_FLUSH_SUPER_BUF_QUEUE,
-                               NULL,
+                               (void *)frame_idx,
                                NULL);
     } else {
         pthread_mutex_unlock(&my_obj->cam_lock);
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c b/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c
index d96eb43..1a56e57 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c
@@ -65,7 +65,9 @@
 int32_t mm_channel_request_super_buf(mm_channel_t *my_obj,
                                      uint32_t num_buf_requested);
 int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj);
-int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj);
+int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj,
+                                         uint32_t frame_idx);
+int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, mm_channel_queue_t * queue);
 int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
                                    mm_evt_paylod_set_get_stream_parms_t *payload);
 int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
@@ -170,7 +172,7 @@
  * FUNCTION   : mm_channel_process_stream_buf
  *
  * DESCRIPTION: handle incoming buffer from stream in a bundle. In this function,
- *              matching logic will be performed on imcoming stream frames.
+ *              matching logic will be performed on incoming stream frames.
  *              Will depends on the bundle attribute, either storing matched frames
  *              in the superbuf queue, or sending matched superbuf frames to upper
  *              layer through registered callback.
@@ -202,6 +204,8 @@
         ch_obj->pending_cnt = cmd_cb->u.req_buf.num_buf_requested;
         mm_channel_superbuf_skip(ch_obj, &ch_obj->bundle.superbuf_queue);
     } else if (MM_CAMERA_CMD_TYPE_FLUSH_QUEUE  == cmd_cb->cmd_type) {
+        ch_obj->bundle.superbuf_queue.expected_frame_id = cmd_cb->u.frame_idx;
+        mm_channel_superbuf_flush(ch_obj, &ch_obj->bundle.superbuf_queue);
         return;
     }
 
@@ -510,7 +514,8 @@
         break;
     case MM_CHANNEL_EVT_FLUSH_SUPER_BUF_QUEUE:
         {
-            rc = mm_channel_flush_super_buf_queue(my_obj);
+            uint32_t frame_idx = (uint32_t)in_val;
+            rc = mm_channel_flush_super_buf_queue(my_obj, frame_idx);
         }
         break;
     case MM_CHANNEL_EVT_SET_STREAM_PARM:
@@ -1118,12 +1123,13 @@
  *
  * PARAMETERS :
  *   @my_obj  : channel object
+ *   @frame_idx : frame idx until which to flush all superbufs
  *
  * RETURN     : int32_t type of status
  *              0  -- success
  *              -1 -- failure
  *==========================================================================*/
-int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj)
+int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj, uint32_t frame_idx)
 {
     int32_t rc = 0;
     mm_camera_cmdcb_t* node = NULL;
@@ -1132,6 +1138,7 @@
     if (NULL != node) {
         memset(node, 0, sizeof(mm_camera_cmdcb_t));
         node->cmd_type = MM_CAMERA_CMD_TYPE_FLUSH_QUEUE;
+        node->u.frame_idx = frame_idx;
 
         /* enqueue to cmd thread */
         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
@@ -1399,6 +1406,85 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_channel_handle_metadata
+ *
+ * DESCRIPTION: Handle frame matching logic change due to metadata
+ *
+ * PARAMETERS :
+ *   @ch_obj  : channel object
+ *   @queue   : superbuf queue
+ *   @buf_info: new buffer from stream
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+int32_t mm_channel_handle_metadata(
+                        mm_channel_t* ch_obj,
+                        mm_channel_queue_t * queue,
+                        mm_camera_buf_info_t *buf_info)
+{
+    int rc = 0 ;
+    mm_stream_t* stream_obj = NULL;
+    stream_obj = mm_channel_util_get_stream_by_handler(ch_obj,
+                buf_info->stream_id);
+
+    if (NULL == stream_obj) {
+        CDBG_ERROR("%s: Invalid Stream Object for stream_id = %d",
+                   __func__, buf_info->stream_id);
+        rc = -1;
+        goto end;
+    }
+    if (NULL == stream_obj->stream_info) {
+        CDBG_ERROR("%s: NULL stream info for stream_id = %d",
+                    __func__, buf_info->stream_id);
+        rc = -1;
+        goto end;
+    }
+
+    if (CAM_STREAM_TYPE_METADATA == stream_obj->stream_info->stream_type) {
+        const cam_metadata_info_t *metadata;
+        metadata = (const cam_metadata_info_t *)buf_info->buf->buffer;
+
+        if (NULL == metadata) {
+            CDBG_ERROR("%s: NULL metadata buffer for metadata stream",
+                       __func__);
+            rc = -1;
+            goto end;
+        }
+
+        if (metadata->is_prep_snapshot_done_valid &&
+                metadata->is_good_frame_idx_range_valid) {
+            CDBG_ERROR("%s: prep_snapshot_done and good_idx_range shouldn't be valid at the same time", __func__);
+            rc = -1;
+            goto end;
+        }
+
+        if (metadata->is_prep_snapshot_done_valid &&
+            metadata->prep_snapshot_done_state == NEED_FUTURE_FRAME) {
+
+            /* Set expected frame id to a future frame idx, large enough to wait
+             * for good_frame_idx_range, and small enough to still capture an image */
+            const int max_future_frame_offset = 100;
+            queue->expected_frame_id += max_future_frame_offset;
+
+            mm_channel_superbuf_flush(ch_obj, queue);
+        } else if (metadata->is_good_frame_idx_range_valid) {
+            if (metadata->good_frame_idx_range.min_frame_idx >
+                queue->expected_frame_id) {
+                CDBG_HIGH("%s: min_frame_idx %d is greater than expected_frame_id %d",
+                    __func__, metadata->good_frame_idx_range.min_frame_idx,
+                    queue->expected_frame_id);
+            }
+            queue->expected_frame_id =
+                metadata->good_frame_idx_range.min_frame_idx;
+        }
+    }
+end:
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : mm_channel_superbuf_comp_and_enqueue
  *
  * DESCRIPTION: implementation for matching logic for superbuf
@@ -1414,7 +1500,7 @@
  *==========================================================================*/
 int32_t mm_channel_superbuf_comp_and_enqueue(
                         mm_channel_t* ch_obj,
-                        mm_channel_queue_t * queue,
+                        mm_channel_queue_t *queue,
                         mm_camera_buf_info_t *buf_info)
 {
     cam_node_t* node = NULL;
@@ -1434,6 +1520,10 @@
         return -1;
     }
 
+    if (mm_channel_handle_metadata(ch_obj, queue, buf_info) < 0) {
+        return -1;
+    }
+
     if (mm_channel_util_seq_comp_w_rollover(buf_info->frame_idx,
                                             queue->expected_frame_id) < 0) {
         /* incoming buf is older than expected buf id, will discard it */
@@ -1468,8 +1558,8 @@
     }
 
     if (pos == head) {
-        CDBG("%s: all nodes in queue are mtached, or no node in queue, create a new node", __func__);
-        /* all nodes in queue are mtached, or no node in queue
+        CDBG("%s: all nodes in queue are matched, or no node in queue, create a new node", __func__);
+        /* all nodes in queue are matched, or no node in queue
          * create a new node */
         mm_channel_queue_node_t *new_buf = NULL;
         cam_node_t* new_node = NULL;
@@ -1484,7 +1574,6 @@
             new_buf->super_buf[buf_s_idx] = *buf_info;
 
             /* enqueue */
-            //cam_list_add_tail_node(&node->list, &queue->que.head.list);
             cam_list_add_tail_node(&new_node->list, &queue->que.head.list);
             queue->que.size++;
 
@@ -1533,7 +1622,7 @@
                     is_new = 0;
                     break;
                 }else{
-                    //TODO: reveiw again
+                    //TODO: review again
                     break;
                 }
             }
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c b/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
index 6f5637e..7dc736b 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
@@ -329,6 +329,66 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_camera_intf_start_zsl_snapshot
+ *
+ * DESCRIPTION: start zsl snapshot
+ *
+ * PARAMETERS :
+ *   @camera_handle: camera handle
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+static int32_t mm_camera_intf_start_zsl_snapshot(uint32_t camera_handle)
+{
+    int32_t rc = -1;
+    mm_camera_obj_t * my_obj = NULL;
+
+    pthread_mutex_lock(&g_intf_lock);
+    my_obj = mm_camera_util_get_camera_by_handler(camera_handle);
+
+    if(my_obj) {
+        pthread_mutex_lock(&my_obj->cam_lock);
+        pthread_mutex_unlock(&g_intf_lock);
+        rc = mm_camera_start_zsl_snapshot(my_obj);
+    } else {
+        pthread_mutex_unlock(&g_intf_lock);
+    }
+    return rc;
+}
+
+/*===========================================================================
+ * FUNCTION   : mm_camera_intf_stop_zsl_snapshot
+ *
+ * DESCRIPTION: stop zsl snapshot
+ *
+ * PARAMETERS :
+ *   @camera_handle: camera handle
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+static int32_t mm_camera_intf_stop_zsl_snapshot(uint32_t camera_handle)
+{
+    int32_t rc = -1;
+    mm_camera_obj_t * my_obj = NULL;
+
+    pthread_mutex_lock(&g_intf_lock);
+    my_obj = mm_camera_util_get_camera_by_handler(camera_handle);
+
+    if(my_obj) {
+        pthread_mutex_lock(&my_obj->cam_lock);
+        pthread_mutex_unlock(&g_intf_lock);
+        rc = mm_camera_stop_zsl_snapshot(my_obj);
+    } else {
+        pthread_mutex_unlock(&g_intf_lock);
+    }
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : mm_camera_intf_close
  *
  * DESCRIPTION: close a camera by its handle
@@ -831,13 +891,14 @@
  * PARAMETERS :
  *   @camera_handle: camera handle
  *   @ch_id        : channel handle
+ *   @frame_idx    : frame index
  *
  * RETURN     : int32_t type of status
  *              0  -- success
  *              -1 -- failure
  *==========================================================================*/
 static int32_t mm_camera_intf_flush_super_buf_queue(uint32_t camera_handle,
-                                                    uint32_t ch_id)
+                                                    uint32_t ch_id, uint32_t frame_idx)
 {
     int32_t rc = -1;
     mm_camera_obj_t * my_obj = NULL;
@@ -850,7 +911,7 @@
     if(my_obj) {
         pthread_mutex_lock(&my_obj->cam_lock);
         pthread_mutex_unlock(&g_intf_lock);
-        rc = mm_camera_flush_super_buf_queue(my_obj, ch_id);
+        rc = mm_camera_flush_super_buf_queue(my_obj, ch_id, frame_idx);
     } else {
         pthread_mutex_unlock(&g_intf_lock);
     }
@@ -1219,6 +1280,8 @@
     .do_auto_focus = mm_camera_intf_do_auto_focus,
     .cancel_auto_focus = mm_camera_intf_cancel_auto_focus,
     .prepare_snapshot = mm_camera_intf_prepare_snapshot,
+    .start_zsl_snapshot = mm_camera_intf_start_zsl_snapshot,
+    .stop_zsl_snapshot = mm_camera_intf_stop_zsl_snapshot,
     .map_buf = mm_camera_intf_map_buf,
     .unmap_buf = mm_camera_intf_unmap_buf,
     .add_channel = mm_camera_intf_add_channel,