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