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