1 /* 2 * Copyright 2013 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 android.hardware.camera2.cts; 18 19 import android.content.Context; 20 import android.graphics.ImageFormat; 21 import android.hardware.camera2.CameraCharacteristics; 22 import android.hardware.camera2.CameraDevice; 23 import android.hardware.camera2.CameraManager; 24 import android.hardware.camera2.CameraMetadata; 25 import android.hardware.camera2.CaptureFailure; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.CaptureResult; 28 import android.hardware.camera2.Size; 29 import static android.hardware.camera2.cts.CameraTestUtils.*; 30 import android.media.ImageReader; 31 import android.os.Handler; 32 import android.os.HandlerThread; 33 import android.test.AndroidTestCase; 34 import android.util.Log; 35 import android.view.Surface; 36 37 import com.android.ex.camera2.blocking.BlockingStateListener; 38 import static com.android.ex.camera2.blocking.BlockingStateListener.*; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.concurrent.LinkedBlockingQueue; 43 import java.util.concurrent.TimeUnit; 44 45 public class CameraCaptureResultTest extends AndroidTestCase { 46 private static final String TAG = "CameraCaptureResultTest"; 47 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 48 49 private CameraManager mCameraManager; 50 private HandlerThread mHandlerThread; 51 private Handler mHandler; 52 private ImageReader mImageReader; 53 private Surface mSurface; 54 private BlockingStateListener mCameraListener; 55 56 private static final int MAX_NUM_IMAGES = 5; 57 private static final int NUM_FRAMES_VERIFIED = 300; 58 private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000; 59 60 // List that includes all public keys from CaptureResult 61 List<CameraMetadata.Key<?>> mAllKeys; 62 63 // List tracking the failed test keys. 64 List<CameraMetadata.Key<?>> mFailedKeys = new ArrayList<CameraMetadata.Key<?>>(); 65 66 @Override setContext(Context context)67 public void setContext(Context context) { 68 mAllKeys = getAllCaptureResultKeys(); 69 super.setContext(context); 70 } 71 72 @Override setUp()73 protected void setUp() throws Exception { 74 super.setUp(); 75 mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); 76 assertNotNull("Can't connect to camera manager", mCameraManager); 77 mHandlerThread = new HandlerThread(TAG); 78 mHandlerThread.start(); 79 mHandler = new Handler(mHandlerThread.getLooper()); 80 mCameraListener = new BlockingStateListener(); 81 mFailedKeys.clear(); 82 } 83 84 @Override tearDown()85 protected void tearDown() throws Exception { 86 mHandlerThread.quitSafely(); 87 super.tearDown(); 88 } 89 testCameraCaptureResultAllKeys()90 public void testCameraCaptureResultAllKeys() throws Exception { 91 /** 92 * Hardcode a key waiver list for the keys we want to skip the sanity check. 93 * FIXME: We need get ride of this list, see bug 11116270. 94 */ 95 List<CameraMetadata.Key<?>> waiverkeys = new ArrayList<CameraMetadata.Key<?>>(); 96 waiverkeys.add(CaptureResult.EDGE_MODE); 97 waiverkeys.add(CaptureResult.JPEG_GPS_COORDINATES); 98 waiverkeys.add(CaptureResult.JPEG_GPS_PROCESSING_METHOD); 99 waiverkeys.add(CaptureResult.JPEG_GPS_TIMESTAMP); 100 waiverkeys.add(CaptureResult.JPEG_ORIENTATION); 101 waiverkeys.add(CaptureResult.JPEG_QUALITY); 102 waiverkeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY); 103 waiverkeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE); 104 waiverkeys.add(CaptureResult.SENSOR_TEMPERATURE); 105 waiverkeys.add(CaptureResult.TONEMAP_CURVE_BLUE); 106 waiverkeys.add(CaptureResult.TONEMAP_CURVE_GREEN); 107 waiverkeys.add(CaptureResult.TONEMAP_CURVE_RED); 108 waiverkeys.add(CaptureResult.TONEMAP_MODE); 109 waiverkeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_GAINS); 110 waiverkeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_TRANSFORM); 111 waiverkeys.add(CaptureResult.STATISTICS_SCENE_FLICKER); 112 113 String[] ids = mCameraManager.getCameraIdList(); 114 for (int i = 0; i < ids.length; i++) { 115 CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]); 116 assertNotNull("CameraCharacteristics shouldn't be null", props); 117 Integer hwLevel = props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 118 if (hwLevel != CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL) { 119 continue; 120 } 121 // TODO: check for LIMITED keys 122 123 CameraDevice camera = null; 124 try { 125 Size[] sizes = CameraTestUtils.getSupportedSizeForFormat( 126 ImageFormat.YUV_420_888, ids[i], mCameraManager); 127 CameraTestUtils.assertArrayNotEmpty(sizes, "Available sizes shouldn't be empty"); 128 createDefaultSurface(sizes[0]); 129 130 if (VERBOSE) { 131 Log.v(TAG, "Testing camera " + ids[i] + "for size " + sizes[0].toString()); 132 } 133 134 camera = CameraTestUtils.openCamera( 135 mCameraManager, ids[i], mCameraListener, mHandler); 136 assertNotNull( 137 String.format("Failed to open camera device %s", ids[i]), camera); 138 mCameraListener.waitForState(STATE_UNCONFIGURED, CAMERA_OPEN_TIMEOUT_MS); 139 140 List<Surface> outputSurfaces = new ArrayList<Surface>(1); 141 outputSurfaces.add(mSurface); 142 camera.configureOutputs(outputSurfaces); 143 mCameraListener.waitForState(STATE_BUSY, CAMERA_BUSY_TIMEOUT_MS); 144 mCameraListener.waitForState(STATE_IDLE, CAMERA_IDLE_TIMEOUT_MS); 145 146 CaptureRequest.Builder requestBuilder = 147 camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 148 assertNotNull("Failed to create capture request", requestBuilder); 149 requestBuilder.addTarget(mSurface); 150 151 // Enable face detection if supported 152 byte[] faceModes = props.get( 153 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES); 154 assertNotNull("Available face detection modes shouldn't be null", faceModes); 155 for (int m = 0; m < faceModes.length; m++) { 156 if (faceModes[m] == CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL) { 157 if (VERBOSE) { 158 Log.v(TAG, "testCameraCaptureResultAllKeys - " + 159 "setting facedetection mode to full"); 160 } 161 requestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, 162 (int)faceModes[m]); 163 } 164 } 165 166 // Enable lensShading mode, it should be supported by full mode device. 167 requestBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 168 CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON); 169 170 SimpleCaptureListener captureListener = new SimpleCaptureListener(); 171 camera.setRepeatingRequest(requestBuilder.build(), captureListener, mHandler); 172 173 for (int m = 0; m < NUM_FRAMES_VERIFIED; m++) { 174 if(VERBOSE) { 175 Log.v(TAG, "Testing frame " + m); 176 } 177 validateCaptureResult( 178 captureListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS), 179 waiverkeys); 180 } 181 182 // Stop repeat, wait for captures to complete, and disconnect from surfaces 183 camera.configureOutputs(/*outputs*/ null); 184 mCameraListener.waitForState(STATE_BUSY, CAMERA_BUSY_TIMEOUT_MS); 185 mCameraListener.waitForState(STATE_UNCONFIGURED, CAMERA_IDLE_TIMEOUT_MS); 186 // Camera has disconnected, clear out the reader 187 mSurface.release(); 188 mImageReader.close(); 189 } finally { 190 if (camera != null) { 191 camera.close(); 192 } 193 } 194 195 } 196 } 197 validateCaptureResult(CaptureResult result, List<CameraMetadata.Key<?>> skippedKeys)198 private void validateCaptureResult(CaptureResult result, 199 List<CameraMetadata.Key<?>> skippedKeys) throws Exception { 200 for (CameraMetadata.Key<?> key : mAllKeys) { 201 if (!skippedKeys.contains(key) && result.get(key) == null) { 202 mFailedKeys.add(key); 203 } 204 } 205 206 StringBuffer failedKeyNames = new StringBuffer("Below Keys have null values:\n"); 207 for (CameraMetadata.Key<?> key : mFailedKeys) { 208 failedKeyNames.append(key.getName() + "\n"); 209 } 210 211 assertTrue("Some keys have null values, " + failedKeyNames.toString(), 212 mFailedKeys.isEmpty()); 213 } 214 215 private static class SimpleCaptureListener extends CameraDevice.CaptureListener { 216 LinkedBlockingQueue<CaptureResult> mQueue = new LinkedBlockingQueue<CaptureResult>(); 217 218 @Override onCaptureStarted(CameraDevice camera, CaptureRequest request, long timestamp)219 public void onCaptureStarted(CameraDevice camera, CaptureRequest request, long timestamp) 220 { 221 } 222 223 @Override onCaptureCompleted(CameraDevice camera, CaptureRequest request, CaptureResult result)224 public void onCaptureCompleted(CameraDevice camera, CaptureRequest request, 225 CaptureResult result) { 226 try { 227 mQueue.put(result); 228 } catch (InterruptedException e) { 229 throw new UnsupportedOperationException( 230 "Can't handle InterruptedException in onCaptureCompleted"); 231 } 232 } 233 234 @Override onCaptureFailed(CameraDevice camera, CaptureRequest request, CaptureFailure failure)235 public void onCaptureFailed(CameraDevice camera, CaptureRequest request, 236 CaptureFailure failure) { 237 } 238 239 @Override onCaptureSequenceCompleted(CameraDevice camera, int sequenceId, int frameNumber)240 public void onCaptureSequenceCompleted(CameraDevice camera, int sequenceId, 241 int frameNumber) { 242 } 243 getCaptureResult(long timeout)244 public CaptureResult getCaptureResult(long timeout) throws InterruptedException { 245 CaptureResult result = mQueue.poll(timeout, TimeUnit.MILLISECONDS); 246 assertNotNull("Wait for a capture result timed out in " + timeout + "ms", result); 247 return result; 248 } 249 } 250 createDefaultSurface(Size sz)251 private void createDefaultSurface(Size sz) { 252 mImageReader = 253 ImageReader.newInstance(sz.getWidth(), 254 sz.getHeight(), 255 ImageFormat.YUV_420_888, 256 MAX_NUM_IMAGES); 257 mImageReader.setOnImageAvailableListener(new ImageDropperListener(), mHandler); 258 mSurface = mImageReader.getSurface(); 259 } 260 261 /** 262 * TODO: Use CameraCharacteristics.getAvailableCaptureResultKeys() once we can filter out 263 * @hide keys. 264 * 265 */ 266 267 /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ 268 * The key entries below this point are generated from metadata 269 * definitions in /system/media/camera/docs. Do not modify by hand or 270 * modify the comment blocks at the start or end. 271 *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/ 272 getAllCaptureResultKeys()273 private static List<CameraMetadata.Key<?>> getAllCaptureResultKeys() { 274 ArrayList<CameraMetadata.Key<?>> resultKeys = new ArrayList<CameraMetadata.Key<?>>(); 275 resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM); 276 resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS); 277 resultKeys.add(CaptureResult.CONTROL_AE_REGIONS); 278 resultKeys.add(CaptureResult.CONTROL_AF_MODE); 279 resultKeys.add(CaptureResult.CONTROL_AF_REGIONS); 280 resultKeys.add(CaptureResult.CONTROL_AWB_MODE); 281 resultKeys.add(CaptureResult.CONTROL_AWB_REGIONS); 282 resultKeys.add(CaptureResult.CONTROL_MODE); 283 resultKeys.add(CaptureResult.CONTROL_AE_STATE); 284 resultKeys.add(CaptureResult.CONTROL_AF_STATE); 285 resultKeys.add(CaptureResult.CONTROL_AWB_STATE); 286 resultKeys.add(CaptureResult.EDGE_MODE); 287 resultKeys.add(CaptureResult.FLASH_MODE); 288 resultKeys.add(CaptureResult.FLASH_STATE); 289 resultKeys.add(CaptureResult.JPEG_GPS_COORDINATES); 290 resultKeys.add(CaptureResult.JPEG_GPS_PROCESSING_METHOD); 291 resultKeys.add(CaptureResult.JPEG_GPS_TIMESTAMP); 292 resultKeys.add(CaptureResult.JPEG_ORIENTATION); 293 resultKeys.add(CaptureResult.JPEG_QUALITY); 294 resultKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY); 295 resultKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE); 296 resultKeys.add(CaptureResult.LENS_APERTURE); 297 resultKeys.add(CaptureResult.LENS_FILTER_DENSITY); 298 resultKeys.add(CaptureResult.LENS_FOCAL_LENGTH); 299 resultKeys.add(CaptureResult.LENS_FOCUS_DISTANCE); 300 resultKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE); 301 resultKeys.add(CaptureResult.LENS_FOCUS_RANGE); 302 resultKeys.add(CaptureResult.LENS_STATE); 303 resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE); 304 resultKeys.add(CaptureResult.REQUEST_FRAME_COUNT); 305 resultKeys.add(CaptureResult.SCALER_CROP_REGION); 306 resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME); 307 resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION); 308 resultKeys.add(CaptureResult.SENSOR_SENSITIVITY); 309 resultKeys.add(CaptureResult.SENSOR_TIMESTAMP); 310 resultKeys.add(CaptureResult.SENSOR_TEMPERATURE); 311 resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE); 312 resultKeys.add(CaptureResult.STATISTICS_FACE_IDS); 313 resultKeys.add(CaptureResult.STATISTICS_FACE_LANDMARKS); 314 resultKeys.add(CaptureResult.STATISTICS_FACE_RECTANGLES); 315 resultKeys.add(CaptureResult.STATISTICS_FACE_SCORES); 316 resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP); 317 resultKeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_GAINS); 318 resultKeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_TRANSFORM); 319 resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER); 320 resultKeys.add(CaptureResult.TONEMAP_CURVE_BLUE); 321 resultKeys.add(CaptureResult.TONEMAP_CURVE_GREEN); 322 resultKeys.add(CaptureResult.TONEMAP_CURVE_RED); 323 resultKeys.add(CaptureResult.TONEMAP_MODE); 324 resultKeys.add(CaptureResult.BLACK_LEVEL_LOCK); 325 326 // Add STATISTICS_FACES key separately here because it is not 327 // defined in metadata xml file. 328 resultKeys.add(CaptureResult.STATISTICS_FACES); 329 330 return resultKeys; 331 } 332 333 /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ 334 * End generated code 335 *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ 336 } 337