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 actual/effective/reported normalized rectangle data from a metering rectangle.
   *
   * <p>If any of the rectangles are out-of-range of their intended bounding box, the {@link
   * #RECTANGLE_EMPTY empty rectangle} is substituted instead (with a weight of {@code 0}).
   *
   * <p>The metering rectangle is bound by the crop region (effective/reported respectively). The
   * metering {@link Camera.Area area} is bound by {@code [-1000, 1000]}.
   *
   * <p>No parameters are mutated; returns the new metering data.
   *
   * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
   * @param meteringRect the user-specified metering rectangle
   * @param zoomData the calculated zoom data corresponding to this request
   * @return the metering area, the reported/effective metering rectangles
   */
  public static MeteringData convertMeteringRectangleToLegacy(
      Rect activeArray, MeteringRectangle meteringRect, ZoomData zoomData) {
    Rect previewCrop = zoomData.previewCrop;

    float scaleW =
        (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f / previewCrop.width();
    float scaleH =
        (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f / previewCrop.height();

    Matrix transform = new Matrix();
    // Move the preview crop so that top,left is at (0,0), otherwise after scaling
    // the corner bounds will be outside of [-1000, 1000]
    transform.setTranslate(-previewCrop.left, -previewCrop.top);
    // Scale into [0, 2000] range about the center of the preview
    transform.postScale(scaleW, scaleH);
    // Move so that top left of a typical rect is at [-1000, -1000]
    transform.postTranslate(/*dx*/ NORMALIZED_RECTANGLE_MIN, /*dy*/ NORMALIZED_RECTANGLE_MIN);

    /*
     * Calculate the preview metering region (effective), and the camera1 api
     * normalized metering region.
     */
    Rect normalizedRegionUnbounded = ParamsUtils.mapRect(transform, meteringRect.getRect());

    /*
     * Try to intersect normalized area with [-1000, 1000] rectangle; otherwise
     * it's completely out of range
     */
    Rect normalizedIntersected = new Rect(normalizedRegionUnbounded);

    Camera.Area meteringArea;
    if (!normalizedIntersected.intersect(NORMALIZED_RECTANGLE_DEFAULT)) {
      Log.w(
          TAG,
          "convertMeteringRectangleToLegacy - metering rectangle too small, "
              + "no metering will be done");
      normalizedIntersected.set(RECTANGLE_EMPTY);
      meteringArea = new Camera.Area(RECTANGLE_EMPTY, MeteringRectangle.METERING_WEIGHT_DONT_CARE);
    } else {
      meteringArea = new Camera.Area(normalizedIntersected, meteringRect.getMeteringWeight());
    }

    /*
     * Calculate effective preview metering region
     */
    Rect previewMetering = meteringRect.getRect();
    if (!previewMetering.intersect(previewCrop)) {
      previewMetering.set(RECTANGLE_EMPTY);
    }

    /*
     * Calculate effective reported metering region
     * - Transform the calculated metering area back into active array space
     * - Clip it to be a subset of the reported crop region
     */
    Rect reportedMetering;
    {
      Camera.Area normalizedAreaUnbounded =
          new Camera.Area(normalizedRegionUnbounded, meteringRect.getMeteringWeight());
      WeightedRectangle reportedMeteringRect =
          convertCameraAreaToActiveArrayRectangle(
              activeArray, zoomData, normalizedAreaUnbounded, /*usePreviewCrop*/ false);
      reportedMetering = reportedMeteringRect.rect;
    }

    if (VERBOSE) {
      Log.v(
          TAG,
          String.format(
              "convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, "
                  + "previewCrop = %s, meteringArea = %s, previewMetering = %s, "
                  + "reportedMetering = %s, normalizedRegionUnbounded = %s",
              activeArray,
              meteringRect,
              previewCrop,
              stringFromArea(meteringArea),
              previewMetering,
              reportedMetering,
              normalizedRegionUnbounded));
    }

    return new MeteringData(meteringArea, previewMetering, reportedMetering);
  }