1/* 2 * Copyright (C) 2016 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 17package com.android.mediaframeworktest.stress; 18 19import com.android.ex.camera2.blocking.BlockingSessionCallback; 20import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 21import com.android.mediaframeworktest.Camera2SurfaceViewTestCase; 22import com.android.mediaframeworktest.helpers.Camera2Focuser; 23import com.android.mediaframeworktest.helpers.CameraTestUtils; 24import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback; 25 26import android.graphics.ImageFormat; 27import android.graphics.Point; 28import android.hardware.camera2.CameraCharacteristics; 29import android.hardware.camera2.CameraDevice; 30import android.hardware.camera2.CaptureRequest; 31import android.hardware.camera2.CaptureResult; 32import android.hardware.camera2.DngCreator; 33import android.hardware.camera2.params.MeteringRectangle; 34import android.media.Image; 35import android.media.ImageReader; 36import android.os.ConditionVariable; 37import android.util.Log; 38import android.util.Pair; 39import android.util.Rational; 40import android.util.Size; 41import android.view.Surface; 42 43import java.io.ByteArrayOutputStream; 44import java.util.ArrayList; 45import java.util.List; 46 47import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS; 48import static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES; 49import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener; 50import static com.android.mediaframeworktest.helpers.CameraTestUtils.basicValidateJpegImage; 51import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession; 52import static com.android.mediaframeworktest.helpers.CameraTestUtils.dumpFile; 53import static com.android.mediaframeworktest.helpers.CameraTestUtils.getDataFromImage; 54import static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull; 55import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader; 56 57/** 58 * <p>Tests for still capture API.</p> 59 * 60 * adb shell am instrument \ 61 * -e class com.android.mediaframeworktest.stress.Camera2StillCaptureTest#testTakePicture \ 62 * -e iterations 200 \ 63 * -e waitIntervalMs 1000 \ 64 * -e resultToFile false \ 65 * -r -w com.android.mediaframeworktest/.Camera2InstrumentationTestRunner 66 */ 67public class Camera2StillCaptureTest extends Camera2SurfaceViewTestCase { 68 private static final String TAG = "StillCaptureTest"; 69 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 70 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 71 // 60 second to accommodate the possible long exposure time. 72 private static final int MAX_REGIONS_AE_INDEX = 0; 73 private static final int MAX_REGIONS_AWB_INDEX = 1; 74 private static final int MAX_REGIONS_AF_INDEX = 2; 75 private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000; 76 private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2; 77 // 5 percent error margin for resulting metering regions 78 private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f; 79 80 @Override 81 protected void setUp() throws Exception { 82 super.setUp(); 83 } 84 85 @Override 86 protected void tearDown() throws Exception { 87 super.tearDown(); 88 } 89 90 /** 91 * Test normal still capture sequence. 92 * <p> 93 * Preview and and jpeg output streams are configured. Max still capture 94 * size is used for jpeg capture. The sequence of still capture being test 95 * is: start preview, auto focus, precapture metering (if AE is not 96 * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode 97 * is CONTINUOUS_PICTURE. 98 * </p> 99 */ 100 public void testTakePicture() throws Exception{ 101 for (String id : mCameraIds) { 102 try { 103 Log.i(TAG, "Testing basic take picture for Camera " + id); 104 openDevice(id); 105 if (!mStaticInfo.isColorOutputSupported()) { 106 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 107 continue; 108 } 109 110 // Test iteration starts... 111 for (int iteration = 0; iteration < getIterationCount(); ++iteration) { 112 Log.v(TAG, String.format("Taking pictures: %d/%d", iteration + 1, 113 getIterationCount())); 114 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, 115 /*afRegions*/null); 116 getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); 117 Thread.sleep(getTestWaitIntervalMs()); 118 } 119 } finally { 120 closeDevice(); 121 closeImageReader(); 122 } 123 } 124 } 125 126 /** 127 * Test the full raw capture use case. 128 * 129 * This includes: 130 * - Configuring the camera with a preview, jpeg, and raw output stream. 131 * - Running preview until AE/AF can settle. 132 * - Capturing with a request targeting all three output streams. 133 */ 134 public void testFullRawCapture() throws Exception { 135 for (int i = 0; i < mCameraIds.length; i++) { 136 try { 137 Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]); 138 openDevice(mCameraIds[i]); 139 if (!mStaticInfo.isCapabilitySupported( 140 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 141 Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] + 142 ". Skip the test."); 143 continue; 144 } 145 146 // Test iteration starts... 147 for (int iteration = 0; iteration < getIterationCount(); ++iteration) { 148 Log.v(TAG, String.format("Taking full RAW pictures: %d/%d", iteration + 1, 149 getIterationCount())); 150 fullRawCaptureTestByCamera(); 151 getResultPrinter().printStatus(getIterationCount(), iteration + 1, 152 mCameraIds[i]); 153 Thread.sleep(getTestWaitIntervalMs()); 154 } 155 } finally { 156 closeDevice(); 157 closeImageReader(); 158 } 159 } 160 } 161 162 /** 163 * Take a picture for a given set of 3A regions for a particular camera. 164 * <p> 165 * Before take a still capture, it triggers an auto focus and lock it first, 166 * then wait for AWB to converge and lock it, then trigger a precapture 167 * metering sequence and wait for AE converged. After capture is received, the 168 * capture result and image are validated. 169 * </p> 170 * 171 * @param aeRegions AE regions for this capture 172 * @param awbRegions AWB regions for this capture 173 * @param afRegions AF regions for this capture 174 */ 175 private void takePictureTestByCamera( 176 MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, 177 MeteringRectangle[] afRegions) throws Exception { 178 takePictureTestByCamera(aeRegions, awbRegions, afRegions, 179 /*addAeTriggerCancel*/false); 180 } 181 182 /** 183 * Take a picture for a given set of 3A regions for a particular camera. 184 * <p> 185 * Before take a still capture, it triggers an auto focus and lock it first, 186 * then wait for AWB to converge and lock it, then trigger a precapture 187 * metering sequence and wait for AE converged. After capture is received, the 188 * capture result and image are validated. If {@code addAeTriggerCancel} is true, 189 * a precapture trigger cancel will be inserted between two adjacent triggers, which 190 * should effective cancel the first trigger. 191 * </p> 192 * 193 * @param aeRegions AE regions for this capture 194 * @param awbRegions AWB regions for this capture 195 * @param afRegions AF regions for this capture 196 * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger. 197 */ 198 private void takePictureTestByCamera( 199 MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, 200 MeteringRectangle[] afRegions, boolean addAeTriggerCancel) throws Exception { 201 202 boolean hasFocuser = mStaticInfo.hasFocuser(); 203 204 Size maxStillSz = mOrderedStillSizes.get(0); 205 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 206 CaptureResult result; 207 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 208 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 209 CaptureRequest.Builder previewRequest = 210 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 211 CaptureRequest.Builder stillRequest = 212 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 213 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 214 maxStillSz, resultListener, imageListener); 215 216 // Set AE mode to ON_AUTO_FLASH if flash is available. 217 if (mStaticInfo.hasFlash()) { 218 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, 219 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 220 stillRequest.set(CaptureRequest.CONTROL_AE_MODE, 221 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 222 } 223 224 Camera2Focuser focuser = null; 225 /** 226 * Step 1: trigger an auto focus run, and wait for AF locked. 227 */ 228 boolean canSetAfRegion = hasFocuser && (afRegions != null) && 229 isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX); 230 if (hasFocuser) { 231 SimpleAutoFocusListener afListener = new SimpleAutoFocusListener(); 232 focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener, 233 mStaticInfo.getCharacteristics(), mHandler); 234 if (canSetAfRegion) { 235 stillRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions); 236 } 237 focuser.startAutoFocus(afRegions); 238 afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS); 239 } 240 241 /** 242 * Have to get the current AF mode to be used for other 3A repeating 243 * request, otherwise, the new AF mode in AE/AWB request could be 244 * different with existing repeating requests being sent by focuser, 245 * then it could make AF unlocked too early. Beside that, for still 246 * capture, AF mode must not be different with the one in current 247 * repeating request, otherwise, the still capture itself would trigger 248 * an AF mode change, and the AF lock would be lost for this capture. 249 */ 250 int currentAfMode = CaptureRequest.CONTROL_AF_MODE_OFF; 251 if (hasFocuser) { 252 currentAfMode = focuser.getCurrentAfMode(); 253 } 254 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode); 255 stillRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode); 256 257 /** 258 * Step 2: AF is already locked, wait for AWB converged, then lock it. 259 */ 260 resultListener = new SimpleCaptureCallback(); 261 boolean canSetAwbRegion = 262 (awbRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX); 263 if (canSetAwbRegion) { 264 previewRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions); 265 stillRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions); 266 } 267 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 268 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 269 waitForResultValue(resultListener, CaptureResult.CONTROL_AWB_STATE, 270 CaptureResult.CONTROL_AWB_STATE_CONVERGED, NUM_RESULTS_WAIT_TIMEOUT); 271 } else { 272 // LEGACY Devices don't have the AWB_STATE reported in results, so just wait 273 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 274 } 275 boolean canSetAwbLock = mStaticInfo.isAwbLockSupported(); 276 if (canSetAwbLock) { 277 previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true); 278 } 279 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 280 // Validate the next result immediately for region and mode. 281 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 282 mCollector.expectEquals("AWB mode in result and request should be same", 283 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE), 284 result.get(CaptureResult.CONTROL_AWB_MODE)); 285 if (canSetAwbRegion) { 286 MeteringRectangle[] resultAwbRegions = 287 getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS); 288 mCollector.expectEquals("AWB regions in result and request should be same", 289 awbRegions, resultAwbRegions); 290 } 291 292 /** 293 * Step 3: trigger an AE precapture metering sequence and wait for AE converged. 294 */ 295 resultListener = new SimpleCaptureCallback(); 296 boolean canSetAeRegion = 297 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX); 298 if (canSetAeRegion) { 299 previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions); 300 stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions); 301 } 302 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 303 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 304 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 305 mSession.capture(previewRequest.build(), resultListener, mHandler); 306 if (addAeTriggerCancel) { 307 // Cancel the current precapture trigger, then send another trigger. 308 // The camera device should behave as if the first trigger is not sent. 309 // Wait one request to make the trigger start doing something before cancel. 310 waitForNumResults(resultListener, /*numResultsWait*/ 1); 311 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 312 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL); 313 mSession.capture(previewRequest.build(), resultListener, mHandler); 314 waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER, 315 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL, 316 NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 317 // Issue another trigger 318 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 319 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 320 mSession.capture(previewRequest.build(), resultListener, mHandler); 321 } 322 waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 323 324 // Validate the next result immediately for region and mode. 325 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 326 mCollector.expectEquals("AE mode in result and request should be same", 327 previewRequest.get(CaptureRequest.CONTROL_AE_MODE), 328 result.get(CaptureResult.CONTROL_AE_MODE)); 329 if (canSetAeRegion) { 330 MeteringRectangle[] resultAeRegions = 331 getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS); 332 333 mCollector.expectMeteringRegionsAreSimilar( 334 "AE regions in result and request should be similar", 335 aeRegions, 336 resultAeRegions, 337 METERING_REGION_ERROR_PERCENT_DELTA); 338 } 339 340 /** 341 * Step 4: take a picture when all 3A are in good state. 342 */ 343 resultListener = new SimpleCaptureCallback(); 344 CaptureRequest request = stillRequest.build(); 345 mSession.capture(request, resultListener, mHandler); 346 // Validate the next result immediately for region and mode. 347 result = resultListener.getCaptureResultForRequest(request, WAIT_FOR_RESULT_TIMEOUT_MS); 348 mCollector.expectEquals("AF mode in result and request should be same", 349 stillRequest.get(CaptureRequest.CONTROL_AF_MODE), 350 result.get(CaptureResult.CONTROL_AF_MODE)); 351 if (canSetAfRegion) { 352 MeteringRectangle[] resultAfRegions = 353 getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS); 354 mCollector.expectMeteringRegionsAreSimilar( 355 "AF regions in result and request should be similar", 356 afRegions, 357 resultAfRegions, 358 METERING_REGION_ERROR_PERCENT_DELTA); 359 } 360 361 if (hasFocuser) { 362 // Unlock auto focus. 363 focuser.cancelAutoFocus(); 364 } 365 366 // validate image 367 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 368 validateJpegCapture(image, maxStillSz); 369 370 // Free image resources 371 image.close(); 372 373 stopPreview(); 374 } 375 376 private void fullRawCaptureTestByCamera() throws Exception { 377 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 378 Size maxStillSz = mOrderedStillSizes.get(0); 379 380 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 381 SimpleImageReaderListener jpegListener = new SimpleImageReaderListener(); 382 SimpleImageReaderListener rawListener = new SimpleImageReaderListener(); 383 384 Size size = mStaticInfo.getRawDimensChecked(); 385 386 if (VERBOSE) { 387 Log.v(TAG, "Testing multi capture with size " + size.toString() 388 + ", preview size " + maxPreviewSz); 389 } 390 391 // Prepare raw capture and start preview. 392 CaptureRequest.Builder previewBuilder = 393 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 394 CaptureRequest.Builder multiBuilder = 395 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 396 397 ImageReader rawReader = null; 398 ImageReader jpegReader = null; 399 400 try { 401 // Create ImageReaders. 402 rawReader = makeImageReader(size, 403 ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler); 404 jpegReader = makeImageReader(maxStillSz, 405 ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler); 406 updatePreviewSurface(maxPreviewSz); 407 408 // Configure output streams with preview and jpeg streams. 409 List<Surface> outputSurfaces = new ArrayList<Surface>(); 410 outputSurfaces.add(rawReader.getSurface()); 411 outputSurfaces.add(jpegReader.getSurface()); 412 outputSurfaces.add(mPreviewSurface); 413 mSessionListener = new BlockingSessionCallback(); 414 mSession = configureCameraSession(mCamera, outputSurfaces, 415 mSessionListener, mHandler); 416 417 // Configure the requests. 418 previewBuilder.addTarget(mPreviewSurface); 419 multiBuilder.addTarget(mPreviewSurface); 420 multiBuilder.addTarget(rawReader.getSurface()); 421 multiBuilder.addTarget(jpegReader.getSurface()); 422 423 // Start preview. 424 mSession.setRepeatingRequest(previewBuilder.build(), null, mHandler); 425 426 // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle. 427 // TODO: Do proper 3A trigger and lock (see testTakePictureTest). 428 Thread.sleep(3000); 429 430 multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 431 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON); 432 CaptureRequest multiRequest = multiBuilder.build(); 433 434 mSession.capture(multiRequest, resultListener, mHandler); 435 436 CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest, 437 NUM_RESULTS_WAIT_TIMEOUT); 438 Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 439 basicValidateJpegImage(jpegImage, maxStillSz); 440 Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 441 validateRaw16Image(rawImage, size); 442 verifyRawCaptureResult(multiRequest, result); 443 444 445 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 446 try (DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result)) { 447 dngCreator.writeImage(outputStream, rawImage); 448 } 449 450 if (DEBUG) { 451 byte[] rawBuffer = outputStream.toByteArray(); 452 String rawFileName = DEBUG_FILE_NAME_BASE + "/raw16_" + TAG + size.toString() + 453 "_cam_" + mCamera.getId() + ".dng"; 454 Log.d(TAG, "Dump raw file into " + rawFileName); 455 dumpFile(rawFileName, rawBuffer); 456 457 byte[] jpegBuffer = getDataFromImage(jpegImage); 458 String jpegFileName = DEBUG_FILE_NAME_BASE + "/jpeg_" + TAG + size.toString() + 459 "_cam_" + mCamera.getId() + ".jpg"; 460 Log.d(TAG, "Dump jpeg file into " + rawFileName); 461 dumpFile(jpegFileName, jpegBuffer); 462 } 463 464 stopPreview(); 465 } finally { 466 CameraTestUtils.closeImageReader(rawReader); 467 CameraTestUtils.closeImageReader(jpegReader); 468 rawReader = null; 469 jpegReader = null; 470 } 471 } 472 473 /** 474 * Validate that raw {@link CaptureResult}. 475 * 476 * @param rawRequest a {@link CaptureRequest} use to capture a RAW16 image. 477 * @param rawResult the {@link CaptureResult} corresponding to the given request. 478 */ 479 private void verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult) { 480 assertNotNull(rawRequest); 481 assertNotNull(rawResult); 482 483 Rational[] empty = new Rational[] { Rational.ZERO, Rational.ZERO, Rational.ZERO}; 484 Rational[] neutralColorPoint = mCollector.expectKeyValueNotNull("NeutralColorPoint", 485 rawResult, CaptureResult.SENSOR_NEUTRAL_COLOR_POINT); 486 if (neutralColorPoint != null) { 487 mCollector.expectEquals("NeutralColorPoint length", empty.length, 488 neutralColorPoint.length); 489 mCollector.expectNotEquals("NeutralColorPoint cannot be all zeroes, ", empty, 490 neutralColorPoint); 491 mCollector.expectValuesGreaterOrEqual("NeutralColorPoint", neutralColorPoint, 492 Rational.ZERO); 493 } 494 495 mCollector.expectKeyValueGreaterOrEqual(rawResult, CaptureResult.SENSOR_GREEN_SPLIT, 0.0f); 496 497 Pair<Double, Double>[] noiseProfile = mCollector.expectKeyValueNotNull("NoiseProfile", 498 rawResult, CaptureResult.SENSOR_NOISE_PROFILE); 499 if (noiseProfile != null) { 500 mCollector.expectEquals("NoiseProfile length", noiseProfile.length, 501 /*Num CFA channels*/4); 502 for (Pair<Double, Double> p : noiseProfile) { 503 mCollector.expectTrue("NoiseProfile coefficients " + p + 504 " must have: S > 0, O >= 0", p.first > 0 && p.second >= 0); 505 } 506 } 507 508 Integer hotPixelMode = mCollector.expectKeyValueNotNull("HotPixelMode", rawResult, 509 CaptureResult.HOT_PIXEL_MODE); 510 Boolean hotPixelMapMode = mCollector.expectKeyValueNotNull("HotPixelMapMode", rawResult, 511 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE); 512 Point[] hotPixelMap = rawResult.get(CaptureResult.STATISTICS_HOT_PIXEL_MAP); 513 514 Size pixelArraySize = mStaticInfo.getPixelArraySizeChecked(); 515 boolean[] availableHotPixelMapModes = mStaticInfo.getValueFromKeyNonNull( 516 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES); 517 518 if (hotPixelMode != null) { 519 Integer requestMode = mCollector.expectKeyValueNotNull(rawRequest, 520 CaptureRequest.HOT_PIXEL_MODE); 521 if (requestMode != null) { 522 mCollector.expectKeyValueEquals(rawResult, CaptureResult.HOT_PIXEL_MODE, 523 requestMode); 524 } 525 } 526 527 if (hotPixelMapMode != null) { 528 Boolean requestMapMode = mCollector.expectKeyValueNotNull(rawRequest, 529 CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE); 530 if (requestMapMode != null) { 531 mCollector.expectKeyValueEquals(rawResult, 532 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE, requestMapMode); 533 } 534 535 if (!hotPixelMapMode) { 536 mCollector.expectTrue("HotPixelMap must be empty", hotPixelMap == null || 537 hotPixelMap.length == 0); 538 } else { 539 mCollector.expectTrue("HotPixelMap must not be empty", hotPixelMap != null); 540 mCollector.expectNotNull("AvailableHotPixelMapModes must not be null", 541 availableHotPixelMapModes); 542 if (availableHotPixelMapModes != null) { 543 mCollector.expectContains("HotPixelMapMode", availableHotPixelMapModes, true); 544 } 545 546 int height = pixelArraySize.getHeight(); 547 int width = pixelArraySize.getWidth(); 548 for (Point p : hotPixelMap) { 549 mCollector.expectTrue("Hotpixel " + p + " must be in pixelArray " + 550 pixelArraySize, p.x >= 0 && p.x < width && p.y >= 0 && p.y < height); 551 } 552 } 553 } 554 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 555 556 } 557 558 //---------------------------------------------------------------- 559 //---------Below are common functions for all tests.-------------- 560 //---------------------------------------------------------------- 561 /** 562 * Validate standard raw (RAW16) capture image. 563 * 564 * @param image The raw16 format image captured 565 * @param rawSize The expected raw size 566 */ 567 private static void validateRaw16Image(Image image, Size rawSize) { 568 CameraTestUtils.validateImage(image, rawSize.getWidth(), rawSize.getHeight(), 569 ImageFormat.RAW_SENSOR, /*filePath*/null); 570 } 571 572 /** 573 * Validate JPEG capture image object sanity and test. 574 * <p> 575 * In addition to image object sanity, this function also does the decoding 576 * test, which is slower. 577 * </p> 578 * 579 * @param image The JPEG image to be verified. 580 * @param jpegSize The JPEG capture size to be verified against. 581 */ 582 private static void validateJpegCapture(Image image, Size jpegSize) { 583 CameraTestUtils.validateImage(image, jpegSize.getWidth(), jpegSize.getHeight(), 584 ImageFormat.JPEG, /*filePath*/null); 585 } 586 587 private static class SimpleAutoFocusListener implements Camera2Focuser.AutoFocusListener { 588 final ConditionVariable focusDone = new ConditionVariable(); 589 @Override 590 public void onAutoFocusLocked(boolean success) { 591 focusDone.open(); 592 } 593 594 public void waitForAutoFocusDone(long timeoutMs) { 595 if (focusDone.block(timeoutMs)) { 596 focusDone.close(); 597 } else { 598 throw new TimeoutRuntimeException("Wait for auto focus done timed out after " 599 + timeoutMs + "ms"); 600 } 601 } 602 } 603 604 private boolean isRegionsSupportedFor3A(int index) { 605 int maxRegions = 0; 606 switch (index) { 607 case MAX_REGIONS_AE_INDEX: 608 maxRegions = mStaticInfo.getAeMaxRegionsChecked(); 609 break; 610 case MAX_REGIONS_AWB_INDEX: 611 maxRegions = mStaticInfo.getAwbMaxRegionsChecked(); 612 break; 613 case MAX_REGIONS_AF_INDEX: 614 maxRegions = mStaticInfo.getAfMaxRegionsChecked(); 615 break; 616 default: 617 throw new IllegalArgumentException("Unknown algorithm index"); 618 } 619 boolean isRegionsSupported = maxRegions > 0; 620 if (index == MAX_REGIONS_AF_INDEX && isRegionsSupported) { 621 mCollector.expectTrue( 622 "Device reports non-zero max AF region count for a camera without focuser!", 623 mStaticInfo.hasFocuser()); 624 isRegionsSupported = isRegionsSupported && mStaticInfo.hasFocuser(); 625 } 626 627 return isRegionsSupported; 628 } 629} 630