content: /*
   * Copyright (C) 2014 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.hardware.camera2.legacy;
  
  import android.graphics.Rect;
  import android.hardware.Camera;
  import android.hardware.Camera.Parameters;
  import android.hardware.camera2.CameraCharacteristics;
  import android.hardware.camera2.CaptureRequest;
  import android.hardware.camera2.params.MeteringRectangle;
  import android.hardware.camera2.utils.ListUtils;
  import android.hardware.camera2.utils.ParamsUtils;
  import android.location.Location;
  import android.util.Log;
  import android.util.Range;
  import android.util.Size;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.Objects;
  
  import static android.hardware.camera2.CaptureRequest.*;
  
  /**
   * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
   */
  @SuppressWarnings("deprecation")
  public class LegacyRequestMapper {
      private static final String TAG = "LegacyRequestMapper";
      private static final boolean DEBUG = false;
  
      /** Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality */
      private static final byte DEFAULT_JPEG_QUALITY = 85;
  
      /**
       * Set the legacy parameters using the {@link LegacyRequest legacy request}.
       *
       * <p>The legacy request's parameters are changed as a side effect of calling this
       * method.</p>
       *
       * @param legacyRequest a non-{@code null} legacy request
       */
      public static void convertRequestMetadata(LegacyRequest legacyRequest) {
          CameraCharacteristics characteristics = legacyRequest.characteristics;
          CaptureRequest request = legacyRequest.captureRequest;
          Size previewSize = legacyRequest.previewSize;
          Camera.Parameters params = legacyRequest.parameters;
  
          Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
  
          /*
           * scaler.cropRegion
           */
          ParameterUtils.ZoomData zoomData;
          {
              zoomData = ParameterUtils.convertScalerCropRegion(activeArray,
                      request.get(SCALER_CROP_REGION),
                      previewSize,
                      params);
  
              if (params.isZoomSupported()) {
                  params.setZoom(zoomData.zoomIndex);
              } else if (DEBUG) {
                  Log.v(TAG, "convertRequestToMetadata - zoom is not supported");
              }
          }
  
          /*
           * colorCorrection.*
           */
          // colorCorrection.aberrationMode
          {
              int aberrationMode = ParamsUtils.getOrDefault(request,
                      COLOR_CORRECTION_ABERRATION_MODE,
                      /*defaultValue*/COLOR_CORRECTION_ABERRATION_MODE_FAST);
  
              if (aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_FAST &&
                      aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY) {
                  Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
                          "colorCorrection.aberrationMode = " + aberrationMode);
              }
          }
  
          /*
           * control.ae*
           */
          // control.aeAntibandingMode
          {
          String legacyMode;
              Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE);
              if (antiBandingMode != null) {
                  legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode);
              } else {
                  legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(),
                          new String[] {
                              Parameters.ANTIBANDING_AUTO,
                              Parameters.ANTIBANDING_OFF,
                              Parameters.ANTIBANDING_50HZ,
                              Parameters.ANTIBANDING_60HZ,
                          });
              }
  
              if (legacyMode != null) {
                  params.setAntibanding(legacyMode);
              }
          }
  
          /*
           * control.aeRegions, afRegions
           */
          {
              // aeRegions
              {
                  // Use aeRegions if available, fall back to using awbRegions if present
                  MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
                  if (request.get(CONTROL_AWB_REGIONS) != null) {
                      Log.w(TAG, "convertRequestMetadata - control.awbRegions setting is not " +
                              "supported, ignoring value");
                  }
                  int maxNumMeteringAreas = params.getMaxNumMeteringAreas();
                  List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy(
                          activeArray, zoomData, aeRegions, maxNumMeteringAreas,
                          /*regionName*/"AE");
  
                  // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
                  if (maxNumMeteringAreas > 0) {
                      params.setMeteringAreas(meteringAreaList);
                  }
              }
  
              // afRegions
              {
                  MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
                  int maxNumFocusAreas = params.getMaxNumFocusAreas();
                  List<Camera.Area> focusAreaList = convertMeteringRegionsToLegacy(
                          activeArray, zoomData, afRegions, maxNumFocusAreas,
                          /*regionName*/"AF");
  
                  // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
                  if (maxNumFocusAreas > 0) {
                      params.setFocusAreas(focusAreaList);
                  }
              }
          }
  
          // control.aeTargetFpsRange
          Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE);
          if (aeFpsRange != null) {
              int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange);
  
              int[] rangeToApply = null;
              for(int[] range : params.getSupportedPreviewFpsRange()) {
                  // Round range up/down to integer FPS value
                  int intRangeLow = (int) Math.floor(range[0] / 1000.0) * 1000;
                  int intRangeHigh = (int) Math.ceil(range[1] / 1000.0) * 1000;
                  if (legacyFps[0] == intRangeLow && legacyFps[1] == intRangeHigh) {
                      rangeToApply = range;
                      break;
                  }
              }
              if (rangeToApply != null) {
                  params.setPreviewFpsRange(rangeToApply[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
                          rangeToApply[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
              } else {
                  Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
              }
          }
  
          /*
           * control
           */
  
          // control.aeExposureCompensation
          {
              Range<Integer> compensationRange =
                      characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
              int compensation = ParamsUtils.getOrDefault(request,
                      CONTROL_AE_EXPOSURE_COMPENSATION,
                      /*defaultValue*/0);
  
              if (!compensationRange.contains(compensation)) {
                  Log.w(TAG,
                          "convertRequestMetadata - control.aeExposureCompensation " +
                          "is out of range, ignoring value");
                  compensation = 0;
              }
  
              params.setExposureCompensation(compensation);
          }
  
          // control.aeLock
          {
              Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false,
                      params.isAutoExposureLockSupported(),
                      /*allowedValue*/false);
  
              if (aeLock != null) {
                  params.setAutoExposureLock(aeLock);
              }
  
              if (DEBUG) {
                  Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock);
              }
  
              // TODO: Don't add control.aeLock to availableRequestKeys if it's not supported
          }
  
          // control.aeMode, flash.mode
          mapAeAndFlashMode(request, /*out*/params);
  
          // control.afMode
          {
              int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE,
                      /*defaultValue*/CONTROL_AF_MODE_OFF);
              String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode,
                      params.getSupportedFocusModes());
  
              if (focusMode != null) {
                  params.setFocusMode(focusMode);
              }
  
              if (DEBUG) {
                  Log.v(TAG, "convertRequestToMetadata - control.afMode "
                          + afMode + " mapped to " + focusMode);
              }
          }
  
          // control.awbMode
          {
              Integer awbMode = getIfSupported(request, CONTROL_AWB_MODE,
                      /*defaultValue*/CONTROL_AWB_MODE_AUTO,
                      params.getSupportedWhiteBalance() != null,
                      /*allowedValue*/CONTROL_AWB_MODE_AUTO);
  
              String whiteBalanceMode = null;
              if (awbMode != null) { // null iff AWB is not supported by camera1 api
                  whiteBalanceMode = convertAwbModeToLegacy(awbMode);
                  params.setWhiteBalance(whiteBalanceMode);
              }
  
              if (DEBUG) {
                  Log.v(TAG, "convertRequestToMetadata - control.awbMode "
                          + awbMode + " mapped to " + whiteBalanceMode);
              }
          }
  
          // control.awbLock
          {
              Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false,
                      params.isAutoWhiteBalanceLockSupported(),
                      /*allowedValue*/false);
  
              if (awbLock != null) {
                  params.setAutoWhiteBalanceLock(awbLock);
              }
  
           // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
          }
  
          // control.captureIntent
          {
              int captureIntent = ParamsUtils.getOrDefault(request,
                      CONTROL_CAPTURE_INTENT,
                      /*defaultValue*/CONTROL_CAPTURE_INTENT_PREVIEW);
  
              captureIntent = filterSupportedCaptureIntent(captureIntent);
  
              params.setRecordingHint(
                      captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_RECORD ||
                      captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
          }
  
          // control.videoStabilizationMode
          {
              Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE,
                      /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF,
                      params.isVideoStabilizationSupported(),
                      /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF);
  
              if (stabMode != null) {
                  params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON);
              }
          }
  
          // lens.focusDistance
          {
              boolean infinityFocusSupported =
                      ListUtils.listContains(params.getSupportedFocusModes(),
                              Parameters.FOCUS_MODE_INFINITY);
              Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE,
                      /*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f);
  
              if (focusDistance == null || focusDistance != 0f) {
                  Log.w(TAG,
                          "convertRequestToMetadata - Ignoring android.lens.focusDistance "
                                  + infinityFocusSupported + ", only 0.0f is supported");
              }
          }
  
          // control.sceneMode, control.mode
          {
              // TODO: Map FACE_PRIORITY scene mode to face detection.
  
              if (params.getSupportedSceneModes() != null) {
                  int controlMode = ParamsUtils.getOrDefault(request, CONTROL_MODE,
                      /*defaultValue*/CONTROL_MODE_AUTO);
                  String modeToSet;
                  switch (controlMode) {
                      case CONTROL_MODE_USE_SCENE_MODE: {
                          int sceneMode = ParamsUtils.getOrDefault(request, CONTROL_SCENE_MODE,
                                  /*defaultValue*/CONTROL_SCENE_MODE_DISABLED);
                          String legacySceneMode = LegacyMetadataMapper.
                                  convertSceneModeToLegacy(sceneMode);
                          if (legacySceneMode != null) {
                              modeToSet = legacySceneMode;
                          } else {
                              modeToSet = Parameters.SCENE_MODE_AUTO;
                              Log.w(TAG, "Skipping unknown requested scene mode: " + sceneMode);
                          }
                          break;
                      }
                      case CONTROL_MODE_AUTO: {
                          modeToSet = Parameters.SCENE_MODE_AUTO;
                          break;
                      }
                      default: {
                          Log.w(TAG, "Control mode " + controlMode +
                                  " is unsupported, defaulting to AUTO");
                          modeToSet = Parameters.SCENE_MODE_AUTO;
                      }
                  }
                  params.setSceneMode(modeToSet);
              }
          }
  
          // control.effectMode
          {
              if (params.getSupportedColorEffects() != null) {
                  int effectMode = ParamsUtils.getOrDefault(request, CONTROL_EFFECT_MODE,
                      /*defaultValue*/CONTROL_EFFECT_MODE_OFF);
                  String legacyEffectMode = LegacyMetadataMapper.convertEffectModeToLegacy(effectMode);
                  if (legacyEffectMode != null) {
                      params.setColorEffect(legacyEffectMode);
                  } else {
                      params.setColorEffect(Parameters.EFFECT_NONE);
                      Log.w(TAG, "Skipping unknown requested effect mode: " + effectMode);
                  }
              }
          }
  
          /*
           * sensor
           */
  
          // sensor.testPattern
          {
              int testPatternMode = ParamsUtils.getOrDefault(request, SENSOR_TEST_PATTERN_MODE,
                      /*defaultValue*/SENSOR_TEST_PATTERN_MODE_OFF);
              if (testPatternMode != SENSOR_TEST_PATTERN_MODE_OFF) {
                  Log.w(TAG, "convertRequestToMetadata - ignoring sensor.testPatternMode "
                          + testPatternMode + "; only OFF is supported");
              }
          }
  
          /*
           * jpeg.*
           */
  
          // jpeg.gpsLocation
          {
              Location location = request.get(JPEG_GPS_LOCATION);
              if (location != null) {
                  if (checkForCompleteGpsData(location)) {
                      params.setGpsAltitude(location.getAltitude());
                      params.setGpsLatitude(location.getLatitude());
                      params.setGpsLongitude(location.getLongitude());
                      params.setGpsProcessingMethod(location.getProvider().toUpperCase());
                      params.setGpsTimestamp(location.getTime());
                  } else {
                      Log.w(TAG, "Incomplete GPS parameters provided in location " + location);
                  }
              } else {
                  params.removeGpsData();
              }
          }
  
          // jpeg.orientation
          {
              Integer orientation = request.get(CaptureRequest.JPEG_ORIENTATION);
              params.setRotation(ParamsUtils.getOrDefault(request, JPEG_ORIENTATION,
                      (orientation == null) ? 0 : orientation));
          }
  
          // jpeg.quality
          {
              params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_QUALITY,
                      DEFAULT_JPEG_QUALITY));
          }
  
          // jpeg.thumbnailQuality
          {
              params.setJpegThumbnailQuality(0xFF & ParamsUtils.getOrDefault(request,
                      JPEG_THUMBNAIL_QUALITY, DEFAULT_JPEG_QUALITY));
          }
  
          // jpeg.thumbnailSize
          {
              List<Camera.Size> sizes = params.getSupportedJpegThumbnailSizes();
  
              if (sizes != null && sizes.size() > 0) {
                  Size s = request.get(JPEG_THUMBNAIL_SIZE);
                  boolean invalidSize = (s == null) ? false : !ParameterUtils.containsSize(sizes,
                          s.getWidth(), s.getHeight());
                  if (invalidSize) {
                      Log.w(TAG, "Invalid JPEG thumbnail size set " + s + ", skipping thumbnail...");
                  }
                  if (s == null || invalidSize) {
                      // (0,0) = "no thumbnail" in Camera API 1
                      params.setJpegThumbnailSize(/*width*/0, /*height*/0);
                  } else {
                      params.setJpegThumbnailSize(s.getWidth(), s.getHeight());
                  }
              }
          }
  
          /*
           * noiseReduction.*
           */
          // noiseReduction.mode
          {
              int mode = ParamsUtils.getOrDefault(request,
                      NOISE_REDUCTION_MODE,
                      /*defaultValue*/NOISE_REDUCTION_MODE_FAST);
  
              if (mode != NOISE_REDUCTION_MODE_FAST &&
                      mode != NOISE_REDUCTION_MODE_HIGH_QUALITY) {
                  Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
                          "noiseReduction.mode = " + mode);
              }
          }
      }
  
      private static boolean checkForCompleteGpsData(Location location) {
          return location != null && location.getProvider() != null && location.getTime() != 0;
      }
  
      static int filterSupportedCaptureIntent(int captureIntent) {
          switch (captureIntent) {
              case CONTROL_CAPTURE_INTENT_CUSTOM:
              case CONTROL_CAPTURE_INTENT_PREVIEW:
              case CONTROL_CAPTURE_INTENT_STILL_CAPTURE:
              case CONTROL_CAPTURE_INTENT_VIDEO_RECORD:
              case CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT:
                  break;
              case CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG:
              case CONTROL_CAPTURE_INTENT_MANUAL:
                  captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
                  Log.w(TAG, "Unsupported control.captureIntent value " + captureIntent
                          + "; default to PREVIEW");
              default:
                  captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
                  Log.w(TAG, "Unknown control.captureIntent value " + captureIntent
                          + "; default to PREVIEW");
          }
  
          return captureIntent;
      }
  
      private static List<Camera.Area> convertMeteringRegionsToLegacy(
              Rect activeArray, ParameterUtils.ZoomData zoomData,
              MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) {
          if (meteringRegions == null || maxNumMeteringAreas <= 0) {
              if (maxNumMeteringAreas > 0) {
                  return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
              } else {
                  return null;
              }
          }
  
          // Add all non-zero weight regions to the list
          List<MeteringRectangle> meteringRectangleList = new ArrayList<>();
          for (MeteringRectangle rect : meteringRegions) {
              if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) {
                  meteringRectangleList.add(rect);
              }
          }
  
          if (meteringRectangleList.size() == 0) {
              Log.w(TAG, "Only received metering rectangles with weight 0.");
              return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
          }
  
          // Ignore any regions beyond our maximum supported count
          int countMeteringAreas =
                  Math.min(maxNumMeteringAreas, meteringRectangleList.size());
          List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas);
  
          for (int i = 0; i < countMeteringAreas; ++i) {
              MeteringRectangle rect = meteringRectangleList.get(i);
  
              ParameterUtils.MeteringData meteringData =
                      ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData);
              meteringAreaList.add(meteringData.meteringArea);
          }
  
          if (maxNumMeteringAreas < meteringRectangleList.size()) {
              Log.w(TAG,
                      "convertMeteringRegionsToLegacy - Too many requested " + regionName +
                              " regions, ignoring all beyond the first " + maxNumMeteringAreas);
          }
  
          if (DEBUG) {
              Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = "
                      + ParameterUtils.stringFromAreaList(meteringAreaList));
          }
  
          return meteringAreaList;
      }
  
      private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) {
          int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
          int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
  
          List<String> supportedFlashModes = p.getSupportedFlashModes();
  
          String flashModeSetting = null;
  
          // Flash is OFF by default, on cameras that support flash
          if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_OFF)) {
              flashModeSetting = Parameters.FLASH_MODE_OFF;
          }
  
          /*
           * Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it
           */
  
          // Ignore flash.mode controls unless aeMode == ON
          if (aeMode == CONTROL_AE_MODE_ON) {
              if (flashMode == FLASH_MODE_TORCH) {
                      if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) {
                          flashModeSetting = Parameters.FLASH_MODE_TORCH;
                      } else {
                          Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == TORCH;" +
                                  "camera does not support it");
                      }
              } else if (flashMode == FLASH_MODE_SINGLE) {
                  if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
                      flashModeSetting = Parameters.FLASH_MODE_ON;
                  } else {
                      Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == SINGLE;" +
                              "camera does not support it");
                  }
              } else {
                  // Use the default FLASH_MODE_OFF
              }
          } else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH) {
                  if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
                      flashModeSetting = Parameters.FLASH_MODE_ON;
                  } else {
                      Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_ALWAYS_FLASH;" +
                              "camera does not support it");
                  }
          } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH) {
              if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) {
                  flashModeSetting = Parameters.FLASH_MODE_AUTO;
              } else {
                  Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH;" +
                          "camera does not support it");
              }
          } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
                  if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) {
                      flashModeSetting = Parameters.FLASH_MODE_RED_EYE;
                  } else {
                      Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH_REDEYE;"
                              + "camera does not support it");
                  }
          } else {
              // Default to aeMode == ON, flash = OFF
          }
  
          if (flashModeSetting != null) {
              p.setFlashMode(flashModeSetting);
          }
  
          if (DEBUG) {
                  Log.v(TAG,
                          "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting
                          + ", requested (api2) " + flashMode
                          + ", supported (api1) " + ListUtils.listToString(supportedFlashModes));
          }
      }
  
      /**
       * Returns null if the anti-banding mode enum is not supported.
       */
      private static String convertAeAntiBandingModeToLegacy(int mode) {
          switch (mode) {
              case CONTROL_AE_ANTIBANDING_MODE_OFF: {
                  return Parameters.ANTIBANDING_OFF;
              }
              case CONTROL_AE_ANTIBANDING_MODE_50HZ: {
                  return Parameters.ANTIBANDING_50HZ;
              }
              case CONTROL_AE_ANTIBANDING_MODE_60HZ: {
                  return Parameters.ANTIBANDING_60HZ;
              }
              case CONTROL_AE_ANTIBANDING_MODE_AUTO: {
                  return Parameters.ANTIBANDING_AUTO;
              }
              default: {
                  return null;
              }
          }
      }
  
      private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
          int[] legacyFps = new int[2];
          legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower() * 1000;
          legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper() * 1000;
          return legacyFps;
      }
  
      private static String convertAwbModeToLegacy(int mode) {
          switch (mode) {
              case CONTROL_AWB_MODE_AUTO:
                  return Camera.Parameters.WHITE_BALANCE_AUTO;
              case CONTROL_AWB_MODE_INCANDESCENT:
                  return Camera.Parameters.WHITE_BALANCE_INCANDESCENT;
              case CONTROL_AWB_MODE_FLUORESCENT:
                  return Camera.Parameters.WHITE_BALANCE_FLUORESCENT;
              case CONTROL_AWB_MODE_WARM_FLUORESCENT:
                  return Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT;
              case CONTROL_AWB_MODE_DAYLIGHT:
                  return Camera.Parameters.WHITE_BALANCE_DAYLIGHT;
              case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
                  return Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;
              case CONTROL_AWB_MODE_TWILIGHT:
                  return Camera.Parameters.WHITE_BALANCE_TWILIGHT;
              case CONTROL_AWB_MODE_SHADE:
                  return Parameters.WHITE_BALANCE_SHADE;
              default:
                  Log.w(TAG, "convertAwbModeToLegacy - unrecognized control.awbMode" + mode);
                  return Camera.Parameters.WHITE_BALANCE_AUTO;
          }
      }
  
  
      /**
       * Return {@code null} if the value is not supported, otherwise return the retrieved key's
       * value from the request (or the default value if it wasn't set).
       *
       * <p>If the fetched value in the request is equivalent to {@code allowedValue},
       * then omit the warning (e.g. turning off AF lock on a camera
       * that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p>
       *
       * <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p.
       */
      private static <T> T getIfSupported(
              CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported,
              T allowedValue) {
          T val = ParamsUtils.getOrDefault(r, key, defaultValue);
  
          if (!isSupported) {
              if (!Objects.equals(val, allowedValue)) {
                  Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val);
              }
              return null;
          }
  
          return val;
      }
  }
  