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 47 public static MeteringRectangle[] getZeroWeightRegion() { 48 return ZERO_WEIGHT_3A_REGION; 49 } 50 51 /** 52 * Convert reported camera2 AF state to OneCamera AutoFocusState. 53 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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