1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera.one.v2.autofocus; 18 19 import android.graphics.PointF; 20 import android.graphics.Rect; 21 import android.hardware.camera2.CaptureRequest; 22 import android.hardware.camera2.params.MeteringRectangle; 23 24 import com.android.camera.one.Settings3A; 25 import com.google.common.base.Preconditions; 26 27 final class PointMeteringParameters implements MeteringParameters { 28 private final PointF mAFPoint; 29 private final PointF mAEPoint; 30 private final int mSensorOrientation; 31 private final Settings3A mSettings3A; 32 PointMeteringParameters(PointF afPoint, PointF aePoint, int sensorOrientation, Settings3A settings3A)33 private PointMeteringParameters(PointF afPoint, PointF aePoint, int sensorOrientation, 34 Settings3A settings3A) { 35 mAFPoint = afPoint; 36 mAEPoint = aePoint; 37 mSensorOrientation = sensorOrientation; 38 mSettings3A = settings3A; 39 } 40 41 /** 42 * Constructs new MeteringParameters. 43 * 44 * @param afPoint The center of the desired AF metering region, in 45 * normalized portrait coordinates such that (0, 0) is top left 46 * and (1, 1) is bottom right. 47 * @param aePoint The center of the desired AE metering region, in 48 * normalized portrait coordinates such that (0, 0) is top left 49 * and (1, 1) is bottom right. 50 * @param sensorOrientation sensor orientation as defined by 51 * CameraCharacteristics 52 * .get(CameraCharacteristics.SENSOR_ORIENTATION). 53 * @param settings3A 3A settings. 54 */ createForNormalizedCoordinates( PointF afPoint, PointF aePoint, int sensorOrientation, Settings3A settings3A)55 public static PointMeteringParameters createForNormalizedCoordinates( 56 PointF afPoint, 57 PointF aePoint, 58 int sensorOrientation, 59 Settings3A settings3A) { 60 Preconditions.checkArgument(sensorOrientation % 90 == 0, "sensorOrientation must be a " + 61 "multiple of 90"); 62 Preconditions.checkArgument(sensorOrientation >= 0, "sensorOrientation must not be " + 63 "negative"); 64 sensorOrientation %= 360; 65 66 return new PointMeteringParameters(afPoint, aePoint, sensorOrientation, 67 settings3A); 68 } 69 70 /** 71 * @param cropRegion The current crop region, see 72 * {@link CaptureRequest#SCALER_CROP_REGION}. 73 */ 74 @Override getAERegions(Rect cropRegion)75 public MeteringRectangle[] getAERegions(Rect cropRegion) { 76 return new MeteringRectangle[] { 77 regionForNormalizedCoord(mAEPoint, cropRegion) 78 }; 79 } 80 81 /** 82 * @param cropRegion The current crop region, see 83 * {@link CaptureRequest#SCALER_CROP_REGION}. 84 */ 85 @Override getAFRegions(Rect cropRegion)86 public MeteringRectangle[] getAFRegions(Rect cropRegion) { 87 return new MeteringRectangle[] { 88 regionForNormalizedCoord(mAFPoint, cropRegion) 89 }; 90 } 91 regionForNormalizedCoord(PointF point, Rect cropRegion)92 private MeteringRectangle regionForNormalizedCoord(PointF point, 93 Rect cropRegion) { 94 // Compute half side length in pixels. 95 int minCropEdge = Math.min(cropRegion.width(), cropRegion.height()); 96 int halfSideLength = (int) (0.5f * mSettings3A.getMeteringRegionFraction() * minCropEdge); 97 98 // Compute the output MeteringRectangle in sensor space. 99 // point is normalized to the screen. 100 // Crop region itself is specified in sensor coordinates (see 101 // CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE). 102 103 // Normalized coordinates, now rotated into sensor space. 104 PointF nsc = transformPortraitCoordinatesToSensorCoordinates(point); 105 106 int xCenterSensor = (int) (cropRegion.left + nsc.x * cropRegion.width()); 107 int yCenterSensor = (int) (cropRegion.top + nsc.y * cropRegion.height()); 108 109 Rect meteringRegion = new Rect(xCenterSensor - halfSideLength, 110 yCenterSensor - halfSideLength, 111 xCenterSensor + halfSideLength, 112 yCenterSensor + halfSideLength); 113 114 // Clamp meteringRegion to cropRegion. 115 meteringRegion.left = clamp(meteringRegion.left, cropRegion.left, 116 cropRegion.right); 117 meteringRegion.top = clamp(meteringRegion.top, cropRegion.top, cropRegion.bottom); 118 meteringRegion.right = clamp(meteringRegion.right, cropRegion.left, 119 cropRegion.right); 120 meteringRegion.bottom = clamp(meteringRegion.bottom, cropRegion.top, 121 cropRegion.bottom); 122 123 return new MeteringRectangle(meteringRegion, mSettings3A.getMeteringWeight()); 124 } 125 126 /** 127 * Given (nx, ny) \in [0, 1]^2, in the display's portrait coordinate system, 128 * returns normalized sensor coordinates \in [0, 1]^2 depending on how the 129 * sensor's orientation \in {0, 90, 180, 270}. 130 */ transformPortraitCoordinatesToSensorCoordinates( PointF point)131 private PointF transformPortraitCoordinatesToSensorCoordinates( 132 PointF point) { 133 switch (mSensorOrientation) { 134 case 0: 135 return point; 136 case 90: 137 return new PointF(point.y, 1.0f - point.x); 138 case 180: 139 return new PointF(1.0f - point.x, 1.0f - point.y); 140 case 270: 141 return new PointF(1.0f - point.y, point.x); 142 default: 143 // Impossible exception. 144 throw new IllegalArgumentException("Unsupported Sensor Orientation"); 145 } 146 } 147 clamp(int value, int min, int max)148 private int clamp(int value, int min, int max) { 149 return Math.min(Math.max(value, min), max); 150 } 151 } 152