/*
 * Copyright (C) 2019 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 "EmulatedRequestState"
#define ATRACE_TAG ATRACE_TAG_CAMERA

#include "EmulatedRequestState.h"

#include <inttypes.h>
#include <log/log.h>
#include <utils/HWLUtils.h>

#include "EmulatedRequestProcessor.h"

namespace android {

using google_camera_hal::HwlPipelineResult;

const std::set<uint8_t> EmulatedRequestState::kSupportedCapabilites = {
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING,
    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR};

const std::set<uint8_t> EmulatedRequestState::kSupportedHWLevels = {
    ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
    ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
    ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3,
};

template <typename T>
T GetClosestValue(T val, T min, T max) {
  if ((min > max) || ((val >= min) && (val <= max))) {
    return val;
  } else if (val > max) {
    return max;
  } else {
    return min;
  }
}

status_t EmulatedRequestState::Update3AMeteringRegion(
    uint32_t tag, const HalCameraMetadata& settings, int32_t* region /*out*/) {
  if ((region == nullptr) || ((tag != ANDROID_CONTROL_AE_REGIONS) &&
                              (tag != ANDROID_CONTROL_AF_REGIONS) &&
                              (tag != ANDROID_CONTROL_AWB_REGIONS))) {
    return BAD_VALUE;
  }

  camera_metadata_ro_entry_t entry;
  auto ret = settings.Get(ANDROID_SCALER_CROP_REGION, &entry);
  if ((ret == OK) && (entry.count > 0)) {
    int32_t crop_region[4];
    crop_region[0] = entry.data.i32[0];
    crop_region[1] = entry.data.i32[1];
    crop_region[2] = entry.data.i32[2] + crop_region[0];
    crop_region[3] = entry.data.i32[3] + crop_region[1];
    ret = settings.Get(tag, &entry);
    if ((ret == OK) && (entry.count > 0)) {
      const int32_t* a_region = entry.data.i32;
      // calculate the intersection of 3A and CROP regions
      if (a_region[0] < crop_region[2] && crop_region[0] < a_region[2] &&
          a_region[1] < crop_region[3] && crop_region[1] < a_region[3]) {
        region[0] = std::max(a_region[0], crop_region[0]);
        region[1] = std::max(a_region[1], crop_region[1]);
        region[2] = std::min(a_region[2], crop_region[2]);
        region[3] = std::min(a_region[3], crop_region[3]);
        region[4] = entry.data.i32[4];
      }
    }
  }

  return OK;
}

status_t EmulatedRequestState::CompensateAE() {
  if (!exposure_compensation_supported_) {
    sensor_exposure_time_ = current_exposure_time_;
    return OK;
  }

  camera_metadata_ro_entry_t entry;
  auto ret =
      request_settings_->Get(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    exposure_compensation_ = entry.data.i32[0];
  } else {
    ALOGW("%s: AE compensation absent from request,  re-using previous value!",
          __FUNCTION__);
  }

  float ae_compensation = ::powf(
      2, exposure_compensation_ *
             ((static_cast<float>(exposure_compensation_step_.numerator) /
               exposure_compensation_step_.denominator)));

  sensor_exposure_time_ = GetClosestValue(
      static_cast<nsecs_t>(ae_compensation * current_exposure_time_),
      sensor_exposure_time_range_.first, sensor_exposure_time_range_.second);

  return OK;
}

status_t EmulatedRequestState::DoFakeAE() {
  camera_metadata_ro_entry_t entry;
  auto ret = request_settings_->Get(ANDROID_CONTROL_AE_LOCK, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    ae_lock_ = entry.data.u8[0];
  } else {
    ae_lock_ = ANDROID_CONTROL_AE_LOCK_OFF;
  }

  if (ae_lock_ == ANDROID_CONTROL_AE_LOCK_ON) {
    ae_state_ = ANDROID_CONTROL_AE_STATE_LOCKED;
    return OK;
  }

  FPSRange fps_range;
  ret = request_settings_->Get(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry);
  if ((ret == OK) && (entry.count == 2)) {
    for (const auto& it : available_fps_ranges_) {
      if ((it.min_fps == entry.data.i32[0]) &&
          (it.max_fps == entry.data.i32[1])) {
        fps_range = {entry.data.i32[0], entry.data.i32[1]};
        break;
      }
    }
    if (fps_range.max_fps == 0) {
      ALOGE("%s: Unsupported framerate range [%d, %d]", __FUNCTION__,
            entry.data.i32[0], entry.data.i32[1]);
      return BAD_VALUE;
    }
  } else {
    fps_range = *available_fps_ranges_.begin();
  }

  ret = request_settings_->Get(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    ae_trigger_ = entry.data.u8[0];
  } else {
    ae_trigger_ = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
  }

  nsecs_t min_frame_duration =
      GetClosestValue(ms2ns(1000 / fps_range.max_fps),
                      EmulatedSensor::kSupportedFrameDurationRange[0],
                      sensor_max_frame_duration_);
  nsecs_t max_frame_duration =
      GetClosestValue(ms2ns(1000 / fps_range.min_fps),
                      EmulatedSensor::kSupportedFrameDurationRange[0],
                      sensor_max_frame_duration_);
  sensor_frame_duration_ = (max_frame_duration + min_frame_duration) / 2;

  // Face priority mode usually changes the AE algorithm behavior by
  // using the regions of interest associated with detected faces.
  // Try to emulate this behavior by slightly increasing the target exposure
  // time compared to normal operation.
  if (exposure_compensation_supported_) {
    float max_ae_compensation = ::powf(
        2, exposure_compensation_range_[1] *
               ((static_cast<float>(exposure_compensation_step_.numerator) /
                 exposure_compensation_step_.denominator)));
    ae_target_exposure_time_ = GetClosestValue(
        static_cast<nsecs_t>(sensor_frame_duration_ / max_ae_compensation),
        sensor_exposure_time_range_.first, sensor_exposure_time_range_.second);
  } else if (scene_mode_ == ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY) {
    ae_target_exposure_time_ = GetClosestValue(
        sensor_frame_duration_ / 4, sensor_exposure_time_range_.first,
        sensor_exposure_time_range_.second);
  } else {
    ae_target_exposure_time_ = GetClosestValue(
        sensor_frame_duration_ / 5, sensor_exposure_time_range_.first,
        sensor_exposure_time_range_.second);
  }

  if ((ae_trigger_ == ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START) ||
      (ae_state_ == ANDROID_CONTROL_AE_STATE_PRECAPTURE)) {
    if (ae_state_ != ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
      ae_frame_counter_ = 0;
    }

    if (ae_trigger_ == ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL) {
      // Done with precapture
      ae_frame_counter_ = 0;
      ae_state_ = ANDROID_CONTROL_AE_STATE_CONVERGED;
      ae_trigger_ = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL;
    } else if ((ae_frame_counter_ > kAEPrecaptureMinFrames) &&
               (abs(ae_target_exposure_time_ - current_exposure_time_) <
                ae_target_exposure_time_ / kAETargetThreshold)) {
      // Done with precapture
      ae_frame_counter_ = 0;
      ae_state_ = ANDROID_CONTROL_AE_STATE_CONVERGED;
      ae_trigger_ = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
    } else {
      // Converge some more
      current_exposure_time_ +=
          (ae_target_exposure_time_ - current_exposure_time_) *
          kExposureTrackRate;
      ae_frame_counter_++;
      ae_state_ = ANDROID_CONTROL_AE_STATE_PRECAPTURE;
    }
  } else {
    switch (ae_state_) {
      case ANDROID_CONTROL_AE_STATE_INACTIVE:
        ae_state_ = ANDROID_CONTROL_AE_STATE_SEARCHING;
        break;
      case ANDROID_CONTROL_AE_STATE_CONVERGED:
        ae_frame_counter_++;
        if (ae_frame_counter_ > kStableAeMaxFrames) {
          float exposure_step = ((double)rand_r(&rand_seed_) / RAND_MAX) *
                                    (kExposureWanderMax - kExposureWanderMin) +
                                kExposureWanderMin;
          ae_target_exposure_time_ =
              GetClosestValue(static_cast<nsecs_t>(ae_target_exposure_time_ *
                                                   std::pow(2, exposure_step)),
                              sensor_exposure_time_range_.first,
                              sensor_exposure_time_range_.second);
          ae_state_ = ANDROID_CONTROL_AE_STATE_SEARCHING;
        }
        break;
      case ANDROID_CONTROL_AE_STATE_SEARCHING:
        current_exposure_time_ +=
            (ae_target_exposure_time_ - current_exposure_time_) *
            kExposureTrackRate;
        if (abs(ae_target_exposure_time_ - current_exposure_time_) <
            ae_target_exposure_time_ / kAETargetThreshold) {
          // Close enough
          ae_state_ = ANDROID_CONTROL_AE_STATE_CONVERGED;
          ae_frame_counter_ = 0;
        }
        break;
      case ANDROID_CONTROL_AE_STATE_LOCKED:
        ae_state_ = ANDROID_CONTROL_AE_STATE_CONVERGED;
        ae_frame_counter_ = 0;
        break;
      default:
        ALOGE("%s: Unexpected AE state %d!", __FUNCTION__, ae_state_);
        return INVALID_OPERATION;
    }
  }

  return OK;
}

status_t EmulatedRequestState::ProcessAWB() {
  if (max_awb_regions_ > 0) {
    auto ret = Update3AMeteringRegion(ANDROID_CONTROL_AWB_REGIONS,
                                      *request_settings_, awb_metering_region_);
    if (ret != OK) {
      return ret;
    }
  }
  if (((awb_mode_ == ANDROID_CONTROL_AWB_MODE_OFF) ||
       (control_mode_ == ANDROID_CONTROL_MODE_OFF)) &&
      supports_manual_post_processing_) {
    // TODO: Add actual manual support
  } else if (is_backward_compatible_) {
    camera_metadata_ro_entry_t entry;
    auto ret = request_settings_->Get(ANDROID_CONTROL_AWB_LOCK, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      awb_lock_ = entry.data.u8[0];
    } else {
      awb_lock_ = ANDROID_CONTROL_AWB_LOCK_OFF;
    }

    if (awb_lock_ == ANDROID_CONTROL_AWB_LOCK_ON) {
      awb_state_ = ANDROID_CONTROL_AWB_STATE_LOCKED;
    } else {
      awb_state_ = ANDROID_CONTROL_AWB_STATE_CONVERGED;
    }
  } else {
    // No color output support no need for AWB
  }

  return OK;
}

status_t EmulatedRequestState::ProcessAF() {
  camera_metadata_ro_entry entry;

  if (max_af_regions_ > 0) {
    auto ret = Update3AMeteringRegion(ANDROID_CONTROL_AF_REGIONS,
                                      *request_settings_, af_metering_region_);
    if (ret != OK) {
      return ret;
    }
  }
  if (af_mode_ == ANDROID_CONTROL_AF_MODE_OFF) {
    camera_metadata_ro_entry_t entry;
    auto ret = request_settings_->Get(ANDROID_LENS_FOCUS_DISTANCE, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if ((entry.data.f[0] >= 0.f) &&
          (entry.data.f[0] <= minimum_focus_distance_)) {
        focus_distance_ = entry.data.f[0];
      } else {
        ALOGE(
            "%s: Unsupported focus distance, It should be within "
            "[%5.2f, %5.2f]",
            __FUNCTION__, 0.f, minimum_focus_distance_);
      }
    }

    af_state_ = ANDROID_CONTROL_AF_STATE_INACTIVE;
    return OK;
  }

  auto ret = request_settings_->Get(ANDROID_CONTROL_AF_TRIGGER, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    af_trigger_ = entry.data.u8[0];
  } else {
    af_trigger_ = ANDROID_CONTROL_AF_TRIGGER_IDLE;
  }

  /**
   * Simulate AF triggers. Transition at most 1 state per frame.
   * - Focusing always succeeds (goes into locked, or PASSIVE_SCAN).
   */

  bool af_trigger_start = false;
  switch (af_trigger_) {
    case ANDROID_CONTROL_AF_TRIGGER_IDLE:
      break;
    case ANDROID_CONTROL_AF_TRIGGER_START:
      af_trigger_start = true;
      break;
    case ANDROID_CONTROL_AF_TRIGGER_CANCEL:
      // Cancel trigger always transitions into INACTIVE
      af_state_ = ANDROID_CONTROL_AF_STATE_INACTIVE;

      // Stay in 'inactive' until at least next frame
      return OK;
    default:
      ALOGE("%s: Unknown AF trigger value", __FUNCTION__);
      return BAD_VALUE;
  }

  // If we get down here, we're either in ANDROID_CONTROL_AF_MODE_AUTO,
  // ANDROID_CONTROL_AF_MODE_MACRO, ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
  // ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE and no other modes like
  // ANDROID_CONTROL_AF_MODE_OFF or ANDROID_CONTROL_AF_MODE_EDOF
  switch (af_state_) {
    case ANDROID_CONTROL_AF_STATE_INACTIVE:
      if (af_trigger_start) {
        switch (af_mode_) {
          case ANDROID_CONTROL_AF_MODE_AUTO:
            // fall-through
          case ANDROID_CONTROL_AF_MODE_MACRO:
            af_state_ = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
            break;
          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
            // fall-through
          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
            af_state_ = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
            break;
        }
      } else {
        // At least one frame stays in INACTIVE
        if (!af_mode_changed_) {
          switch (af_mode_) {
            case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
              // fall-through
            case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
              af_state_ = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
              break;
          }
        }
      }
      break;
    case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
      /**
       * When the AF trigger is activated, the algorithm should finish
       * its PASSIVE_SCAN if active, and then transition into AF_FOCUSED
       * or AF_NOT_FOCUSED as appropriate
       */
      if (af_trigger_start) {
        // Randomly transition to focused or not focused
        if (rand_r(&rand_seed_) % 3) {
          af_state_ = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
        } else {
          af_state_ = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
        }
      }
      /**
       * When the AF trigger is not involved, the AF algorithm should
       * start in INACTIVE state, and then transition into PASSIVE_SCAN
       * and PASSIVE_FOCUSED states
       */
      else {
        // Randomly transition to passive focus
        if (rand_r(&rand_seed_) % 3 == 0) {
          af_state_ = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
        }
      }

      break;
    case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
      if (af_trigger_start) {
        // Randomly transition to focused or not focused
        if (rand_r(&rand_seed_) % 3) {
          af_state_ = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
        } else {
          af_state_ = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
        }
      }
      // TODO: initiate passive scan (PASSIVE_SCAN)
      break;
    case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN:
      // Simulate AF sweep completing instantaneously

      // Randomly transition to focused or not focused
      if (rand_r(&rand_seed_) % 3) {
        af_state_ = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
      } else {
        af_state_ = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
      }
      break;
    case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
      if (af_trigger_start) {
        switch (af_mode_) {
          case ANDROID_CONTROL_AF_MODE_AUTO:
            // fall-through
          case ANDROID_CONTROL_AF_MODE_MACRO:
            af_state_ = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
            break;
          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
            // fall-through
          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
            // continuous autofocus => trigger start has no effect
            break;
        }
      }
      break;
    case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
      if (af_trigger_start) {
        switch (af_mode_) {
          case ANDROID_CONTROL_AF_MODE_AUTO:
            // fall-through
          case ANDROID_CONTROL_AF_MODE_MACRO:
            af_state_ = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
            break;
          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
            // fall-through
          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
            // continuous autofocus => trigger start has no effect
            break;
        }
      }
      break;
    default:
      ALOGE("%s: Bad af state %d", __FUNCTION__, af_state_);
  }

  return OK;
}

status_t EmulatedRequestState::ProcessAE() {
  if (max_ae_regions_ > 0) {
    auto ret = Update3AMeteringRegion(ANDROID_CONTROL_AE_REGIONS,
                                      *request_settings_, ae_metering_region_);
    if (ret != OK) {
      ALOGE("%s: Failed updating the 3A metering regions: %d, (%s)",
            __FUNCTION__, ret, strerror(-ret));
    }
  }

  camera_metadata_ro_entry_t entry;
  bool auto_ae_mode = false;
  bool auto_ae_flash_mode = false;
  switch (ae_mode_) {
    case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH:
    case ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH:
    case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE:
      auto_ae_flash_mode = true;
      [[fallthrough]];
    case ANDROID_CONTROL_AE_MODE_ON:
      auto_ae_mode = true;
  };
  if (((ae_mode_ == ANDROID_CONTROL_AE_MODE_OFF) ||
       (control_mode_ == ANDROID_CONTROL_MODE_OFF)) &&
      supports_manual_sensor_) {
    auto ret = request_settings_->Get(ANDROID_SENSOR_EXPOSURE_TIME, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if ((entry.data.i64[0] >= sensor_exposure_time_range_.first) &&
          (entry.data.i64[0] <= sensor_exposure_time_range_.second)) {
        sensor_exposure_time_ = entry.data.i64[0];
      } else {
        ALOGE(
            "%s: Sensor exposure time %" PRId64
            " not within supported range[%" PRId64 ", %" PRId64 "]",
            __FUNCTION__,
            entry.data.i64[0],
            sensor_exposure_time_range_.first,
            sensor_exposure_time_range_.second);
        // Use last valid value
      }
    }

    ret = request_settings_->Get(ANDROID_SENSOR_FRAME_DURATION, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if ((entry.data.i64[0] >=
           EmulatedSensor::kSupportedFrameDurationRange[0]) &&
          (entry.data.i64[0] <= sensor_max_frame_duration_)) {
        sensor_frame_duration_ = entry.data.i64[0];
      } else {
        ALOGE(
            "%s: Sensor frame duration %" PRId64
            " not within supported range[%" PRId64 ", %" PRId64 "]",
            __FUNCTION__, entry.data.i64[0],
            EmulatedSensor::kSupportedFrameDurationRange[0],
            sensor_max_frame_duration_);
        // Use last valid value
      }
    }

    if (sensor_frame_duration_ < sensor_exposure_time_) {
      sensor_frame_duration_ = sensor_exposure_time_;
    }

    ret = request_settings_->Get(ANDROID_SENSOR_SENSITIVITY, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if ((entry.data.i32[0] >= sensor_sensitivity_range_.first) &&
          (entry.data.i32[0] <= sensor_sensitivity_range_.second)) {
        sensor_sensitivity_ = entry.data.i32[0];
      } else {
        ALOGE("%s: Sensor sensitivity %d not within supported range[%d, %d]",
              __FUNCTION__, entry.data.i32[0],
              sensor_sensitivity_range_.first,
              sensor_sensitivity_range_.second);
        // Use last valid value
      }
    }
    ae_state_ = ANDROID_CONTROL_AE_STATE_INACTIVE;
  } else if (is_backward_compatible_ && auto_ae_mode) {
    auto ret = DoFakeAE();
    if (ret != OK) {
      ALOGE("%s: Failed fake AE: %d, (%s)", __FUNCTION__, ret, strerror(-ret));
    }

    // Do AE compensation on the results of the AE
    ret = CompensateAE();
    if (ret != OK) {
      ALOGE("%s: Failed during AE compensation: %d, (%s)", __FUNCTION__, ret,
            strerror(-ret));
    }
  } else {
    ALOGI(
        "%s: No emulation for current AE mode using previous sensor settings!",
        __FUNCTION__);
  }

  if (is_flash_supported_) {
    flash_state_ = ANDROID_FLASH_STATE_READY;
    // Flash fires only if the request manually enables it (SINGLE/TORCH)
    // and the appropriate AE mode is set or during still capture with auto
    // flash AE modes.
    bool manual_flash_mode = false;
    auto ret = request_settings_->Get(ANDROID_FLASH_MODE, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if ((entry.data.u8[0] == ANDROID_FLASH_MODE_SINGLE) ||
          (entry.data.u8[0] == ANDROID_FLASH_MODE_TORCH)) {
        manual_flash_mode = true;
      }
    }
    if (manual_flash_mode && !auto_ae_flash_mode) {
      flash_state_ = ANDROID_FLASH_STATE_FIRED;
    } else {
      bool is_still_capture = false;
      ret = request_settings_->Get(ANDROID_CONTROL_CAPTURE_INTENT, &entry);
      if ((ret == OK) && (entry.count == 1)) {
        if (entry.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE) {
          is_still_capture = true;
        }
      }
      if (is_still_capture && auto_ae_flash_mode) {
        flash_state_ = ANDROID_FLASH_STATE_FIRED;
      }
    }
  } else {
    flash_state_ = ANDROID_FLASH_STATE_UNAVAILABLE;
  }

  return OK;
}

status_t EmulatedRequestState::InitializeSensorSettings(
    std::unique_ptr<HalCameraMetadata> request_settings,
    EmulatedSensor::SensorSettings* sensor_settings /*out*/) {
  if ((sensor_settings == nullptr) || (request_settings.get() == nullptr)) {
    return BAD_VALUE;
  }

  std::lock_guard<std::mutex> lock(request_state_mutex_);
  request_settings_ = std::move(request_settings);
  camera_metadata_ro_entry_t entry;
  auto ret = request_settings_->Get(ANDROID_CONTROL_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_control_modes_.find(entry.data.u8[0]) !=
        available_control_modes_.end()) {
      control_mode_ = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported control mode!", __FUNCTION__);
      return BAD_VALUE;
    }
  }

  ret = request_settings_->Get(ANDROID_SENSOR_PIXEL_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_sensor_pixel_modes_.find(entry.data.u8[0]) !=
        available_sensor_pixel_modes_.end()) {
      sensor_pixel_mode_ = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported control sensor pixel  mode!", __FUNCTION__);
      return BAD_VALUE;
    }
  }

  ret = request_settings_->Get(ANDROID_CONTROL_SCENE_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    // Disabled scene is not expected to be among the available scene list
    if ((entry.data.u8[0] == ANDROID_CONTROL_SCENE_MODE_DISABLED) ||
        (available_scenes_.find(entry.data.u8[0]) != available_scenes_.end())) {
      scene_mode_ = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported scene mode!", __FUNCTION__);
      return BAD_VALUE;
    }
  }

  float min_zoom = min_zoom_, max_zoom = max_zoom_;
  ret = request_settings_->Get(ANDROID_CONTROL_EXTENDED_SCENE_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    bool extended_scene_mode_valid = false;
    for (const auto& cap : available_extended_scene_mode_caps_) {
      if (cap.mode == entry.data.u8[0]) {
        extended_scene_mode_ = entry.data.u8[0];
        min_zoom = cap.min_zoom;
        max_zoom = cap.max_zoom;
        extended_scene_mode_valid = true;
        break;
      }
    }
    if (!extended_scene_mode_valid) {
      ALOGE("%s: Unsupported extended scene mode %d!", __FUNCTION__,
            entry.data.u8[0]);
      return BAD_VALUE;
    }
    if (extended_scene_mode_ != ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) {
      scene_mode_ = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
    }
  }

  // Check zoom ratio range and override to supported range
  ret = request_settings_->Get(ANDROID_CONTROL_ZOOM_RATIO, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    zoom_ratio_ = std::min(std::max(entry.data.f[0], min_zoom), max_zoom);
  }

  // Check rotate_and_crop setting
  ret = request_settings_->Get(ANDROID_SCALER_ROTATE_AND_CROP, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_rotate_crop_modes_.find(entry.data.u8[0]) !=
        available_rotate_crop_modes_.end()) {
      rotate_and_crop_ = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported rotate and crop mode: %u", __FUNCTION__, entry.data.u8[0]);
      return BAD_VALUE;
    }
  }

  // Check video stabilization parameter
  uint8_t vstab_mode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
  ret = request_settings_->Get(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_vstab_modes_.find(entry.data.u8[0]) !=
      available_vstab_modes_.end()) {
      vstab_mode = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported video stabilization mode: %u! Video stabilization will be disabled!",
            __FUNCTION__, entry.data.u8[0]);
    }
  }

  // Check video stabilization parameter
  uint8_t edge_mode = ANDROID_EDGE_MODE_OFF;
  ret = request_settings_->Get(ANDROID_EDGE_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_edge_modes_.find(entry.data.u8[0]) !=
      available_edge_modes_.end()) {
      edge_mode = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported edge mode: %u", __FUNCTION__, entry.data.u8[0]);
      return BAD_VALUE;
    }
  }

  // Check test pattern parameter
  uint8_t test_pattern_mode = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
  ret = request_settings_->Get(ANDROID_SENSOR_TEST_PATTERN_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_test_pattern_modes_.find(entry.data.u8[0]) !=
        available_test_pattern_modes_.end()) {
      test_pattern_mode = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported test pattern mode: %u", __FUNCTION__,
            entry.data.u8[0]);
      return BAD_VALUE;
    }
  }
  uint32_t test_pattern_data[4] = {0, 0, 0, 0};
  if (test_pattern_mode == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
    ret = request_settings_->Get(ANDROID_SENSOR_TEST_PATTERN_DATA, &entry);
    if ((ret == OK) && (entry.count == 4)) {
      // 'Convert' from i32 to u32 here
      memcpy(test_pattern_data, entry.data.i32, sizeof(test_pattern_data));
    }
  }
  // BLACK is just SOLID_COLOR with all-zero data
  if (test_pattern_mode == ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) {
    test_pattern_mode = ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR;
  }

  // 3A modes are active in case the scene is disabled or set to face priority
  // or the control mode is not using scenes
  if ((scene_mode_ == ANDROID_CONTROL_SCENE_MODE_DISABLED) ||
      (scene_mode_ == ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY) ||
      (control_mode_ != ANDROID_CONTROL_MODE_USE_SCENE_MODE)) {
    ret = request_settings_->Get(ANDROID_CONTROL_AE_MODE, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if (available_ae_modes_.find(entry.data.u8[0]) !=
          available_ae_modes_.end()) {
        ae_mode_ = entry.data.u8[0];
      } else {
        ALOGE("%s: Unsupported AE mode! Using last valid mode!", __FUNCTION__);
      }
    }

    ret = request_settings_->Get(ANDROID_CONTROL_AWB_MODE, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if (available_awb_modes_.find(entry.data.u8[0]) !=
          available_awb_modes_.end()) {
        awb_mode_ = entry.data.u8[0];
      } else {
        ALOGE("%s: Unsupported AWB mode! Using last valid mode!", __FUNCTION__);
      }
    }

    ret = request_settings_->Get(ANDROID_CONTROL_AF_MODE, &entry);
    if ((ret == OK) && (entry.count == 1)) {
      if (available_af_modes_.find(entry.data.u8[0]) !=
          available_af_modes_.end()) {
        af_mode_changed_ = af_mode_ != entry.data.u8[0];
        af_mode_ = entry.data.u8[0];
      } else {
        ALOGE("%s: Unsupported AF mode! Using last valid mode!", __FUNCTION__);
      }
    }
  } else {
    auto it = scene_overrides_.find(scene_mode_);
    if (it != scene_overrides_.end()) {
      ae_mode_ = it->second.ae_mode;
      awb_mode_ = it->second.awb_mode;
      af_mode_changed_ = af_mode_ != entry.data.u8[0];
      af_mode_ = it->second.af_mode;
    } else {
      ALOGW(
          "%s: Current scene has no overrides! Using the currently active 3A "
          "modes!",
          __FUNCTION__);
    }
  }

  ret = ProcessAE();
  if (ret != OK) {
    return ret;
  }

  ret = ProcessAWB();
  if (ret != OK) {
    return ret;
  }

  ret = ProcessAF();
  if (ret != OK) {
    return ret;
  }

  ret = request_settings_->Get(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (available_lens_shading_map_modes_.find(entry.data.u8[0]) !=
        available_lens_shading_map_modes_.end()) {
      sensor_settings->lens_shading_map_mode = entry.data.u8[0];
    } else {
      ALOGE("%s: Unsupported lens shading map mode!", __FUNCTION__);
    }
  }

  sensor_settings->exposure_time = sensor_exposure_time_;
  sensor_settings->frame_duration = sensor_frame_duration_;
  sensor_settings->gain = sensor_sensitivity_;
  sensor_settings->report_neutral_color_point = report_neutral_color_point_;
  sensor_settings->report_green_split = report_green_split_;
  sensor_settings->report_noise_profile = report_noise_profile_;
  sensor_settings->zoom_ratio = zoom_ratio_;
  sensor_settings->report_rotate_and_crop = report_rotate_and_crop_;
  sensor_settings->rotate_and_crop = rotate_and_crop_;
  sensor_settings->report_video_stab = !available_vstab_modes_.empty();
  sensor_settings->video_stab = vstab_mode;
  sensor_settings->report_edge_mode = report_edge_mode_;
  sensor_settings->edge_mode = edge_mode;
  sensor_settings->sensor_pixel_mode = sensor_pixel_mode_;
  sensor_settings->test_pattern_mode = test_pattern_mode;
  memcpy(sensor_settings->test_pattern_data, test_pattern_data,
         sizeof(sensor_settings->test_pattern_data));

  return OK;
}

std::unique_ptr<HwlPipelineResult> EmulatedRequestState::InitializeResult(
    uint32_t pipeline_id, uint32_t frame_number) {
  std::lock_guard<std::mutex> lock(request_state_mutex_);
  auto result = std::make_unique<HwlPipelineResult>();
  result->camera_id = camera_id_;
  result->pipeline_id = pipeline_id;
  result->frame_number = frame_number;
  result->result_metadata = HalCameraMetadata::Clone(request_settings_.get());
  result->partial_result = partial_result_count_;

  // Results supported on all emulated devices
  result->result_metadata->Set(ANDROID_REQUEST_PIPELINE_DEPTH,
                               &max_pipeline_depth_, 1);
  result->result_metadata->Set(ANDROID_CONTROL_MODE, &control_mode_, 1);
  result->result_metadata->Set(ANDROID_SENSOR_PIXEL_MODE, &sensor_pixel_mode_,
                               1);

  result->result_metadata->Set(ANDROID_CONTROL_AF_MODE, &af_mode_, 1);
  result->result_metadata->Set(ANDROID_CONTROL_AF_STATE, &af_state_, 1);
  result->result_metadata->Set(ANDROID_CONTROL_AWB_MODE, &awb_mode_, 1);
  result->result_metadata->Set(ANDROID_CONTROL_AWB_STATE, &awb_state_, 1);
  result->result_metadata->Set(ANDROID_CONTROL_AE_MODE, &ae_mode_, 1);
  result->result_metadata->Set(ANDROID_CONTROL_AE_STATE, &ae_state_, 1);
  int32_t fps_range[] = {ae_target_fps_.min_fps, ae_target_fps_.max_fps};
  result->result_metadata->Set(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, fps_range,
                               ARRAY_SIZE(fps_range));
  result->result_metadata->Set(ANDROID_FLASH_STATE, &flash_state_, 1);
  result->result_metadata->Set(ANDROID_LENS_STATE, &lens_state_, 1);

  // Results depending on device capability and features
  if (is_backward_compatible_) {
    result->result_metadata->Set(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
                                 &ae_trigger_, 1);
    result->result_metadata->Set(ANDROID_CONTROL_AF_TRIGGER, &af_trigger_, 1);
    uint8_t vstab_mode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
    result->result_metadata->Set(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
                                 &vstab_mode, 1);
    if (exposure_compensation_supported_) {
      result->result_metadata->Set(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
                                   &exposure_compensation_, 1);
    }
  }
  if (ae_lock_available_ && report_ae_lock_) {
    result->result_metadata->Set(ANDROID_CONTROL_AE_LOCK, &ae_lock_, 1);
  }
  if (awb_lock_available_ && report_awb_lock_) {
    result->result_metadata->Set(ANDROID_CONTROL_AWB_LOCK, &awb_lock_, 1);
  }
  if (scenes_supported_) {
    result->result_metadata->Set(ANDROID_CONTROL_SCENE_MODE, &scene_mode_, 1);
  }
  if (max_ae_regions_ > 0) {
    result->result_metadata->Set(ANDROID_CONTROL_AE_REGIONS, ae_metering_region_,
                                 ARRAY_SIZE(ae_metering_region_));
  }
  if (max_awb_regions_ > 0) {
    result->result_metadata->Set(ANDROID_CONTROL_AWB_REGIONS,
                                 awb_metering_region_,
                                 ARRAY_SIZE(awb_metering_region_));
  }
  if (max_af_regions_ > 0) {
    result->result_metadata->Set(ANDROID_CONTROL_AF_REGIONS, af_metering_region_,
                                 ARRAY_SIZE(af_metering_region_));
  }
  if (report_exposure_time_) {
    result->result_metadata->Set(ANDROID_SENSOR_EXPOSURE_TIME,
                                 &sensor_exposure_time_, 1);
  }
  if (report_frame_duration_) {
    result->result_metadata->Set(ANDROID_SENSOR_FRAME_DURATION,
                                 &sensor_frame_duration_, 1);
  }
  if (report_sensitivity_) {
    result->result_metadata->Set(ANDROID_SENSOR_SENSITIVITY,
                                 &sensor_sensitivity_, 1);
  }
  if (report_rolling_shutter_skew_) {
    result->result_metadata->Set(
        ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
        &EmulatedSensor::kSupportedFrameDurationRange[0], 1);
  }
  if (report_post_raw_boost_) {
    result->result_metadata->Set(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
                                 &post_raw_boost_, 1);
  }
  if (report_focus_distance_) {
    result->result_metadata->Set(ANDROID_LENS_FOCUS_DISTANCE, &focus_distance_,
                                 1);
  }
  if (report_focus_range_) {
    float focus_range[2] = {0.f};
    if (minimum_focus_distance_ > .0f) {
      focus_range[0] = 1 / minimum_focus_distance_;
    }
    result->result_metadata->Set(ANDROID_LENS_FOCUS_RANGE, focus_range,
                                 ARRAY_SIZE(focus_range));
  }
  if (report_filter_density_) {
    result->result_metadata->Set(ANDROID_LENS_FILTER_DENSITY, &filter_density_,
                                 1);
  }
  if (report_ois_mode_) {
    result->result_metadata->Set(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
                                 &ois_mode_, 1);
  }
  if (report_pose_rotation_) {
    result->result_metadata->Set(ANDROID_LENS_POSE_ROTATION, pose_rotation_,
                                 ARRAY_SIZE(pose_rotation_));
  }
  if (report_pose_translation_) {
    result->result_metadata->Set(ANDROID_LENS_POSE_TRANSLATION,
                                 pose_translation_,
                                 ARRAY_SIZE(pose_translation_));
  }
  if (report_intrinsic_calibration_) {
    result->result_metadata->Set(ANDROID_LENS_INTRINSIC_CALIBRATION,
                                 intrinsic_calibration_,
                                 ARRAY_SIZE(intrinsic_calibration_));
  }
  if (report_distortion_) {
    result->result_metadata->Set(ANDROID_LENS_DISTORTION, distortion_,
                                 ARRAY_SIZE(distortion_));
  }
  if (report_black_level_lock_) {
    result->result_metadata->Set(ANDROID_BLACK_LEVEL_LOCK, &black_level_lock_,
                                 1);
  }
  if (report_scene_flicker_) {
    result->result_metadata->Set(ANDROID_STATISTICS_SCENE_FLICKER,
                                 &current_scene_flicker_, 1);
  }
  if (zoom_ratio_supported_) {
    result->result_metadata->Set(ANDROID_CONTROL_ZOOM_RATIO, &zoom_ratio_, 1);
    result->result_metadata->Set(ANDROID_SCALER_CROP_REGION,
                                 scaler_crop_region_default_,
                                 ARRAY_SIZE(scaler_crop_region_default_));
  }
  if (report_extended_scene_mode_) {
    result->result_metadata->Set(ANDROID_CONTROL_EXTENDED_SCENE_MODE,
                                 &extended_scene_mode_, 1);
  }
  return result;
}

bool EmulatedRequestState::SupportsCapability(uint8_t cap) {
  return available_capabilities_.find(cap) != available_capabilities_.end();
}

status_t EmulatedRequestState::InitializeSensorDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret =
      static_metadata_->Get(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE, &entry);
  if ((ret == OK) && (entry.count == 2)) {
    sensor_sensitivity_range_ =
        std::make_pair(entry.data.i32[0], entry.data.i32[1]);
  } else if (!supports_manual_sensor_) {
    sensor_sensitivity_range_ =
        std::make_pair(EmulatedSensor::kSupportedSensitivityRange[0],
                       EmulatedSensor::kSupportedSensitivityRange[1]);
  } else {
    ALOGE("%s: Manual sensor devices must advertise sensor sensitivity range!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE, &entry);
  if ((ret == OK) && (entry.count == 2)) {
    sensor_exposure_time_range_ =
        std::make_pair(entry.data.i64[0], entry.data.i64[1]);
  } else if (!supports_manual_sensor_) {
    sensor_exposure_time_range_ =
        std::make_pair(EmulatedSensor::kSupportedExposureTimeRange[0],
                       EmulatedSensor::kSupportedExposureTimeRange[1]);
  } else {
    ALOGE(
        "%s: Manual sensor devices must advertise sensor exposure time range!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    sensor_max_frame_duration_ = entry.data.i64[0];
  } else if (!supports_manual_sensor_) {
    sensor_max_frame_duration_ = EmulatedSensor::kSupportedFrameDurationRange[1];
  } else {
    ALOGE("%s: Manual sensor devices must advertise sensor max frame duration!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  if (supports_manual_sensor_) {
    if (available_requests_.find(ANDROID_SENSOR_SENSITIVITY) ==
        available_requests_.end()) {
      ALOGE(
          "%s: Sensor sensitivity must be configurable on manual sensor "
          "devices!",
          __FUNCTION__);
      return BAD_VALUE;
    }

    if (available_requests_.find(ANDROID_SENSOR_EXPOSURE_TIME) ==
        available_requests_.end()) {
      ALOGE(
          "%s: Sensor exposure time must be configurable on manual sensor "
          "devices!",
          __FUNCTION__);
      return BAD_VALUE;
    }

    if (available_requests_.find(ANDROID_SENSOR_FRAME_DURATION) ==
        available_requests_.end()) {
      ALOGE(
          "%s: Sensor frame duration must be configurable on manual sensor "
          "devices!",
          __FUNCTION__);
      return BAD_VALUE;
    }
  }

  report_rolling_shutter_skew_ =
      available_results_.find(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW) !=
      available_results_.end();
  report_sensitivity_ = available_results_.find(ANDROID_SENSOR_SENSITIVITY) !=
                        available_results_.end();
  report_exposure_time_ =
      available_results_.find(ANDROID_SENSOR_EXPOSURE_TIME) !=
      available_results_.end();
  report_frame_duration_ =
      available_results_.find(ANDROID_SENSOR_FRAME_DURATION) !=
      available_results_.end();
  report_neutral_color_point_ =
      available_results_.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT) !=
      available_results_.end();
  report_green_split_ = available_results_.find(ANDROID_SENSOR_GREEN_SPLIT) !=
                        available_results_.end();
  report_noise_profile_ =
      available_results_.find(ANDROID_SENSOR_NOISE_PROFILE) !=
      available_results_.end();

  if (is_raw_capable_ && !report_green_split_) {
    ALOGE("%s: RAW capable devices must be able to report the noise profile!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  if (is_raw_capable_ && !report_neutral_color_point_) {
    ALOGE(
        "%s: RAW capable devices must be able to report the neutral color "
        "point!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  if (is_raw_capable_ && !report_green_split_) {
    ALOGE("%s: RAW capable devices must be able to report the green split!",
          __FUNCTION__);
    return BAD_VALUE;
  }
  if (available_results_.find(ANDROID_SENSOR_TIMESTAMP) ==
      available_results_.end()) {
    ALOGE("%s: Sensor timestamp must always be part of the results!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
                              &entry);
  if (ret == OK) {
    available_test_pattern_modes_.insert(entry.data.i32,
                                         entry.data.i32 + entry.count);
  } else {
    ALOGE("%s: No available test pattern modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  sensor_exposure_time_ = GetClosestValue(EmulatedSensor::kDefaultExposureTime,
                                          sensor_exposure_time_range_.first,
                                          sensor_exposure_time_range_.second);
  sensor_frame_duration_ =
      GetClosestValue(EmulatedSensor::kDefaultFrameDuration,
                      EmulatedSensor::kSupportedFrameDurationRange[0],
                      sensor_max_frame_duration_);
  sensor_sensitivity_ = GetClosestValue(EmulatedSensor::kDefaultSensitivity,
                                        sensor_sensitivity_range_.first,
                                        sensor_sensitivity_range_.second);

  bool off_test_pattern_mode_supported =
      available_test_pattern_modes_.find(ANDROID_SENSOR_TEST_PATTERN_MODE_OFF) !=
      available_test_pattern_modes_.end();
  int32_t test_pattern_mode = (off_test_pattern_mode_supported)
                                  ? ANDROID_SENSOR_TEST_PATTERN_MODE_OFF
                                  : *available_test_pattern_modes_.begin();
  int32_t test_pattern_data[4] = {0, 0, 0, 0};

  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    default_requests_[idx]->Set(ANDROID_SENSOR_EXPOSURE_TIME,
                                &sensor_exposure_time_, 1);
    default_requests_[idx]->Set(ANDROID_SENSOR_FRAME_DURATION,
                                &sensor_frame_duration_, 1);
    default_requests_[idx]->Set(ANDROID_SENSOR_SENSITIVITY,
                                &sensor_sensitivity_, 1);
    default_requests_[idx]->Set(ANDROID_SENSOR_TEST_PATTERN_MODE,
                                &test_pattern_mode, 1);
    default_requests_[idx]->Set(ANDROID_SENSOR_TEST_PATTERN_DATA,
                                test_pattern_data, 4);
  }

  return OK;
}

status_t EmulatedRequestState::InitializeStatisticsDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(
      ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &entry);
  if (ret == OK) {
    available_face_detect_modes_.insert(entry.data.u8,
                                        entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available face detect modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(
      ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, &entry);
  if (ret == OK) {
    available_lens_shading_map_modes_.insert(entry.data.u8,
                                             entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available lens shading modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(
      ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, &entry);
  if (ret == OK) {
    available_hot_pixel_map_modes_.insert(entry.data.u8,
                                          entry.data.u8 + entry.count);
  } else if (is_raw_capable_) {
    ALOGE("%s: RAW capable device must support hot pixel map modes!",
          __FUNCTION__);
    return BAD_VALUE;
  } else {
    available_hot_pixel_map_modes_.emplace(
        ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF);
  }

  bool hot_pixel_mode_off_supported =
      available_hot_pixel_map_modes_.find(
          ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF) !=
      available_hot_pixel_map_modes_.end();
  bool face_detect_mode_off_supported =
      available_face_detect_modes_.find(
          ANDROID_STATISTICS_FACE_DETECT_MODE_OFF) !=
      available_face_detect_modes_.end();
  bool lens_shading_map_mode_off_supported =
      available_lens_shading_map_modes_.find(
          ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON) !=
      available_lens_shading_map_modes_.end();
  bool lens_shading_map_mode_on_supported =
      available_lens_shading_map_modes_.find(
          ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON) !=
      available_lens_shading_map_modes_.end();
  if (is_raw_capable_ && !lens_shading_map_mode_on_supported) {
    ALOGE("%s: RAW capable device must support lens shading map reporting!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  if (lens_shading_map_mode_on_supported &&
      (available_results_.find(ANDROID_STATISTICS_LENS_SHADING_MAP) ==
       available_results_.end())) {
    ALOGE(
        "%s: Lens shading map reporting available but corresponding result key "
        "is absent!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  if (lens_shading_map_mode_on_supported &&
      ((shading_map_size_[0] == 0) || (shading_map_size_[1] == 0))) {
    ALOGE(
        "%s: Lens shading map reporting available but without valid shading "
        "map size!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  report_scene_flicker_ =
      available_results_.find(ANDROID_STATISTICS_SCENE_FLICKER) !=
      available_results_.end();

  uint8_t face_detect_mode = face_detect_mode_off_supported
                                 ? ANDROID_STATISTICS_FACE_DETECT_MODE_OFF
                                 : *available_face_detect_modes_.begin();
  uint8_t hot_pixel_map_mode = hot_pixel_mode_off_supported
                                   ? ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF
                                   : *available_hot_pixel_map_modes_.begin();
  uint8_t lens_shading_map_mode =
      lens_shading_map_mode_off_supported
          ? ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF
          : *available_lens_shading_map_modes_.begin();
  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    if ((static_cast<RequestTemplate>(idx) == RequestTemplate::kStillCapture) &&
        is_raw_capable_ && lens_shading_map_mode_on_supported) {
      uint8_t lens_shading_map_on = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON;
      default_requests_[idx]->Set(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
                                  &lens_shading_map_on, 1);
    } else {
      default_requests_[idx]->Set(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
                                  &lens_shading_map_mode, 1);
    }

    default_requests_[idx]->Set(ANDROID_STATISTICS_FACE_DETECT_MODE,
                                &face_detect_mode, 1);
    default_requests_[idx]->Set(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
                                &hot_pixel_map_mode, 1);
  }

  return InitializeBlackLevelDefaults();
}

status_t EmulatedRequestState::InitializeControlSceneDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret =
      static_metadata_->Get(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, &entry);
  if (ret == OK) {
    available_scenes_.insert(entry.data.u8, entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available scene modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  if ((entry.count == 1) &&
      (entry.data.u8[0] == ANDROID_CONTROL_SCENE_MODE_DISABLED)) {
    scenes_supported_ = false;
    return OK;
  } else {
    scenes_supported_ = true;
  }

  if (available_requests_.find(ANDROID_CONTROL_SCENE_MODE) ==
      available_requests_.end()) {
    ALOGE("%s: Scene mode cannot be set!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_SCENE_MODE) ==
      available_results_.end()) {
    ALOGE("%s: Scene mode cannot be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  camera_metadata_ro_entry_t overrides_entry;
  ret = static_metadata_->Get(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
                              &overrides_entry);
  if ((ret == OK) && ((overrides_entry.count / 3) == available_scenes_.size()) &&
      ((overrides_entry.count % 3) == 0)) {
    for (size_t i = 0; i < entry.count; i++) {
      SceneOverride scene(overrides_entry.data.u8[i*3],
                          overrides_entry.data.u8[i*3 + 1],
                          overrides_entry.data.u8[i*3 + 2]);
      if (available_ae_modes_.find(scene.ae_mode) == available_ae_modes_.end()) {
        ALOGE("%s: AE scene mode override: %d not supported!", __FUNCTION__,
              scene.ae_mode);
        return BAD_VALUE;
      }
      if (available_awb_modes_.find(scene.awb_mode) ==
          available_awb_modes_.end()) {
        ALOGE("%s: AWB scene mode override: %d not supported!", __FUNCTION__,
              scene.awb_mode);
        return BAD_VALUE;
      }
      if (available_af_modes_.find(scene.af_mode) == available_af_modes_.end()) {
        ALOGE("%s: AF scene mode override: %d not supported!", __FUNCTION__,
              scene.af_mode);
        return BAD_VALUE;
      }
      scene_overrides_.emplace(entry.data.u8[i], scene);
    }
  } else {
    ALOGE("%s: No available scene overrides!", __FUNCTION__);
    return BAD_VALUE;
  }

  return OK;
}

status_t EmulatedRequestState::InitializeControlAFDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(ANDROID_CONTROL_AF_AVAILABLE_MODES, &entry);
  if (ret == OK) {
    available_af_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available AF modes!", __FUNCTION__);
    return BAD_VALUE;
  }
  // Off mode must always be present
  if (available_af_modes_.find(ANDROID_CONTROL_AF_MODE_OFF) ==
      available_af_modes_.end()) {
    ALOGE("%s: AF off control mode must always be present!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_requests_.find(ANDROID_CONTROL_AF_MODE) ==
      available_requests_.end()) {
    ALOGE("%s: Clients must be able to set AF mode!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_requests_.find(ANDROID_CONTROL_AF_TRIGGER) ==
      available_requests_.end()) {
    ALOGE("%s: Clients must be able to set AF trigger!", __FUNCTION__);
    return BAD_VALUE;
  }
  if (available_results_.find(ANDROID_CONTROL_AF_TRIGGER) ==
      available_results_.end()) {
    ALOGE("%s: AF trigger must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AF_MODE) ==
      available_results_.end()) {
    ALOGE("%s: AF mode must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AF_STATE) ==
      available_results_.end()) {
    ALOGE("%s: AF state must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  bool auto_mode_present =
      available_af_modes_.find(ANDROID_CONTROL_AF_MODE_AUTO) !=
      available_af_modes_.end();
  bool picture_caf_mode_present =
      available_af_modes_.find(ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE) !=
      available_af_modes_.end();
  bool video_caf_mode_present =
      available_af_modes_.find(ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO) !=
      available_af_modes_.end();
  af_supported_ = auto_mode_present && (minimum_focus_distance_ > .0f);
  picture_caf_supported_ =
      picture_caf_mode_present && (minimum_focus_distance_ > .0f);
  video_caf_supported_ =
      video_caf_mode_present && (minimum_focus_distance_ > .0f);

  return OK;
}

status_t EmulatedRequestState::InitializeControlAWBDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(ANDROID_CONTROL_AWB_AVAILABLE_MODES, &entry);
  if (ret == OK) {
    available_awb_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available AWB modes!", __FUNCTION__);
    return BAD_VALUE;
  }
  // Auto mode must always be present
  if (available_awb_modes_.find(ANDROID_CONTROL_AWB_MODE_AUTO) ==
      available_awb_modes_.end()) {
    ALOGE("%s: AWB auto control mode must always be present!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AWB_MODE) ==
      available_results_.end()) {
    ALOGE("%s: AWB mode must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AWB_STATE) ==
      available_results_.end()) {
    ALOGE("%s: AWB state must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    awb_lock_available_ =
        entry.data.u8[0] == ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
  } else {
    ALOGV("%s: No available AWB lock!", __FUNCTION__);
    awb_lock_available_ = false;
  }
  report_awb_lock_ = available_results_.find(ANDROID_CONTROL_AWB_LOCK) !=
                     available_results_.end();

  return OK;
}

status_t EmulatedRequestState::InitializeBlackLevelDefaults() {
  if (is_level_full_or_higher_) {
    if (available_requests_.find(ANDROID_BLACK_LEVEL_LOCK) ==
        available_requests_.end()) {
      ALOGE(
          "%s: Full or above capable devices must be able to set the black "
          "level lock!",
          __FUNCTION__);
      return BAD_VALUE;
    }

    if (available_results_.find(ANDROID_BLACK_LEVEL_LOCK) ==
        available_results_.end()) {
      ALOGE(
          "%s: Full or above capable devices must be able to report the black "
          "level lock!",
          __FUNCTION__);
      return BAD_VALUE;
    }

    report_black_level_lock_ = true;
    uint8_t blackLevelLock = ANDROID_BLACK_LEVEL_LOCK_OFF;
    for (size_t idx = 0; idx < kTemplateCount; idx++) {
      if (default_requests_[idx].get() == nullptr) {
        continue;
      }

      default_requests_[idx]->Set(ANDROID_BLACK_LEVEL_LOCK, &blackLevelLock, 1);
    }
  }

  return InitializeEdgeDefaults();
}

status_t EmulatedRequestState::InitializeControlAEDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(ANDROID_CONTROL_AE_AVAILABLE_MODES, &entry);
  if (ret == OK) {
    available_ae_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available AE modes!", __FUNCTION__);
    return BAD_VALUE;
  }
  // On mode must always be present
  if (available_ae_modes_.find(ANDROID_CONTROL_AE_MODE_ON) ==
      available_ae_modes_.end()) {
    ALOGE("%s: AE on control mode must always be present!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AE_MODE) ==
      available_results_.end()) {
    ALOGE("%s: AE mode must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AE_STATE) ==
      available_results_.end()) {
    ALOGE("%s: AE state must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    ae_lock_available_ =
        entry.data.u8[0] == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
  } else {
    ALOGV("%s: No available AE lock!", __FUNCTION__);
    ae_lock_available_ = false;
  }
  report_ae_lock_ = available_results_.find(ANDROID_CONTROL_AE_LOCK) !=
                    available_results_.end();

  if (supports_manual_sensor_) {
    if (!ae_lock_available_) {
      ALOGE("%s: AE lock must always be available for manual sensors!",
            __FUNCTION__);
      return BAD_VALUE;
    }
    auto off_mode = available_control_modes_.find(ANDROID_CONTROL_MODE_OFF);
    if (off_mode == available_control_modes_.end()) {
      ALOGE("%s: Off control mode must always be present for manual sensors!",
            __FUNCTION__);
      return BAD_VALUE;
    }

    off_mode = available_ae_modes_.find(ANDROID_CONTROL_AE_MODE_OFF);
    if (off_mode == available_ae_modes_.end()) {
      ALOGE(
          "%s: AE off control mode must always be present for manual sensors!",
          __FUNCTION__);
      return BAD_VALUE;
    }
  }

  if (available_requests_.find(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER) ==
      available_requests_.end()) {
    ALOGE("%s: Clients must be able to set AE pre-capture trigger!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER) ==
      available_results_.end()) {
    ALOGE("%s: AE pre-capture trigger must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
                              &entry);
  if (ret == OK) {
    available_antibanding_modes_.insert(entry.data.u8,
                                        entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available antibanding modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_CONTROL_AE_COMPENSATION_RANGE, &entry);
  if ((ret == OK) && (entry.count == 2)) {
    exposure_compensation_range_[0] = entry.data.i32[0];
    exposure_compensation_range_[1] = entry.data.i32[1];
  } else {
    ALOGE("%s: No available exposure compensation range!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_CONTROL_AE_COMPENSATION_STEP, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    exposure_compensation_step_ = entry.data.r[0];
  } else {
    ALOGE("%s: No available exposure compensation step!", __FUNCTION__);
    return BAD_VALUE;
  }

  bool ae_comp_requests =
      available_requests_.find(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION) !=
      available_requests_.end();
  bool ae_comp_results =
      available_results_.find(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION) !=
      available_results_.end();
  exposure_compensation_supported_ =
      ((exposure_compensation_range_[0] < 0) &&
       (exposure_compensation_range_[1] > 0) &&
       (exposure_compensation_step_.denominator > 0) &&
       (exposure_compensation_step_.numerator > 0)) &&
      ae_comp_results && ae_comp_requests;

  return OK;
}

status_t EmulatedRequestState::InitializeMeteringRegionDefault(
    uint32_t tag, int32_t* region /*out*/) {
  if (region == nullptr) {
    return BAD_VALUE;
  }
  if (available_requests_.find(tag) == available_requests_.end()) {
    ALOGE("%s: %d metering region configuration must be supported!",
          __FUNCTION__, tag);
    return BAD_VALUE;
  }
  if (available_results_.find(tag) == available_results_.end()) {
    ALOGE("%s: %d metering region must be reported!", __FUNCTION__, tag);
    return BAD_VALUE;
  }

  region[0] = scaler_crop_region_default_[0];
  region[1] = scaler_crop_region_default_[1];
  region[2] = scaler_crop_region_default_[2];
  region[3] = scaler_crop_region_default_[3];
  region[4] = 0;

  return OK;
}

status_t EmulatedRequestState::InitializeControlDefaults() {
  camera_metadata_ro_entry_t entry;
  int32_t metering_area[5] = {0};  // (top, left, width, height, wight)
  auto ret = static_metadata_->Get(ANDROID_CONTROL_AVAILABLE_MODES, &entry);
  if (ret == OK) {
    available_control_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available control modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  available_sensor_pixel_modes_.insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);

  if (SupportsCapability(
          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR)) {
    available_sensor_pixel_modes_.insert(
        ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
  }

  // Auto mode must always be present
  if (available_control_modes_.find(ANDROID_CONTROL_MODE_AUTO) ==
      available_control_modes_.end()) {
    ALOGE("%s: Auto control modes must always be present!", __FUNCTION__);
    return BAD_VALUE;
  }

  // Capture intent must always be user configurable
  if (available_requests_.find(ANDROID_CONTROL_CAPTURE_INTENT) ==
      available_requests_.end()) {
    ALOGE("%s: Clients must be able to set the capture intent!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
                              &entry);
  if ((ret == OK) && ((entry.count % 2) == 0)) {
    available_fps_ranges_.reserve(entry.count / 2);
    for (size_t i = 0; i < entry.count; i += 2) {
      FPSRange range(entry.data.i32[i], entry.data.i32[i + 1]);
      if (range.min_fps > range.max_fps) {
        ALOGE("%s: Mininum framerate: %d bigger than maximum framerate: %d",
              __FUNCTION__, range.min_fps, range.max_fps);
        return BAD_VALUE;
      }
      if ((range.max_fps >= kMinimumStreamingFPS) &&
          (range.max_fps == range.min_fps) && (ae_target_fps_.max_fps == 0)) {
        ae_target_fps_ = range;
      }
      available_fps_ranges_.push_back(range);
    }
  } else {
    ALOGE("%s: No available framerate ranges!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (ae_target_fps_.max_fps == 0) {
    ALOGE("%s: No minimum streaming capable framerate range available!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_requests_.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE) ==
      available_requests_.end()) {
    ALOGE("%s: Clients must be able to set the target framerate range!",
          __FUNCTION__);
    return BAD_VALUE;
  }

  if (available_results_.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE) ==
      available_results_.end()) {
    ALOGE("%s: Target framerate must be reported!", __FUNCTION__);
    return BAD_VALUE;
  }

  report_extended_scene_mode_ =
      available_results_.find(ANDROID_CONTROL_EXTENDED_SCENE_MODE) !=
      available_results_.end();

  if (is_backward_compatible_) {
    ret = static_metadata_->Get(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
                                &entry);
    if (ret == OK) {
      post_raw_boost_ = entry.data.i32[0];
    } else {
      ALOGW("%s: No available post RAW boost! Setting default!", __FUNCTION__);
      post_raw_boost_ = 100;
    }
    report_post_raw_boost_ =
        available_results_.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST) !=
        available_results_.end();

    ret = static_metadata_->Get(ANDROID_CONTROL_AVAILABLE_EFFECTS, &entry);
    if ((ret == OK) && (entry.count > 0)) {
      available_effects_.insert(entry.data.u8, entry.data.u8 + entry.count);
      if (available_effects_.find(ANDROID_CONTROL_EFFECT_MODE_OFF) ==
          available_effects_.end()) {
        ALOGE("%s: Off color effect mode not supported!", __FUNCTION__);
        return BAD_VALUE;
      }
    } else {
      ALOGE("%s: No available effects!", __FUNCTION__);
      return BAD_VALUE;
    }

    ret = static_metadata_->Get(
        ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, &entry);
    if ((ret == OK) && (entry.count > 0)) {
      available_vstab_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
      if (available_vstab_modes_.find(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF) ==
        available_vstab_modes_.end()) {
        ALOGE("%s: Off video stabilization mode not supported!", __FUNCTION__);
        return BAD_VALUE;
      }
      if (available_vstab_modes_.find(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON) !=
        available_vstab_modes_.end()) {
        vstab_available_ = true;
      }
    } else {
      ALOGE("%s: No available video stabilization modes!", __FUNCTION__);
      return BAD_VALUE;
    }

    ret = static_metadata_->Get(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
                                &entry);
    if ((ret == OK) && (entry.count > 0)) {
      if (entry.count != 1) {
        ALOGE("%s: Invalid max digital zoom capability!", __FUNCTION__);
        return BAD_VALUE;
      }
      max_zoom_ = entry.data.f[0];
    } else {
      ALOGE("%s: No available max digital zoom", __FUNCTION__);
      return BAD_VALUE;
    }

    ret = static_metadata_->Get(ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
    if ((ret == OK) && (entry.count > 0)) {
      if (entry.count != 2) {
        ALOGE("%s: Invalid zoom ratio range capability!", __FUNCTION__);
        return BAD_VALUE;
      }

      if (entry.data.f[1] != max_zoom_) {
        ALOGE("%s: Max zoom ratio must be equal to max digital zoom",
              __FUNCTION__);
        return BAD_VALUE;
      }

      if (entry.data.f[1] < entry.data.f[0]) {
        ALOGE("%s: Max zoom ratio must be larger than min zoom ratio",
              __FUNCTION__);
        return BAD_VALUE;
      }

      // Sanity check request and result keys
      if (available_requests_.find(ANDROID_CONTROL_ZOOM_RATIO) ==
          available_requests_.end()) {
        ALOGE("%s: Zoom ratio tag must be available in available request keys",
              __FUNCTION__);
        return BAD_VALUE;
      }
      if (available_results_.find(ANDROID_CONTROL_ZOOM_RATIO) ==
          available_results_.end()) {
        ALOGE("%s: Zoom ratio tag must be available in available result keys",
              __FUNCTION__);
        return BAD_VALUE;
      }

      zoom_ratio_supported_ = true;
      min_zoom_ = entry.data.f[0];
    }

    ret = static_metadata_->Get(
        ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES, &entry);
    if ((ret == OK) && (entry.count > 0)) {
      if (entry.count % 3 != 0) {
        ALOGE("%s: Invalid bokeh capabilities!", __FUNCTION__);
        return BAD_VALUE;
      }

      camera_metadata_ro_entry_t zoom_ratio_ranges_entry;
      ret = static_metadata_->Get(
          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
          &zoom_ratio_ranges_entry);
      if (ret != OK ||
          zoom_ratio_ranges_entry.count / 2 != entry.count / 3 - 1) {
        ALOGE("%s: Invalid bokeh mode zoom ratio ranges.", __FUNCTION__);
        return BAD_VALUE;
      }

      // Sanity check request and characteristics keys
      if (available_requests_.find(ANDROID_CONTROL_EXTENDED_SCENE_MODE) ==
          available_requests_.end()) {
        ALOGE("%s: Extended scene mode must be configurable for this device",
              __FUNCTION__);
        return BAD_VALUE;
      }
      if (available_characteristics_.find(
              ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES) ==
              available_characteristics_.end() ||
          available_characteristics_.find(
              ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES) ==
              available_characteristics_.end()) {
        ALOGE(
            "%s: ExtendedSceneMode maxSizes and zoomRatioRanges "
            "characteristics keys must "
            "be available",
            __FUNCTION__);
        return BAD_VALUE;
      }

      // Derive available bokeh caps.
      StreamConfigurationMap stream_configuration_map(*static_metadata_);
      std::set<StreamSize> yuv_sizes = stream_configuration_map.GetOutputSizes(
          HAL_PIXEL_FORMAT_YCBCR_420_888);
      bool has_extended_scene_mode_off = false;
      for (size_t i = 0, j = 0; i < entry.count; i += 3) {
        int32_t mode = entry.data.i32[i];
        int32_t max_width = entry.data.i32[i + 1];
        int32_t max_height = entry.data.i32[i + 2];
        float min_zoom_ratio, max_zoom_ratio;

        if (mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED ||
            (mode > ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS &&
             mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START)) {
          ALOGE("%s: Invalid extended scene mode %d", __FUNCTION__, mode);
          return BAD_VALUE;
        }

        if (mode == ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) {
          has_extended_scene_mode_off = true;
          if (max_width != 0 || max_height != 0) {
            ALOGE(
                "%s: Invalid max width or height for "
                "EXTENDED_SCENE_MODE_DISABLED",
                __FUNCTION__);
            return BAD_VALUE;
          }
          min_zoom_ratio = min_zoom_;
          max_zoom_ratio = max_zoom_;
        } else if (yuv_sizes.find({max_width, max_height}) == yuv_sizes.end()) {
          ALOGE("%s: Invalid max width or height for extended scene mode %d",
                __FUNCTION__, mode);
          return BAD_VALUE;
        } else {
          min_zoom_ratio = zoom_ratio_ranges_entry.data.f[j];
          max_zoom_ratio = zoom_ratio_ranges_entry.data.f[j + 1];
          j += 2;
        }

        ExtendedSceneModeCapability cap(mode, max_width, max_height,
                                        min_zoom_ratio, max_zoom_ratio);
        available_extended_scene_mode_caps_.push_back(cap);
      }
      if (!has_extended_scene_mode_off) {
        ALOGE("%s: Off extended scene mode not supported!", __FUNCTION__);
        return BAD_VALUE;
      }
    }

    ret = static_metadata_->Get(ANDROID_CONTROL_MAX_REGIONS, &entry);
    if ((ret == OK) && (entry.count == 3)) {
      max_ae_regions_ = entry.data.i32[0];
      max_awb_regions_ = entry.data.i32[1];
      max_af_regions_ = entry.data.i32[2];
    } else {
      ALOGE(
          "%s: Metering regions must be available for backward compatible "
          "devices!",
          __FUNCTION__);
      return BAD_VALUE;
    }

    if ((is_level_full_or_higher_) &&
        ((max_ae_regions_ == 0) || (max_af_regions_ == 0))) {
      ALOGE(
          "%s: Full and higher level cameras must support at AF and AE "
          "metering regions",
          __FUNCTION__);
      return BAD_VALUE;
    }

    if (max_ae_regions_ > 0) {
      ret = InitializeMeteringRegionDefault(ANDROID_CONTROL_AE_REGIONS,
                                            ae_metering_region_);
      if (ret != OK) {
        return ret;
      }
    }

    if (max_awb_regions_ > 0) {
      ret = InitializeMeteringRegionDefault(ANDROID_CONTROL_AWB_REGIONS,
                                            awb_metering_region_);
      if (ret != OK) {
        return ret;
      }
    }

    if (max_af_regions_ > 0) {
      ret = InitializeMeteringRegionDefault(ANDROID_CONTROL_AF_REGIONS,
                                            af_metering_region_);
      if (ret != OK) {
        return ret;
      }
    }

    ret = InitializeControlAEDefaults();
    if (ret != OK) {
      return ret;
    }

    ret = InitializeControlAWBDefaults();
    if (ret != OK) {
      return ret;
    }

    ret = InitializeControlAFDefaults();
    if (ret != OK) {
      return ret;
    }

    ret = InitializeControlSceneDefaults();
    if (ret != OK) {
      return ret;
    }
  }

  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    auto template_idx = static_cast<RequestTemplate>(idx);
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    uint8_t intent = ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM;
    uint8_t control_mode, ae_mode, awb_mode, af_mode, scene_mode, vstab_mode;
    control_mode = ANDROID_CONTROL_MODE_AUTO;
    ae_mode = ANDROID_CONTROL_AE_MODE_ON;
    awb_mode = ANDROID_CONTROL_AWB_MODE_AUTO;
    af_mode = af_supported_ ? ANDROID_CONTROL_AF_MODE_AUTO
                            : ANDROID_CONTROL_AF_MODE_OFF;
    scene_mode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
    vstab_mode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
    uint8_t effect_mode = ANDROID_CONTROL_EFFECT_MODE_OFF;
    uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
    uint8_t awb_lock = ANDROID_CONTROL_AWB_LOCK_OFF;
    int32_t ae_target_fps[] = {ae_target_fps_.min_fps, ae_target_fps_.max_fps};
    float zoom_ratio = 1.0f;
    switch (template_idx) {
      case RequestTemplate::kManual:
        intent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;
        control_mode = ANDROID_CONTROL_MODE_OFF;
        ae_mode = ANDROID_CONTROL_AE_MODE_OFF;
        awb_mode = ANDROID_CONTROL_AWB_MODE_OFF;
        af_mode = ANDROID_CONTROL_AF_MODE_OFF;
        break;
      case RequestTemplate::kZeroShutterLag:
        intent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
        if (picture_caf_supported_) {
          af_mode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
        }
        break;
      case RequestTemplate::kPreview:
        intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
        if (picture_caf_supported_) {
          af_mode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
        }
        break;
      case RequestTemplate::kStillCapture:
        intent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
        if (picture_caf_supported_) {
          af_mode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
        }
        break;
      case RequestTemplate::kVideoRecord:
        intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
        if (video_caf_supported_) {
          af_mode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
        }
        if (vstab_available_) {
          vstab_mode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON;
        }
        break;
      case RequestTemplate::kVideoSnapshot:
        intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
        if (video_caf_supported_) {
          af_mode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
        }
        if (vstab_available_) {
          vstab_mode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON;
        }
        break;
      default:
        // Noop
        break;
    }

    if (intent != ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM) {
      default_requests_[idx]->Set(ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
      default_requests_[idx]->Set(ANDROID_CONTROL_MODE, &control_mode, 1);
      default_requests_[idx]->Set(ANDROID_CONTROL_AE_MODE, &ae_mode, 1);
      default_requests_[idx]->Set(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
                                  ae_target_fps, ARRAY_SIZE(ae_target_fps));
      default_requests_[idx]->Set(ANDROID_CONTROL_AWB_MODE, &awb_mode, 1);
      default_requests_[idx]->Set(ANDROID_CONTROL_AF_MODE, &af_mode, 1);
      if (is_backward_compatible_) {
        default_requests_[idx]->Set(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
                                    &post_raw_boost_, 1);
        if (vstab_available_) {
          default_requests_[idx]->Set(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
                                      &vstab_mode, 1);
        }
        if (ae_lock_available_) {
          default_requests_[idx]->Set(ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
        }
        if (awb_lock_available_) {
          default_requests_[idx]->Set(ANDROID_CONTROL_AWB_LOCK, &awb_lock, 1);
        }
        if (scenes_supported_) {
          default_requests_[idx]->Set(ANDROID_CONTROL_SCENE_MODE, &scene_mode,
                                      1);
        }
        if (max_ae_regions_ > 0) {
          default_requests_[idx]->Set(ANDROID_CONTROL_AE_REGIONS, metering_area,
                                      ARRAY_SIZE(metering_area));
        }
        if (max_awb_regions_ > 0) {
          default_requests_[idx]->Set(ANDROID_CONTROL_AWB_REGIONS,
                                      metering_area, ARRAY_SIZE(metering_area));
        }
        if (max_af_regions_ > 0) {
          default_requests_[idx]->Set(ANDROID_CONTROL_AF_REGIONS, metering_area,
                                      ARRAY_SIZE(metering_area));
        }
        if (exposure_compensation_supported_) {
          default_requests_[idx]->Set(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
                                      &exposure_compensation_, 1);
        }
        if (zoom_ratio_supported_) {
          default_requests_[idx]->Set(ANDROID_CONTROL_ZOOM_RATIO, &zoom_ratio,
                                      1);
        }
        bool is_auto_antbanding_supported =
            available_antibanding_modes_.find(
                ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO) !=
            available_antibanding_modes_.end();
        uint8_t antibanding_mode = is_auto_antbanding_supported
                                       ? ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO
                                       : *available_antibanding_modes_.begin();
        default_requests_[idx]->Set(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
                                    &antibanding_mode, 1);
        default_requests_[idx]->Set(ANDROID_CONTROL_EFFECT_MODE, &effect_mode,
                                    1);
        uint8_t ae_trigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
        default_requests_[idx]->Set(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
                                    &ae_trigger, 1);
        uint8_t af_trigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
        default_requests_[idx]->Set(ANDROID_CONTROL_AF_TRIGGER, &af_trigger, 1);
      }
    }
  }

  return InitializeHotPixelDefaults();
}

status_t EmulatedRequestState::InitializeTonemapDefaults() {
  if (is_backward_compatible_) {
    camera_metadata_ro_entry_t entry;
    auto ret =
        static_metadata_->Get(ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES, &entry);
    if (ret == OK) {
      available_tonemap_modes_.insert(entry.data.u8,
                                      entry.data.u8 + entry.count);
    } else {
      ALOGE("%s: No available tonemap modes!", __FUNCTION__);
      return BAD_VALUE;
    }

    if ((is_level_full_or_higher_) && (available_tonemap_modes_.size() < 3)) {
      ALOGE(
          "%s: Full and higher level cameras must support at least three or "
          "more tonemap modes",
          __FUNCTION__);
      return BAD_VALUE;
    }

    bool fast_mode_supported =
        available_tonemap_modes_.find(ANDROID_TONEMAP_MODE_FAST) !=
        available_tonemap_modes_.end();
    bool hq_mode_supported =
        available_tonemap_modes_.find(ANDROID_TONEMAP_MODE_HIGH_QUALITY) !=
        available_tonemap_modes_.end();
    uint8_t tonemap_mode = *available_tonemap_modes_.begin();
    for (size_t idx = 0; idx < kTemplateCount; idx++) {
      if (default_requests_[idx].get() == nullptr) {
        continue;
      }

      switch (static_cast<RequestTemplate>(idx)) {
        case RequestTemplate::kVideoRecord:  // Pass-through
        case RequestTemplate::kPreview:
          if (fast_mode_supported) {
            tonemap_mode = ANDROID_TONEMAP_MODE_FAST;
          }
          break;
        case RequestTemplate::kVideoSnapshot:  // Pass-through
        case RequestTemplate::kStillCapture:
          if (hq_mode_supported) {
            tonemap_mode = ANDROID_TONEMAP_MODE_HIGH_QUALITY;
          }
          break;
        default:
          // Noop
          break;
      }

      default_requests_[idx]->Set(ANDROID_TONEMAP_MODE, &tonemap_mode, 1);
      default_requests_[idx]->Set(
          ANDROID_TONEMAP_CURVE_RED, EmulatedSensor::kDefaultToneMapCurveRed,
          ARRAY_SIZE(EmulatedSensor::kDefaultToneMapCurveRed));
      default_requests_[idx]->Set(
          ANDROID_TONEMAP_CURVE_GREEN, EmulatedSensor::kDefaultToneMapCurveGreen,
          ARRAY_SIZE(EmulatedSensor::kDefaultToneMapCurveGreen));
      default_requests_[idx]->Set(
          ANDROID_TONEMAP_CURVE_BLUE, EmulatedSensor::kDefaultToneMapCurveBlue,
          ARRAY_SIZE(EmulatedSensor::kDefaultToneMapCurveBlue));
    }
  }

  return InitializeStatisticsDefaults();
}

status_t EmulatedRequestState::InitializeEdgeDefaults() {
  if (is_backward_compatible_) {
    camera_metadata_ro_entry_t entry;
    auto ret = static_metadata_->Get(ANDROID_EDGE_AVAILABLE_EDGE_MODES, &entry);
    if (ret == OK) {
      available_edge_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
    } else {
      ALOGE("%s: No available edge modes!", __FUNCTION__);
      return BAD_VALUE;
    }

    report_edge_mode_ = available_results_.find(ANDROID_EDGE_MODE) != available_results_.end();
    bool is_fast_mode_supported =
        available_edge_modes_.find(ANDROID_EDGE_MODE_FAST) !=
        available_edge_modes_.end();
    bool is_hq_mode_supported =
        available_edge_modes_.find(ANDROID_EDGE_MODE_HIGH_QUALITY) !=
        available_edge_modes_.end();
    bool is_zsl_mode_supported =
        available_edge_modes_.find(ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG) !=
        available_edge_modes_.end();
    uint8_t edge_mode = *available_ae_modes_.begin();
    for (size_t idx = 0; idx < kTemplateCount; idx++) {
      if (default_requests_[idx].get() == nullptr) {
        continue;
      }

      switch (static_cast<RequestTemplate>(idx)) {
        case RequestTemplate::kVideoRecord:  // Pass-through
        case RequestTemplate::kPreview:
          if (is_fast_mode_supported) {
            edge_mode = ANDROID_EDGE_MODE_FAST;
          }
          break;
        case RequestTemplate::kVideoSnapshot:  // Pass-through
        case RequestTemplate::kStillCapture:
          if (is_hq_mode_supported) {
            edge_mode = ANDROID_EDGE_MODE_HIGH_QUALITY;
          }
          break;
        case RequestTemplate::kZeroShutterLag:
          if (is_zsl_mode_supported) {
            edge_mode = ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG;
          }
          break;
        default:
          // Noop
          break;
      }

      default_requests_[idx]->Set(ANDROID_EDGE_MODE, &edge_mode, 1);
    }
  }

  return InitializeShadingDefaults();
}

status_t EmulatedRequestState::InitializeColorCorrectionDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(
      ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, &entry);
  if (ret == OK) {
    available_color_aberration_modes_.insert(entry.data.u8,
                                             entry.data.u8 + entry.count);
  } else if (supports_manual_post_processing_) {
    ALOGE(
        "%s: Devices capable of manual post-processing must support color "
        "abberation!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  if (!available_color_aberration_modes_.empty()) {
    bool is_fast_mode_supported =
        available_color_aberration_modes_.find(
            ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST) !=
        available_color_aberration_modes_.end();
    bool is_hq_mode_supported =
        available_color_aberration_modes_.find(
            ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY) !=
        available_color_aberration_modes_.end();
    uint8_t color_aberration = *available_color_aberration_modes_.begin();
    uint8_t color_correction_mode = ANDROID_COLOR_CORRECTION_MODE_FAST;
    for (size_t idx = 0; idx < kTemplateCount; idx++) {
      if (default_requests_[idx].get() == nullptr) {
        continue;
      }

      switch (static_cast<RequestTemplate>(idx)) {
        case RequestTemplate::kVideoRecord:  // Pass-through
        case RequestTemplate::kPreview:
          if (is_fast_mode_supported) {
            color_aberration = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST;
          }
          break;
        case RequestTemplate::kVideoSnapshot:  // Pass-through
        case RequestTemplate::kStillCapture:
          if (is_hq_mode_supported) {
            color_aberration =
                ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY;
          }
          break;
        default:
          // Noop
          break;
      }

      default_requests_[idx]->Set(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
                                  &color_aberration, 1);
      if (is_backward_compatible_) {
        default_requests_[idx]->Set(ANDROID_COLOR_CORRECTION_MODE,
                                    &color_correction_mode, 1);
        default_requests_[idx]->Set(
            ANDROID_COLOR_CORRECTION_TRANSFORM,
            EmulatedSensor::kDefaultColorTransform,
            ARRAY_SIZE(EmulatedSensor::kDefaultColorTransform));
        default_requests_[idx]->Set(
            ANDROID_COLOR_CORRECTION_GAINS,
            EmulatedSensor::kDefaultColorCorrectionGains,
            ARRAY_SIZE(EmulatedSensor::kDefaultColorCorrectionGains));
      }
    }
  }

  return InitializeSensorDefaults();
}

status_t EmulatedRequestState::InitializeScalerDefaults() {
  if (is_backward_compatible_) {
    camera_metadata_ro_entry_t entry;
    auto ret =
        static_metadata_->Get(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &entry);
    if ((ret == OK) && (entry.count == 4)) {
      scaler_crop_region_default_[0] = entry.data.i32[0];
      scaler_crop_region_default_[1] = entry.data.i32[1];
      scaler_crop_region_default_[2] = entry.data.i32[2];
      scaler_crop_region_default_[3] = entry.data.i32[3];
    } else {
      ALOGE("%s: Sensor pixel array size is not available!", __FUNCTION__);
      return BAD_VALUE;
    }

    if (available_requests_.find(ANDROID_SCALER_CROP_REGION) ==
        available_requests_.end()) {
      ALOGE(
          "%s: Backward compatible devices must support scaler crop "
          "configuration!",
          __FUNCTION__);
      return BAD_VALUE;
    }
    if (available_results_.find(ANDROID_SCALER_CROP_REGION) ==
        available_results_.end()) {
      ALOGE("%s: Scaler crop must reported on backward compatible devices!",
            __FUNCTION__);
      return BAD_VALUE;
    }
    ret = static_metadata_->Get(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
                                &entry);
    if ((ret == OK) && (entry.count > 0)) {
      // Listing rotate and crop, so need to make sure it's consistently reported
      if (available_requests_.find(ANDROID_SCALER_ROTATE_AND_CROP) ==
          available_requests_.end()) {
        ALOGE(
            "%s: Rotate and crop must be listed in request keys if supported!",
            __FUNCTION__);
        return BAD_VALUE;
      }
      if (available_results_.find(ANDROID_SCALER_ROTATE_AND_CROP) ==
          available_results_.end()) {
        ALOGE("%s: Rotate and crop must be listed in result keys if supported!",
              __FUNCTION__);
        return BAD_VALUE;
      }
      if (available_characteristics_.find(
              ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES) ==
          available_characteristics_.end()) {
        ALOGE(
            "%s: Rotate and crop must be listed in characteristics keys if "
            "supported!",
            __FUNCTION__);
        return BAD_VALUE;
      }
      report_rotate_and_crop_ = true;
      for (size_t i = 0; i < entry.count; i++) {
        if (entry.data.u8[i] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
          rotate_and_crop_ = ANDROID_SCALER_ROTATE_AND_CROP_AUTO;
        }
        available_rotate_crop_modes_.insert(entry.data.u8[i]);
      }
    }

    for (size_t idx = 0; idx < kTemplateCount; idx++) {
      if (default_requests_[idx].get() == nullptr) {
        continue;
      }

      default_requests_[idx]->Set(ANDROID_SCALER_CROP_REGION,
                                  scaler_crop_region_default_,
                                  ARRAY_SIZE(scaler_crop_region_default_));
      if (report_rotate_and_crop_) {
        default_requests_[idx]->Set(ANDROID_SCALER_ROTATE_AND_CROP,
                                    &rotate_and_crop_, 1);
      }
    }
  }

  return InitializeControlDefaults();
}

status_t EmulatedRequestState::InitializeShadingDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(ANDROID_SHADING_AVAILABLE_MODES, &entry);
  if (ret == OK) {
    available_shading_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available lens shading modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (supports_manual_post_processing_ &&
      (available_shading_modes_.size() < 2)) {
    ALOGE(
        "%s: Devices capable of manual post-processing need to support at "
        "least "
        "two"
        " lens shading modes!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  bool is_fast_mode_supported =
      available_shading_modes_.find(ANDROID_SHADING_MODE_FAST) !=
      available_shading_modes_.end();
  bool is_hq_mode_supported =
      available_shading_modes_.find(ANDROID_SHADING_MODE_HIGH_QUALITY) !=
      available_shading_modes_.end();
  uint8_t shading_mode = *available_shading_modes_.begin();
  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    switch (static_cast<RequestTemplate>(idx)) {
      case RequestTemplate::kVideoRecord:  // Pass-through
      case RequestTemplate::kPreview:
        if (is_fast_mode_supported) {
          shading_mode = ANDROID_SHADING_MODE_FAST;
        }
        break;
      case RequestTemplate::kVideoSnapshot:  // Pass-through
      case RequestTemplate::kStillCapture:
        if (is_hq_mode_supported) {
          shading_mode = ANDROID_SHADING_MODE_HIGH_QUALITY;
        }
        break;
      default:
        // Noop
        break;
    }

    default_requests_[idx]->Set(ANDROID_SHADING_MODE, &shading_mode, 1);
  }

  return InitializeNoiseReductionDefaults();
}

status_t EmulatedRequestState::InitializeNoiseReductionDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(
      ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, &entry);
  if (ret == OK) {
    available_noise_reduction_modes_.insert(entry.data.u8,
                                            entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available noise reduction modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  if ((is_level_full_or_higher_) &&
      (available_noise_reduction_modes_.size() < 2)) {
    ALOGE(
        "%s: Full and above device must support at least two noise reduction "
        "modes!",
        __FUNCTION__);
    return BAD_VALUE;
  }

  bool is_fast_mode_supported =
      available_noise_reduction_modes_.find(ANDROID_NOISE_REDUCTION_MODE_FAST) !=
      available_noise_reduction_modes_.end();
  bool is_hq_mode_supported = available_noise_reduction_modes_.find(
                                  ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY) !=
                              available_noise_reduction_modes_.end();
  bool is_zsl_mode_supported =
      available_noise_reduction_modes_.find(
          ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG) !=
      available_noise_reduction_modes_.end();
  uint8_t noise_reduction_mode = *available_noise_reduction_modes_.begin();
  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    switch (static_cast<RequestTemplate>(idx)) {
      case RequestTemplate::kVideoRecord:  // Pass-through
      case RequestTemplate::kVideoSnapshot:  // Pass-through
      case RequestTemplate::kPreview:
        if (is_fast_mode_supported) {
          noise_reduction_mode = ANDROID_NOISE_REDUCTION_MODE_FAST;
        }
        break;
      case RequestTemplate::kStillCapture:
        if (is_hq_mode_supported) {
          noise_reduction_mode = ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY;
        }
        break;
      case RequestTemplate::kZeroShutterLag:
        if (is_zsl_mode_supported) {
          noise_reduction_mode = ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG;
        }
        break;
      default:
        // Noop
        break;
    }

    default_requests_[idx]->Set(ANDROID_NOISE_REDUCTION_MODE,
                                &noise_reduction_mode, 1);
  }

  return InitializeColorCorrectionDefaults();
}

status_t EmulatedRequestState::InitializeHotPixelDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
                                   &entry);
  if (ret == OK) {
    available_hot_pixel_modes_.insert(entry.data.u8,
                                      entry.data.u8 + entry.count);
  } else {
    ALOGE("%s: No available hotpixel modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  if ((is_level_full_or_higher_) && (available_hot_pixel_modes_.size() < 2)) {
    ALOGE(
        "%s: Full and higher level cameras must support at least fast and hq "
        "hotpixel modes",
        __FUNCTION__);
    return BAD_VALUE;
  }

  bool fast_mode_supported =
      available_hot_pixel_modes_.find(ANDROID_HOT_PIXEL_MODE_FAST) !=
      available_hot_pixel_modes_.end();
  bool hq_mode_supported =
      available_hot_pixel_modes_.find(ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY) !=
      available_hot_pixel_modes_.end();
  uint8_t hotpixel_mode = *available_hot_pixel_modes_.begin();
  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    switch (static_cast<RequestTemplate>(idx)) {
      case RequestTemplate::kVideoRecord:  // Pass-through
      case RequestTemplate::kPreview:
        if (fast_mode_supported) {
          hotpixel_mode = ANDROID_HOT_PIXEL_MODE_FAST;
        }
        break;
      case RequestTemplate::kVideoSnapshot:  // Pass-through
      case RequestTemplate::kStillCapture:
        if (hq_mode_supported) {
          hotpixel_mode = ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY;
        }
        break;
      default:
        // Noop
        break;
    }

    default_requests_[idx]->Set(ANDROID_HOT_PIXEL_MODE, &hotpixel_mode, 1);
  }

  return InitializeTonemapDefaults();
}

status_t EmulatedRequestState::InitializeFlashDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret = static_metadata_->Get(ANDROID_FLASH_INFO_AVAILABLE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    is_flash_supported_ = entry.data.u8[0];
  } else {
    ALOGE("%s: No available flash info!", __FUNCTION__);
    return BAD_VALUE;
  }

  if (is_flash_supported_) {
    flash_state_ = ANDROID_FLASH_STATE_READY;
  } else {
    flash_state_ = ANDROID_FLASH_STATE_UNAVAILABLE;
  }

  uint8_t flash_mode = ANDROID_FLASH_MODE_OFF;
  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    default_requests_[idx]->Set(ANDROID_FLASH_MODE, &flash_mode, 1);
  }

  return InitializeScalerDefaults();
}

status_t EmulatedRequestState::InitializeLensDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret =
      static_metadata_->Get(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    minimum_focus_distance_ = entry.data.f[0];
  } else {
    ALOGW("%s: No available minimum focus distance assuming fixed focus!",
          __FUNCTION__);
    minimum_focus_distance_ = .0f;
  }

  ret = static_metadata_->Get(ANDROID_LENS_INFO_AVAILABLE_APERTURES, &entry);
  if ((ret == OK) && (entry.count > 0)) {
    // TODO: add support for multiple apertures
    aperture_ = entry.data.f[0];
  } else {
    ALOGE("%s: No available aperture!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &entry);
  if ((ret == OK) && (entry.count > 0)) {
    focal_length_ = entry.data.f[0];
  } else {
    ALOGE("%s: No available focal length!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_LENS_INFO_SHADING_MAP_SIZE, &entry);
  if ((ret == OK) && (entry.count == 2)) {
    shading_map_size_[0] = entry.data.i32[0];
    shading_map_size_[1] = entry.data.i32[1];
  } else if (is_raw_capable_) {
    ALOGE("%s: No available shading map size!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
                              &entry);
  if ((ret == OK) && (entry.count > 0)) {
    // TODO: add support for multiple filter densities
    filter_density_ = entry.data.f[0];
  } else {
    ALOGE("%s: No available filter density!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
                              &entry);
  if ((ret == OK) && (entry.count > 0)) {
    // TODO: add support for multiple OIS modes
    available_ois_modes_.insert(entry.data.u8, entry.data.u8 + entry.count);
    if (available_ois_modes_.find(ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF) ==
        available_ois_modes_.end()) {
      ALOGE("%s: OIS off mode not supported!", __FUNCTION__);
      return BAD_VALUE;
    }
  } else {
    ALOGE("%s: No available OIS modes!", __FUNCTION__);
    return BAD_VALUE;
  }

  ret = static_metadata_->Get(ANDROID_LENS_POSE_ROTATION, &entry);
  if ((ret == OK) && (entry.count == ARRAY_SIZE(pose_rotation_))) {
    memcpy(pose_rotation_, entry.data.f, sizeof(pose_rotation_));
  }
  ret = static_metadata_->Get(ANDROID_LENS_POSE_TRANSLATION, &entry);
  if ((ret == OK) && (entry.count == ARRAY_SIZE(pose_translation_))) {
    memcpy(pose_translation_, entry.data.f, sizeof(pose_translation_));
  }
  ret = static_metadata_->Get(ANDROID_LENS_INTRINSIC_CALIBRATION, &entry);
  if ((ret == OK) && (entry.count == ARRAY_SIZE(intrinsic_calibration_))) {
    memcpy(intrinsic_calibration_, entry.data.f, sizeof(intrinsic_calibration_));
  }

  ret = static_metadata_->Get(ANDROID_LENS_DISTORTION, &entry);
  if ((ret == OK) && (entry.count == ARRAY_SIZE(distortion_))) {
    memcpy(distortion_, entry.data.f, sizeof(distortion_));
  }

  report_focus_distance_ =
      available_results_.find(ANDROID_LENS_FOCUS_DISTANCE) !=
      available_results_.end();
  report_focus_range_ = available_results_.find(ANDROID_LENS_FOCUS_RANGE) !=
                        available_results_.end();
  report_filter_density_ =
      available_results_.find(ANDROID_LENS_FILTER_DENSITY) !=
      available_results_.end();
  report_ois_mode_ =
      available_results_.find(ANDROID_LENS_OPTICAL_STABILIZATION_MODE) !=
      available_results_.end();
  report_pose_rotation_ = available_results_.find(ANDROID_LENS_POSE_ROTATION) !=
                          available_results_.end();
  report_pose_translation_ =
      available_results_.find(ANDROID_LENS_POSE_TRANSLATION) !=
      available_results_.end();
  report_intrinsic_calibration_ =
      available_results_.find(ANDROID_LENS_INTRINSIC_CALIBRATION) !=
      available_results_.end();
  report_distortion_ = available_results_.find(ANDROID_LENS_DISTORTION) !=
                       available_results_.end();

  focus_distance_ = minimum_focus_distance_;
  for (size_t idx = 0; idx < kTemplateCount; idx++) {
    if (default_requests_[idx].get() == nullptr) {
      continue;
    }

    default_requests_[idx]->Set(ANDROID_LENS_APERTURE, &aperture_, 1);
    default_requests_[idx]->Set(ANDROID_LENS_FOCAL_LENGTH, &focal_length_, 1);
    default_requests_[idx]->Set(ANDROID_LENS_FOCUS_DISTANCE, &focus_distance_,
                                1);
    default_requests_[idx]->Set(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
                                &ois_mode_, 1);
  }

  return InitializeFlashDefaults();
}

status_t EmulatedRequestState::InitializeInfoDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret =
      static_metadata_->Get(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (kSupportedHWLevels.find(entry.data.u8[0]) ==
        kSupportedCapabilites.end()) {
      ALOGE("%s: HW Level: %u not supported", __FUNCTION__, entry.data.u8[0]);
      return BAD_VALUE;
    }
  } else {
    ALOGE("%s: No available hardware level!", __FUNCTION__);
    return BAD_VALUE;
  }

  supported_hw_level_ = entry.data.u8[0];
  is_level_full_or_higher_ =
      (supported_hw_level_ == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL) ||
      (supported_hw_level_ == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3);

  return InitializeReprocessDefaults();
}

status_t EmulatedRequestState::InitializeReprocessDefaults() {
  if (supports_private_reprocessing_ || supports_yuv_reprocessing_ ||
      supports_remosaic_reprocessing_) {
    StreamConfigurationMap config_map(*static_metadata_);
    if (!config_map.SupportsReprocessing()) {
      ALOGE(
          "%s: Reprocess capability present but InputOutput format map is "
          "absent!",
          __FUNCTION__);
      return BAD_VALUE;
    }

    auto input_formats = config_map.GetInputFormats();
    for (const auto& input_format : input_formats) {
      auto output_formats =
          config_map.GetValidOutputFormatsForInput(input_format);
      for (const auto& output_format : output_formats) {
        if (!EmulatedSensor::IsReprocessPathSupported(
                EmulatedSensor::OverrideFormat(input_format),
                EmulatedSensor::OverrideFormat(output_format))) {
          ALOGE(
              "%s: Input format: 0x%x to output format: 0x%x reprocess is"
              " currently not supported!",
              __FUNCTION__, input_format, output_format);
          return BAD_VALUE;
        }
      }
    }
  }

  return InitializeLensDefaults();
}

status_t EmulatedRequestState::InitializeRequestDefaults() {
  camera_metadata_ro_entry_t entry;
  auto ret =
      static_metadata_->Get(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
  if ((ret == OK) && (entry.count > 0)) {
    for (size_t i = 0; i < entry.count; i++) {
      if (kSupportedCapabilites.find(entry.data.u8[i]) ==
          kSupportedCapabilites.end()) {
        ALOGE("%s: Capability: %u not supported", __FUNCTION__,
              entry.data.u8[i]);
        return BAD_VALUE;
      }
    }
  } else {
    ALOGE("%s: No available capabilities!", __FUNCTION__);
    return BAD_VALUE;
  }
  available_capabilities_.insert(entry.data.u8, entry.data.u8 + entry.count);

  ret = static_metadata_->Get(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (entry.data.u8[0] == 0) {
      ALOGE("%s: Maximum request pipeline depth must have a non zero value!",
            __FUNCTION__);
      return BAD_VALUE;
    }
  } else {
    ALOGE("%s: Maximum request pipeline depth absent!", __FUNCTION__);
    return BAD_VALUE;
  }
  max_pipeline_depth_ = entry.data.u8[0];

  ret = static_metadata_->Get(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
  if ((ret == OK) && (entry.count == 1)) {
    if (entry.data.i32[0] != 1) {
      ALOGW("%s: Partial results not supported!", __FUNCTION__);
    }
  }

  ret = static_metadata_->Get(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
                              &entry);
  if ((ret != OK) || (entry.count == 0)) {
    ALOGE("%s: No available characteristic keys!", __FUNCTION__);
    return BAD_VALUE;
  }
  available_characteristics_.insert(entry.data.i32,
                                    entry.data.i32 + entry.count);

  ret = static_metadata_->Get(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
  if ((ret != OK) || (entry.count == 0)) {
    ALOGE("%s: No available result keys!", __FUNCTION__);
    return BAD_VALUE;
  }
  available_results_.insert(entry.data.i32, entry.data.i32 + entry.count);

  ret = static_metadata_->Get(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
  if ((ret != OK) || (entry.count == 0)) {
    ALOGE("%s: No available request keys!", __FUNCTION__);
    return BAD_VALUE;
  }
  available_requests_.insert(entry.data.i32, entry.data.i32 + entry.count);

  supports_manual_sensor_ =
      SupportsCapability(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
  supports_manual_post_processing_ = SupportsCapability(
      ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
  supports_private_reprocessing_ = SupportsCapability(
      ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
  supports_yuv_reprocessing_ = SupportsCapability(
      ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
  supports_remosaic_reprocessing_ = SupportsCapability(
      ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING);
  is_backward_compatible_ = SupportsCapability(
      ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
  is_raw_capable_ =
      SupportsCapability(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);

  if (supports_manual_sensor_) {
    auto templateIdx = static_cast<size_t>(RequestTemplate::kManual);
    default_requests_[templateIdx] = HalCameraMetadata::Create(1, 10);
  }

  for (size_t templateIdx = 0; templateIdx < kTemplateCount; templateIdx++) {
    switch (static_cast<RequestTemplate>(templateIdx)) {
      case RequestTemplate::kPreview:
      case RequestTemplate::kStillCapture:
      case RequestTemplate::kVideoRecord:
      case RequestTemplate::kVideoSnapshot:
        default_requests_[templateIdx] = HalCameraMetadata::Create(1, 10);
        break;
      default:
        // Noop
        break;
    }
  }

  if (supports_yuv_reprocessing_ || supports_private_reprocessing_) {
    auto templateIdx = static_cast<size_t>(RequestTemplate::kZeroShutterLag);
    default_requests_[templateIdx] = HalCameraMetadata::Create(1, 10);
  }

  return InitializeInfoDefaults();
}

status_t EmulatedRequestState::Initialize(
    std::unique_ptr<HalCameraMetadata> staticMeta) {
  std::lock_guard<std::mutex> lock(request_state_mutex_);
  static_metadata_ = std::move(staticMeta);

  return InitializeRequestDefaults();
}

status_t EmulatedRequestState::GetDefaultRequest(
    RequestTemplate type, std::unique_ptr<HalCameraMetadata>* default_settings) {
  if (default_settings == nullptr) {
    ALOGE("%s default_settings is nullptr", __FUNCTION__);
    return BAD_VALUE;
  }

  std::lock_guard<std::mutex> lock(request_state_mutex_);
  auto idx = static_cast<size_t>(type);
  if (idx >= kTemplateCount) {
    ALOGE("%s: Unexpected request type: %d", __FUNCTION__, type);
    return BAD_VALUE;
  }

  if (default_requests_[idx].get() == nullptr) {
    ALOGE("%s: Unsupported request type: %d", __FUNCTION__, type);
    return BAD_VALUE;
  }

  *default_settings =
      HalCameraMetadata::Clone(default_requests_[idx]->GetRawCameraMetadata());

  return OK;
}

}  // namespace android