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 (VERBOSE) {
      Log.v(
          TAG,
          "convertMeteringRegionsToLegacy - "
              + regionName
              + " areas = "
              + ParameterUtils.stringFromAreaList(meteringAreaList));
    }

    return meteringAreaList;
  }
  /**
   * Calculate the effective crop rectangle for this preview viewport; assumes the preview is
   * centered to the sensor and scaled to fit across one of the dimensions without skewing.
   *
   * <p>The preview size must be a subset of the active array size; the resulting rectangle will
   * also be a subset of the active array rectangle.
   *
   * <p>The unzoomed crop rectangle is calculated only.
   *
   * @param activeArray active array dimensions, in sensor space
   * @param previewSize size of the preview buffer render target, in pixels (not in sensor space)
   * @return a rectangle which serves as the preview stream's effective crop region (unzoomed), in
   *     sensor space
   * @throws NullPointerException if any of the args were {@code null}
   * @throws IllegalArgumentException if {@code previewSize} is wider or taller than {@code
   *     activeArray}
   */
  private static Rect getPreviewCropRectangleUnzoomed(Rect activeArray, Size previewSize) {
    if (previewSize.getWidth() > activeArray.width()) {
      throw new IllegalArgumentException("previewSize must not be wider than activeArray");
    } else if (previewSize.getHeight() > activeArray.height()) {
      throw new IllegalArgumentException("previewSize must not be taller than activeArray");
    }

    float aspectRatioArray = activeArray.width() * 1.0f / activeArray.height();
    float aspectRatioPreview = previewSize.getWidth() * 1.0f / previewSize.getHeight();

    float cropH, cropW;
    if (Math.abs(aspectRatioPreview - aspectRatioArray) < ASPECT_RATIO_TOLERANCE) {
      cropH = activeArray.height();
      cropW = activeArray.width();
    } else if (aspectRatioPreview < aspectRatioArray) {
      // The new width must be smaller than the height, so scale the width by AR
      cropH = activeArray.height();
      cropW = cropH * aspectRatioPreview;
    } else {
      // The new height must be smaller (or equal) than the width, so scale the height by AR
      cropW = activeArray.width();
      cropH = cropW / aspectRatioPreview;
    }

    Matrix translateMatrix = new Matrix();
    RectF cropRect = new RectF(/*left*/ 0, /*top*/ 0, cropW, cropH);

    // Now center the crop rectangle so its center is in the center of the active array
    translateMatrix.setTranslate(activeArray.exactCenterX(), activeArray.exactCenterY());
    translateMatrix.postTranslate(-cropRect.centerX(), -cropRect.centerY());

    translateMatrix.mapRect(/*inout*/ cropRect);

    // Round the rect corners towards the nearest integer values
    return ParamsUtils.createRect(cropRect);
  }