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;
18 
19 import android.graphics.PointF;
20 import android.graphics.Rect;
21 import android.hardware.camera2.CameraCharacteristics;
22 import android.hardware.camera2.CaptureResult;
23 import android.hardware.camera2.params.MeteringRectangle;
24 
25 import com.android.camera.debug.Log;
26 import com.android.camera.one.OneCamera;
27 import com.android.camera.one.Settings3A;
28 import com.android.camera.util.CameraUtil;
29 
30 /**
31  * Helper class to implement auto focus and 3A in camera2-based
32  * {@link com.android.camera.one.OneCamera} implementations.
33  */
34 public class AutoFocusHelper {
35     private static final Log.Tag TAG = new Log.Tag("OneCameraAFHelp");
36 
37     /** camera2 API metering region weight. */
38     private static final int CAMERA2_REGION_WEIGHT = (int)
39         (CameraUtil.lerp(MeteringRectangle.METERING_WEIGHT_MIN, MeteringRectangle.METERING_WEIGHT_MAX,
40                         Settings3A.getMeteringRegionWeight()));
41 
42     /** Zero weight 3A region, to reset regions per API. */
43     private static final MeteringRectangle[] ZERO_WEIGHT_3A_REGION = new MeteringRectangle[]{
44             new MeteringRectangle(0, 0, 0, 0, 0)
45     };
46 
getZeroWeightRegion()47     public static MeteringRectangle[] getZeroWeightRegion() {
48         return ZERO_WEIGHT_3A_REGION;
49     }
50 
51     /**
52      * Convert reported camera2 AF state to OneCamera AutoFocusState.
53      */
stateFromCamera2State(int state)54     public static OneCamera.AutoFocusState stateFromCamera2State(int state) {
55         switch (state) {
56             case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:
57                 return OneCamera.AutoFocusState.ACTIVE_SCAN;
58             case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
59                 return OneCamera.AutoFocusState.PASSIVE_SCAN;
60             case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
61                 return OneCamera.AutoFocusState.PASSIVE_FOCUSED;
62             case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
63                 return OneCamera.AutoFocusState.ACTIVE_FOCUSED;
64             case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
65                 return OneCamera.AutoFocusState.PASSIVE_UNFOCUSED;
66             case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
67                 return OneCamera.AutoFocusState.ACTIVE_UNFOCUSED;
68             default:
69                 return OneCamera.AutoFocusState.INACTIVE;
70         }
71     }
72 
73     /**
74      * Complain if CONTROL_AF_STATE is not present in result.
75      * Could indicate bug in API implementation.
76      */
checkControlAfState(CaptureResult result)77     public static boolean checkControlAfState(CaptureResult result) {
78         boolean missing = result.get(CaptureResult.CONTROL_AF_STATE) == null;
79         if (missing) {
80             // throw new IllegalStateException("CaptureResult missing CONTROL_AF_STATE.");
81             Log.e(TAG, "\n!!!! TotalCaptureResult missing CONTROL_AF_STATE. !!!!\n ");
82         }
83         return !missing;
84     }
85 
86     /**
87      * Complain if LENS_STATE is not present in result.
88      * Could indicate bug in API implementation.
89      */
checkLensState(CaptureResult result)90     public static boolean checkLensState(CaptureResult result) {
91         boolean missing = result.get(CaptureResult.LENS_STATE) == null;
92         if (missing) {
93             // throw new IllegalStateException("CaptureResult missing LENS_STATE.");
94             Log.e(TAG, "\n!!!! TotalCaptureResult missing LENS_STATE. !!!!\n ");
95         }
96         return !missing;
97     }
98 
99 
logExtraFocusInfo(CaptureResult result)100     public static void logExtraFocusInfo(CaptureResult result) {
101         if(!checkControlAfState(result) || !checkLensState(result)) {
102             return;
103         }
104 
105         Object tag = result.getRequest().getTag();
106 
107         Log.v(TAG, String.format("af_state:%-17s  lens_foc_dist:%.3f  lens_state:%-10s  %s",
108                 controlAFStateToString(result.get(CaptureResult.CONTROL_AF_STATE)),
109                 result.get(CaptureResult.LENS_FOCUS_DISTANCE),
110                 lensStateToString(result.get(CaptureResult.LENS_STATE)),
111                 (tag == null) ? "" : "[" + tag +"]"
112         ));
113     }
114 
115     /** Compute 3A regions for a sensor-referenced touch coordinate.
116      * Returns a MeteringRectangle[] with length 1.
117      *
118      * @param nx x coordinate of the touch point, in normalized portrait coordinates.
119      * @param ny y coordinate of the touch point, in normalized portrait coordinates.
120      * @param fraction Fraction in [0,1]. Multiplied by min(cropRegion.width(), cropRegion.height())
121      *             to determine the side length of the square MeteringRectangle.
122      * @param cropRegion Crop region of the image.
123      * @param sensorOrientation sensor orientation as defined by
124      *             CameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION).
125      */
regionsForNormalizedCoord(float nx, float ny, float fraction, final Rect cropRegion, int sensorOrientation)126     private static MeteringRectangle[] regionsForNormalizedCoord(float nx, float ny,
127         float fraction, final Rect cropRegion, int sensorOrientation) {
128         // Compute half side length in pixels.
129         int minCropEdge = Math.min(cropRegion.width(), cropRegion.height());
130         int halfSideLength = (int) (0.5f * fraction * minCropEdge);
131 
132         // Compute the output MeteringRectangle in sensor space.
133         // nx, ny is normalized to the screen.
134         // Crop region itself is specified in sensor coordinates.
135 
136         // Normalized coordinates, now rotated into sensor space.
137         PointF nsc = CameraUtil.normalizedSensorCoordsForNormalizedDisplayCoords(
138             nx, ny, sensorOrientation);
139 
140         int xCenterSensor = (int)(cropRegion.left + nsc.x * cropRegion.width());
141         int yCenterSensor = (int)(cropRegion.top + nsc.y * cropRegion.height());
142 
143         Rect meteringRegion = new Rect(xCenterSensor - halfSideLength,
144             yCenterSensor - halfSideLength,
145             xCenterSensor + halfSideLength,
146             yCenterSensor + halfSideLength);
147 
148         // Clamp meteringRegion to cropRegion.
149         meteringRegion.left = CameraUtil.clamp(meteringRegion.left, cropRegion.left, cropRegion.right);
150         meteringRegion.top = CameraUtil.clamp(meteringRegion.top, cropRegion.top, cropRegion.bottom);
151         meteringRegion.right = CameraUtil.clamp(meteringRegion.right, cropRegion.left, cropRegion.right);
152         meteringRegion.bottom = CameraUtil.clamp(meteringRegion.bottom, cropRegion.top, cropRegion.bottom);
153 
154         return new MeteringRectangle[]{new MeteringRectangle(meteringRegion, CAMERA2_REGION_WEIGHT)};
155     }
156 
157     /**
158      * Return AF region(s) for a sensor-referenced touch coordinate.
159      *
160      * <p>
161      * Normalized coordinates are referenced to portrait preview window with
162      * (0, 0) top left and (1, 1) bottom right. Rotation has no effect.
163      * </p>
164      *
165      * @return AF region(s).
166      */
afRegionsForNormalizedCoord(float nx, float ny, final Rect cropRegion, int sensorOrientation)167     public static MeteringRectangle[] afRegionsForNormalizedCoord(float nx,
168         float ny, final Rect cropRegion, int sensorOrientation) {
169         return regionsForNormalizedCoord(nx, ny, Settings3A.getAutoFocusRegionWidth(),
170             cropRegion, sensorOrientation);
171     }
172 
173     /**
174      * Return AE region(s) for a sensor-referenced touch coordinate.
175      *
176      * <p>
177      * Normalized coordinates are referenced to portrait preview window with
178      * (0, 0) top left and (1, 1) bottom right. Rotation has no effect.
179      * </p>
180      *
181      * @return AE region(s).
182      */
aeRegionsForNormalizedCoord(float nx, float ny, final Rect cropRegion, int sensorOrientation)183     public static MeteringRectangle[] aeRegionsForNormalizedCoord(float nx,
184         float ny, final Rect cropRegion, int sensorOrientation) {
185         return regionsForNormalizedCoord(nx, ny, Settings3A.getMeteringRegionWidth(),
186             cropRegion, sensorOrientation);
187     }
188 
189     /**
190      * [Gcam mode only]: Return AE region(s) for a sensor-referenced touch coordinate.
191      *
192      * <p>
193      * Normalized coordinates are referenced to portrait preview window with
194      * (0, 0) top left and (1, 1) bottom right. Rotation has no effect.
195      * </p>
196      *
197      * @return AE region(s).
198      */
gcamAERegionsForNormalizedCoord(float nx, float ny, final Rect cropRegion, int sensorOrientation)199     public static MeteringRectangle[] gcamAERegionsForNormalizedCoord(float nx,
200         float ny, final Rect cropRegion, int sensorOrientation) {
201         return regionsForNormalizedCoord(nx, ny, Settings3A.getGcamMeteringRegionFraction(),
202             cropRegion, sensorOrientation);
203     }
204 
205     /**
206      * Calculates sensor crop region for a zoom level (zoom >= 1.0).
207      *
208      * @return Crop region.
209      */
cropRegionForZoom(CameraCharacteristics characteristics, float zoom)210     public static Rect cropRegionForZoom(CameraCharacteristics characteristics, float zoom) {
211         Rect sensor = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
212         int xCenter = sensor.width() / 2;
213         int yCenter = sensor.height() / 2;
214         int xDelta = (int) (0.5f * sensor.width() / zoom);
215         int yDelta = (int) (0.5f * sensor.height() / zoom);
216         return new Rect(xCenter - xDelta, yCenter - yDelta, xCenter + xDelta, yCenter + yDelta);
217     }
218 
219     /**
220      * Utility function: converts CaptureResult.CONTROL_AF_STATE to String.
221      */
controlAFStateToString(int controlAFState)222     private static String controlAFStateToString(int controlAFState) {
223         switch (controlAFState) {
224             case CaptureResult.CONTROL_AF_STATE_INACTIVE:
225                 return "inactive";
226             case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
227                 return "passive_scan";
228             case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
229                 return "passive_focused";
230             case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:
231                 return "active_scan";
232             case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
233                 return "focus_locked";
234             case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
235                 return "not_focus_locked";
236             case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
237                 return "passive_unfocused";
238             default:
239                 return "unknown";
240         }
241     }
242 
243     /**
244      * Utility function: converts CaptureResult.LENS_STATE to String.
245      */
lensStateToString(int lensState)246     private static String lensStateToString(int lensState) {
247         switch (lensState) {
248             case CaptureResult.LENS_STATE_MOVING:
249                 return "moving";
250             case CaptureResult.LENS_STATE_STATIONARY:
251                 return "stationary";
252             default:
253                 return "unknown";
254         }
255     }
256 
257 }
258