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 android.hardware.camera2.cts; 18 19 import static android.hardware.camera2.cts.CameraTestUtils.*; 20 21 import android.graphics.Bitmap; 22 import android.graphics.Bitmap.Config; 23 import android.graphics.ImageFormat; 24 import android.graphics.Point; 25 import android.graphics.Rect; 26 import android.hardware.camera2.CameraCharacteristics; 27 import android.hardware.camera2.CameraDevice; 28 import android.hardware.camera2.CaptureRequest; 29 import android.hardware.camera2.CaptureResult; 30 import android.hardware.camera2.DngCreator; 31 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 32 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener; 33 import android.hardware.camera2.cts.helpers.Camera2Focuser; 34 import android.hardware.camera2.cts.helpers.StaticMetadata; 35 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase; 36 import android.hardware.camera2.params.DynamicRangeProfiles; 37 import android.hardware.camera2.params.MeteringRectangle; 38 import android.hardware.camera2.params.OutputConfiguration; 39 import android.location.Location; 40 import android.location.LocationManager; 41 import android.media.Image; 42 import android.media.ImageReader; 43 import android.os.ConditionVariable; 44 import android.platform.test.annotations.RequiresFlagsEnabled; 45 import android.util.Log; 46 import android.util.Pair; 47 import android.util.Range; 48 import android.util.Rational; 49 import android.util.Size; 50 import android.view.Surface; 51 52 import com.android.ex.camera2.blocking.BlockingSessionCallback; 53 import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 54 import com.android.internal.camera.flags.Flags; 55 56 import junit.framework.Assert; 57 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 import org.junit.runners.Parameterized; 61 62 import java.io.ByteArrayOutputStream; 63 import java.util.ArrayList; 64 import java.util.Arrays; 65 import java.util.List; 66 import java.util.Set; 67 68 @RunWith(Parameterized.class) 69 public class StillCaptureTest extends Camera2SurfaceViewTestCase { 70 private static final String TAG = "StillCaptureTest"; 71 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 72 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 73 // 60 second to accommodate the possible long exposure time. 74 private static final int RELAXED_CAPTURE_IMAGE_TIMEOUT_MS = CAPTURE_IMAGE_TIMEOUT_MS + 1000; 75 private static final int MAX_REGIONS_AE_INDEX = 0; 76 private static final int MAX_REGIONS_AWB_INDEX = 1; 77 private static final int MAX_REGIONS_AF_INDEX = 2; 78 private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000; 79 private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2; 80 private static final int NUM_FRAMES_WAITED = 30; 81 // 5 percent error margin for resulting metering regions 82 private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f; 83 // Android CDD (5.0 and newer) required number of simultenous bitmap allocations for camera 84 private static final int MAX_ALLOCATED_BITMAPS = 3; 85 86 @Override setUp()87 public void setUp() throws Exception { 88 super.setUp(); 89 } 90 91 @Override tearDown()92 public void tearDown() throws Exception { 93 super.tearDown(); 94 } 95 96 /** 97 * Test JPEG capture exif fields for each camera. 98 */ 99 @Test testJpegExif()100 public void testJpegExif() throws Exception { 101 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 102 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 103 try { 104 Log.i(TAG, "Testing JPEG exif for Camera " + cameraIdsUnderTest[i]); 105 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) { 106 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 107 " does not support color outputs, skipping"); 108 continue; 109 } 110 openDevice(cameraIdsUnderTest[i]); 111 Size maxJpegSize = mOrderedStillSizes.get(0); 112 stillExifTestByCamera(ImageFormat.JPEG, maxJpegSize); 113 } finally { 114 closeDevice(); 115 closeImageReader(); 116 } 117 } 118 } 119 120 /** 121 * Test HEIC capture exif fields for each camera. 122 */ 123 @Test testHeicExif()124 public void testHeicExif() throws Exception { 125 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 126 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 127 try { 128 Log.i(TAG, "Testing HEIC exif for Camera " + cameraIdsUnderTest[i]); 129 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) { 130 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 131 " does not support color outputs, skipping"); 132 continue; 133 } 134 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isHeicSupported()) { 135 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 136 " does not support HEIC, skipping"); 137 continue; 138 } 139 140 openDevice(cameraIdsUnderTest[i]); 141 142 // Test maximum Heic size capture 143 List<Size> orderedHeicSizes = CameraTestUtils.getSupportedHeicSizes( 144 cameraIdsUnderTest[i], mCameraManager, null/*bound*/); 145 Size maxHeicSize = orderedHeicSizes.get(0); 146 stillExifTestByCamera(ImageFormat.HEIC, maxHeicSize); 147 148 // Test preview size Heic capture 149 Size previewSize = mOrderedPreviewSizes.get(0); 150 stillExifTestByCamera(ImageFormat.HEIC, previewSize); 151 152 } finally { 153 closeDevice(); 154 closeImageReader(); 155 } 156 } 157 } 158 159 /** 160 * Test dynamic depth capture along with preview for each camera. 161 */ 162 @Test testDynamicDepthCapture()163 public void testDynamicDepthCapture() throws Exception { 164 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 165 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 166 try { 167 Log.i(TAG, "Testing dynamic depth for Camera " + cameraIdsUnderTest[i]); 168 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) { 169 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 170 " does not support color outputs, skipping"); 171 continue; 172 } 173 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isDepthJpegSupported()) { 174 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 175 " does not support dynamic depth, skipping"); 176 continue; 177 } 178 179 openDevice(cameraIdsUnderTest[i]); 180 181 // Check the maximum supported size. 182 List<Size> orderedDepthJpegSizes = CameraTestUtils.getSortedSizesForFormat( 183 cameraIdsUnderTest[i], mCameraManager, ImageFormat.DEPTH_JPEG, null/*bound*/); 184 Size maxDepthJpegSize = orderedDepthJpegSizes.get(0); 185 stillDynamicDepthTestByCamera(ImageFormat.DEPTH_JPEG, maxDepthJpegSize); 186 } finally { 187 closeDevice(); 188 closeImageReader(); 189 } 190 } 191 } 192 193 /** 194 * Test HEIC_ULTRAHDR capture along with preview for each camera. 195 */ 196 @Test 197 @RequiresFlagsEnabled(Flags.FLAG_CAMERA_HEIF_GAINMAP) testHeicUltraHdrCapture()198 public void testHeicUltraHdrCapture() throws Exception { 199 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 200 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 201 try { 202 Log.i(TAG, "Testing HEIC_ULTRAHDR for Camera " + cameraIdsUnderTest[i]); 203 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) { 204 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 205 " does not support color outputs, skipping"); 206 continue; 207 } 208 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isHeicUltraHdrSupported()) { 209 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 210 " does not support HEIC_ULTRAHDR, skipping"); 211 continue; 212 } 213 214 openDevice(cameraIdsUnderTest[i]); 215 216 // Check the maximum supported size. 217 List<Size> orderedHEIC_ULTRAHDRSizes = CameraTestUtils.getSortedSizesForFormat( 218 cameraIdsUnderTest[i], mCameraManager, ImageFormat.HEIC_ULTRAHDR, 219 null/*bound*/); 220 Size maxHEIC_ULTRAHDRSize = orderedHEIC_ULTRAHDRSizes.get(0); 221 stillUltraHDRTestByCamera(ImageFormat.HEIC_ULTRAHDR, maxHEIC_ULTRAHDRSize); 222 } finally { 223 closeDevice(); 224 closeImageReader(); 225 } 226 } 227 } 228 229 /** 230 * Test Jpeg/R capture along with preview for each camera. 231 */ 232 @Test testJpegRCapture()233 public void testJpegRCapture() throws Exception { 234 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 235 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 236 try { 237 Log.i(TAG, "Testing Jpeg/R for Camera " + cameraIdsUnderTest[i]); 238 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) { 239 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 240 " does not support color outputs, skipping"); 241 continue; 242 } 243 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isJpegRSupported()) { 244 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 245 " does not support Jpeg/R, skipping"); 246 continue; 247 } 248 249 openDevice(cameraIdsUnderTest[i]); 250 251 // Check the maximum supported size. 252 List<Size> orderedJpegRSizes = CameraTestUtils.getSortedSizesForFormat( 253 cameraIdsUnderTest[i], mCameraManager, ImageFormat.JPEG_R, null/*bound*/); 254 Size maxJpegRSize = orderedJpegRSizes.get(0); 255 stillUltraHDRTestByCamera(ImageFormat.JPEG_R, maxJpegRSize); 256 } finally { 257 closeDevice(); 258 closeImageReader(); 259 } 260 } 261 } 262 263 /** 264 * Issue a still capture and validate the UltraHDR output. 265 */ stillUltraHDRTestByCamera(int format, Size stillSize)266 private void stillUltraHDRTestByCamera(int format, Size stillSize) throws Exception { 267 assertTrue(format == ImageFormat.JPEG_R || format == ImageFormat.HEIC_ULTRAHDR); 268 269 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 270 if (VERBOSE) { 271 Log.v(TAG, "Testing UltraHDR format: " + format + " with size " + 272 stillSize.toString() + ", preview size " + maxPreviewSz); 273 } 274 275 // prepare capture and start preview. 276 CaptureRequest.Builder previewBuilder = 277 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 278 CaptureRequest.Builder stillBuilder = 279 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 280 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 281 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 282 283 updatePreviewSurface(maxPreviewSz); 284 createImageReader(stillSize, format, MAX_READER_IMAGES, imageListener); 285 286 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 287 OutputConfiguration previewConfig = new OutputConfiguration(mPreviewSurface); 288 if (mStaticInfo.isCapabilitySupported(CameraCharacteristics 289 .REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) { 290 previewConfig.setDynamicRangeProfile(DynamicRangeProfiles.HLG10); 291 } 292 outputConfigs.add(previewConfig); 293 outputConfigs.add(new OutputConfiguration(mReaderSurface)); 294 mSessionListener = new BlockingSessionCallback(); 295 mSession = configureCameraSessionWithConfig(mCamera, outputConfigs, mSessionListener, 296 mHandler); 297 298 previewBuilder.addTarget(mPreviewSurface); 299 stillBuilder.addTarget(mReaderSurface); 300 301 // Start preview. 302 mSession.setRepeatingRequest(previewBuilder.build(), resultListener, mHandler); 303 304 // Capture a few UltraHDR images and check whether they are valid jpegs. 305 for (int i = 0; i < MAX_READER_IMAGES; i++) { 306 CaptureRequest request = stillBuilder.build(); 307 mSession.capture(request, resultListener, mHandler); 308 assertNotNull(resultListener.getCaptureResultForRequest(request, 309 NUM_RESULTS_WAIT_TIMEOUT)); 310 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 311 assertNotNull("Unable to acquire next image", image); 312 CameraTestUtils.validateImage(image, stillSize.getWidth(), stillSize.getHeight(), 313 format, null /*filePath*/); 314 315 // Free image resources 316 image.close(); 317 } 318 } 319 320 /** 321 * Test normal still capture sequence. 322 * <p> 323 * Preview and jpeg output streams are configured. Max still capture 324 * size is used for jpeg capture. The sequence of still capture being test 325 * is: start preview, auto focus, precapture metering (if AE is not 326 * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode 327 * is CONTINUOUS_PICTURE. 328 * </p> 329 */ 330 @Test testTakePicture()331 public void testTakePicture() throws Exception{ 332 for (String id : getCameraIdsUnderTest()) { 333 try { 334 Log.i(TAG, "Testing basic take picture for Camera " + id); 335 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 336 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 337 continue; 338 } 339 openDevice(id); 340 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null); 341 } finally { 342 closeDevice(); 343 closeImageReader(); 344 } 345 } 346 } 347 348 /** 349 * Test ZSL still capture sequence. 350 * <p> 351 * Preview and jpeg output streams are configured. Max still capture 352 * size is used for jpeg capture. The sequence of still capture being test 353 * is: start preview, auto focus, precapture metering (if AE is not 354 * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode 355 * is CONTINUOUS_PICTURE. Same as testTakePicture, but with enableZSL set. 356 * </p> 357 */ 358 @Test testTakePictureZsl()359 public void testTakePictureZsl() throws Exception{ 360 for (String id : getCameraIdsUnderTest()) { 361 try { 362 Log.i(TAG, "Testing basic ZSL take picture for Camera " + id); 363 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 364 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 365 continue; 366 } 367 openDevice(id); 368 CaptureRequest.Builder stillRequest = 369 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 370 stillRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, true); 371 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null, 372 /*addAeTriggerCancel*/false, /*allocateBitmap*/false, 373 /*previewRequest*/null, stillRequest); 374 } finally { 375 closeDevice(); 376 closeImageReader(); 377 } 378 } 379 } 380 381 /** 382 * Test basic Raw capture. Raw buffer avaiablility is checked, but raw buffer data is not. 383 */ 384 @Test testBasicRawCapture()385 public void testBasicRawCapture() throws Exception { 386 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 387 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 388 try { 389 Log.i(TAG, "Testing raw capture for Camera " + cameraIdsUnderTest[i]); 390 391 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isCapabilitySupported( 392 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 393 Log.i(TAG, "RAW capability is not supported in camera " + cameraIdsUnderTest[i] + 394 ". Skip the test."); 395 continue; 396 } 397 398 openDevice(cameraIdsUnderTest[i]); 399 rawCaptureTestByCamera(/*stillRequest*/null); 400 } finally { 401 closeDevice(); 402 closeImageReader(); 403 } 404 } 405 } 406 407 /** 408 * Test basic Raw ZSL capture. Raw buffer avaiablility is checked, but raw buffer data is not. 409 */ 410 @Test testBasicRawZslCapture()411 public void testBasicRawZslCapture() throws Exception { 412 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 413 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 414 try { 415 Log.i(TAG, "Testing raw ZSL capture for Camera " + cameraIdsUnderTest[i]); 416 417 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isCapabilitySupported( 418 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 419 Log.i(TAG, "RAW capability is not supported in camera " + cameraIdsUnderTest[i] + 420 ". Skip the test."); 421 continue; 422 } 423 openDevice(cameraIdsUnderTest[i]); 424 CaptureRequest.Builder stillRequest = 425 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 426 stillRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, true); 427 rawCaptureTestByCamera(stillRequest); 428 } finally { 429 closeDevice(); 430 closeImageReader(); 431 } 432 } 433 } 434 435 436 /** 437 * Test the full raw capture use case. 438 * 439 * This includes: 440 * - Configuring the camera with a preview, jpeg, and raw output stream. 441 * - Running preview until AE/AF can settle. 442 * - Capturing with a request targeting all three output streams. 443 */ 444 @Test testFullRawCapture()445 public void testFullRawCapture() throws Exception { 446 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 447 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 448 try { 449 Log.i(TAG, "Testing raw+JPEG capture for Camera " + cameraIdsUnderTest[i]); 450 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isCapabilitySupported( 451 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 452 Log.i(TAG, "RAW capability is not supported in camera " + cameraIdsUnderTest[i] + 453 ". Skip the test."); 454 continue; 455 } 456 457 openDevice(cameraIdsUnderTest[i]); 458 fullRawCaptureTestByCamera(/*stillRequest*/null); 459 } finally { 460 closeDevice(); 461 closeImageReader(); 462 } 463 } 464 } 465 466 /** 467 * Test the full raw capture ZSL use case. 468 * 469 * This includes: 470 * - Configuring the camera with a preview, jpeg, and raw output stream. 471 * - Running preview until AE/AF can settle. 472 * - Capturing with a request targeting all three output streams. 473 */ 474 @Test testFullRawZSLCapture()475 public void testFullRawZSLCapture() throws Exception { 476 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 477 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 478 try { 479 Log.i(TAG, "Testing raw+JPEG ZSL capture for Camera " + cameraIdsUnderTest[i]); 480 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isCapabilitySupported( 481 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 482 Log.i(TAG, "RAW capability is not supported in camera " + cameraIdsUnderTest[i] + 483 ". Skip the test."); 484 continue; 485 } 486 openDevice(cameraIdsUnderTest[i]); 487 CaptureRequest.Builder stillRequest = 488 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 489 stillRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, true); 490 fullRawCaptureTestByCamera(stillRequest); 491 } finally { 492 closeDevice(); 493 closeImageReader(); 494 } 495 } 496 } 497 498 /** 499 * Test touch for focus. 500 * <p> 501 * AF is in CAF mode when preview is started, test uses several pre-selected 502 * regions to simulate touches. Active scan is triggered to make sure the AF 503 * converges in reasonable time. 504 * </p> 505 */ 506 @Test testTouchForFocus()507 public void testTouchForFocus() throws Exception { 508 for (String id : getCameraIdsUnderTest()) { 509 try { 510 Log.i(TAG, "Testing touch for focus for Camera " + id); 511 StaticMetadata staticInfo = mAllStaticInfo.get(id); 512 int maxAfRegions = staticInfo.getAfMaxRegionsChecked(); 513 if (!(staticInfo.hasFocuser() && maxAfRegions > 0)) { 514 continue; 515 } 516 // TODO: Relax test to use non-SurfaceView output for depth cases 517 if (!staticInfo.isColorOutputSupported()) { 518 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 519 continue; 520 } 521 openDevice(id); 522 touchForFocusTestByCamera(); 523 } finally { 524 closeDevice(); 525 closeImageReader(); 526 } 527 } 528 } 529 530 /** 531 * Test all combination of available preview sizes and still sizes. 532 * <p> 533 * For each still capture, Only the jpeg buffer is validated, capture 534 * result validation is covered by {@link #stillExifTestByCamera} test. 535 * </p> 536 */ 537 @Test(timeout=120*60*1000) // timeout = 120 mins for long running tests testStillPreviewCombination()538 public void testStillPreviewCombination() throws Exception { 539 for (String id : getCameraIdsUnderTest()) { 540 try { 541 Log.i(TAG, "Testing Still preview capture combination for Camera " + id); 542 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 543 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 544 continue; 545 } 546 openDevice(id); 547 previewStillCombinationTestByCamera(); 548 } finally { 549 closeDevice(); 550 closeImageReader(); 551 } 552 } 553 } 554 555 /** 556 * Test AE compensation. 557 * <p> 558 * For each integer EV compensation setting: retrieve the exposure value (exposure time * 559 * sensitivity) with or without compensation, verify if the exposure value is legal (conformed 560 * to what static info has) and the ratio between two exposure values matches EV compensation 561 * setting. Also test for the behavior that exposure settings should be changed when AE 562 * compensation settings is changed, even when AE lock is ON. 563 * </p> 564 */ 565 @Test testAeCompensation()566 public void testAeCompensation() throws Exception { 567 for (String id : getCameraIdsUnderTest()) { 568 try { 569 Log.i(TAG, "Testing AE compensation for Camera " + id); 570 571 StaticMetadata staticInfo = mAllStaticInfo.get(id); 572 if (staticInfo.isHardwareLevelLegacy()) { 573 Log.i(TAG, "Skipping test on legacy devices"); 574 continue; 575 } 576 if (!staticInfo.isColorOutputSupported()) { 577 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 578 continue; 579 } 580 openDevice(id); 581 aeCompensationTestByCamera(); 582 } finally { 583 closeDevice(); 584 closeImageReader(); 585 } 586 } 587 } 588 589 /** 590 * Test Ae region for still capture. 591 */ 592 @Test testAeRegions()593 public void testAeRegions() throws Exception { 594 for (String id : getCameraIdsUnderTest()) { 595 try { 596 Log.i(TAG, "Testing AE regions for Camera " + id); 597 openDevice(id); 598 599 boolean aeRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX); 600 if (!aeRegionsSupported) { 601 continue; 602 } 603 604 ArrayList<MeteringRectangle[]> aeRegionTestCases = get3ARegionTestCasesForCamera(); 605 for (MeteringRectangle[] aeRegions : aeRegionTestCases) { 606 takePictureTestByCamera(aeRegions, /*awbRegions*/null, /*afRegions*/null); 607 } 608 } finally { 609 closeDevice(); 610 closeImageReader(); 611 } 612 } 613 } 614 615 /** 616 * Test AWB region for still capture. 617 */ 618 @Test testAwbRegions()619 public void testAwbRegions() throws Exception { 620 for (String id : getCameraIdsUnderTest()) { 621 try { 622 Log.i(TAG, "Testing AE regions for Camera " + id); 623 openDevice(id); 624 625 boolean awbRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX); 626 if (!awbRegionsSupported) { 627 continue; 628 } 629 630 ArrayList<MeteringRectangle[]> awbRegionTestCases = get3ARegionTestCasesForCamera(); 631 for (MeteringRectangle[] awbRegions : awbRegionTestCases) { 632 takePictureTestByCamera(/*aeRegions*/null, awbRegions, /*afRegions*/null); 633 } 634 } finally { 635 closeDevice(); 636 closeImageReader(); 637 } 638 } 639 } 640 641 /** 642 * Test Af region for still capture. 643 */ 644 @Test testAfRegions()645 public void testAfRegions() throws Exception { 646 for (String id : getCameraIdsUnderTest()) { 647 try { 648 Log.i(TAG, "Testing AF regions for Camera " + id); 649 openDevice(id); 650 651 boolean afRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX); 652 if (!afRegionsSupported) { 653 continue; 654 } 655 656 ArrayList<MeteringRectangle[]> afRegionTestCases = get3ARegionTestCasesForCamera(); 657 for (MeteringRectangle[] afRegions : afRegionTestCases) { 658 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, afRegions); 659 } 660 } finally { 661 closeDevice(); 662 closeImageReader(); 663 } 664 } 665 } 666 667 /** 668 * Test preview is still running after a still request 669 */ 670 @Test testPreviewPersistence()671 public void testPreviewPersistence() throws Exception { 672 for (String id : getCameraIdsUnderTest()) { 673 try { 674 Log.i(TAG, "Testing preview persistence for Camera " + id); 675 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 676 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 677 continue; 678 } 679 openDevice(id); 680 previewPersistenceTestByCamera(); 681 } finally { 682 closeDevice(); 683 closeImageReader(); 684 } 685 } 686 } 687 688 @Test testAePrecaptureTriggerCancelJpegCapture()689 public void testAePrecaptureTriggerCancelJpegCapture() throws Exception { 690 for (String id : getCameraIdsUnderTest()) { 691 try { 692 Log.i(TAG, "Testing AE precapture cancel for jpeg capture for Camera " + id); 693 694 StaticMetadata staticInfo = mAllStaticInfo.get(id); 695 // Legacy device doesn't support AE precapture trigger 696 if (staticInfo.isHardwareLevelLegacy()) { 697 Log.i(TAG, "Skipping AE precapture trigger cancel test on legacy devices"); 698 continue; 699 } 700 if (!staticInfo.isColorOutputSupported()) { 701 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 702 continue; 703 } 704 openDevice(id); 705 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null, 706 /*addAeTriggerCancel*/true, /*allocateBitmap*/false, 707 /*previewRequest*/null, /*stillRequest*/null); 708 } finally { 709 closeDevice(); 710 closeImageReader(); 711 } 712 } 713 } 714 715 /** 716 * Test allocate some bitmaps while taking picture. 717 * <p> 718 * Per android CDD (5.0 and newer), android devices should support allocation of at least 3 719 * bitmaps equal to the size of the images produced by the largest resolution camera sensor on 720 * the devices. 721 * </p> 722 */ 723 @Test testAllocateBitmap()724 public void testAllocateBitmap() throws Exception { 725 for (String id : getCameraIdsUnderTest()) { 726 try { 727 Log.i(TAG, "Testing bitmap allocations for Camera " + id); 728 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 729 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 730 continue; 731 } 732 openDevice(id); 733 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null, 734 /*addAeTriggerCancel*/false, /*allocateBitmap*/true, 735 /*previewRequest*/null, /*stillRequest*/null); 736 } finally { 737 closeDevice(); 738 closeImageReader(); 739 } 740 } 741 742 } 743 744 /** 745 * Test focal length controls. 746 */ 747 @Test testFocalLengths()748 public void testFocalLengths() throws Exception { 749 for (String id : getCameraIdsUnderTest()) { 750 try { 751 StaticMetadata staticInfo = mAllStaticInfo.get(id); 752 if (staticInfo.isHardwareLevelLegacy()) { 753 Log.i(TAG, "Camera " + id + " is legacy, skipping"); 754 continue; 755 } 756 if (!staticInfo.isColorOutputSupported()) { 757 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 758 continue; 759 } 760 if (staticInfo.isExternalCamera()) { 761 Log.i(TAG, "Camera " + id + " is external, skipping"); 762 continue; 763 } 764 openDevice(id); 765 focalLengthTestByCamera(); 766 } finally { 767 closeDevice(); 768 closeImageReader(); 769 } 770 } 771 } 772 focalLengthTestByCamera()773 private void focalLengthTestByCamera() throws Exception { 774 float[] focalLengths = mStaticInfo.getAvailableFocalLengthsChecked(); 775 int numStillCaptures = focalLengths.length; 776 777 Size maxStillSz = mOrderedStillSizes.get(0); 778 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 779 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 780 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 781 CaptureRequest.Builder previewRequest = 782 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 783 CaptureRequest.Builder stillRequest = 784 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 785 Size thumbnailSize = new Size(0, 0); 786 Location sTestLocation = new Location(LocationManager.GPS_PROVIDER); 787 sTestLocation.setTime(1199145600000L); 788 sTestLocation.setLatitude(37.736071); 789 sTestLocation.setLongitude(-122.441983); 790 sTestLocation.setAltitude(21.0); 791 ExifTestData exifTestData = new ExifTestData( 792 /* gpsLocation */ sTestLocation, 793 /* orientation */ 0, 794 /* jpgQuality */ (byte) 80, 795 /* thumbnailQuality */ (byte) 75); 796 setJpegKeys(stillRequest, exifTestData, thumbnailSize, mCollector); 797 CaptureResult result; 798 799 // Set the max number of images to number of focal lengths supported 800 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 801 maxStillSz, resultListener, focalLengths.length, imageListener, false /*isHeic*/); 802 803 for(float focalLength : focalLengths) { 804 805 previewRequest.set(CaptureRequest.LENS_FOCAL_LENGTH, focalLength); 806 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 807 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 808 waitForResultValue(resultListener, CaptureResult.LENS_STATE, 809 CaptureResult.LENS_STATE_STATIONARY, NUM_RESULTS_WAIT_TIMEOUT); 810 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 811 Float focalLengthInResult = result.get(CaptureResult.LENS_FOCAL_LENGTH); 812 Set<Float> validFocalLengths = getAvailableFocalLengthsForResult( 813 result, mStaticInfo, mAllStaticInfo); 814 if (focalLengths.length > 1) { 815 mCollector.expectEquals( 816 "Focal length in preview result and request should be the same", 817 previewRequest.get(CaptureRequest.LENS_FOCAL_LENGTH), 818 focalLengthInResult); 819 } else { 820 mCollector.expectTrue( 821 "Focal length in preview result should be a supported value", 822 validFocalLengths.contains(focalLengthInResult)); 823 } 824 825 stillRequest.set(CaptureRequest.LENS_FOCAL_LENGTH, focalLength); 826 CaptureRequest request = stillRequest.build(); 827 resultListener = new SimpleCaptureCallback(); 828 mSession.capture(request, resultListener, mHandler); 829 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 830 focalLengthInResult = result.get(CaptureResult.LENS_FOCAL_LENGTH); 831 if (focalLengths.length > 1) { 832 mCollector.expectEquals( 833 "Focal length in still capture result and request should be the same", 834 stillRequest.get(CaptureRequest.LENS_FOCAL_LENGTH), 835 result.get(CaptureResult.LENS_FOCAL_LENGTH)); 836 } else { 837 mCollector.expectTrue( 838 "Focal length in still capture result should be a supported value", 839 validFocalLengths.contains(focalLengthInResult)); 840 } 841 842 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 843 844 validateJpegCapture(image, maxStillSz); 845 verifyJpegKeys(image, result, maxStillSz, thumbnailSize, exifTestData, 846 mStaticInfo, mAllStaticInfo, mCollector, mDebugFileNameBase, ImageFormat.JPEG); 847 } 848 } 849 850 851 /** 852 * Start preview,take a picture and test preview is still running after snapshot 853 */ previewPersistenceTestByCamera()854 private void previewPersistenceTestByCamera() throws Exception { 855 Size maxStillSz = mOrderedStillSizes.get(0); 856 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 857 858 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 859 SimpleCaptureCallback stillResultListener = new SimpleCaptureCallback(); 860 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 861 CaptureRequest.Builder previewRequest = 862 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 863 CaptureRequest.Builder stillRequest = 864 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 865 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 866 maxStillSz, resultListener, imageListener, false /*isHeic*/); 867 868 // make sure preview is actually running 869 waitForNumResults(resultListener, NUM_FRAMES_WAITED); 870 871 // take a picture 872 CaptureRequest request = stillRequest.build(); 873 mSession.capture(request, stillResultListener, mHandler); 874 stillResultListener.getCaptureResultForRequest(request, 875 WAIT_FOR_RESULT_TIMEOUT_MS); 876 877 // validate image 878 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 879 validateJpegCapture(image, maxStillSz); 880 881 // make sure preview is still running after still capture 882 waitForNumResults(resultListener, NUM_FRAMES_WAITED); 883 884 stopPreview(); 885 886 // Free image resources 887 image.close(); 888 closeImageReader(); 889 return; 890 } 891 892 /** 893 * Take a picture for a given set of 3A regions for a particular camera. 894 * <p> 895 * Before take a still capture, it triggers an auto focus and lock it first, 896 * then wait for AWB to converge and lock it, then trigger a precapture 897 * metering sequence and wait for AE converged. After capture is received, the 898 * capture result and image are validated. 899 * </p> 900 * 901 * @param aeRegions AE regions for this capture 902 * @param awbRegions AWB regions for this capture 903 * @param afRegions AF regions for this capture 904 */ takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions)905 private void takePictureTestByCamera( 906 MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, 907 MeteringRectangle[] afRegions) throws Exception { 908 takePictureTestByCamera(aeRegions, awbRegions, afRegions, 909 /*addAeTriggerCancel*/false, /*allocateBitmap*/false, 910 /*previewRequest*/null, /*stillRequest*/null); 911 } 912 913 /** 914 * Take a picture for a given set of 3A regions for a particular camera. 915 * <p> 916 * Before take a still capture, it triggers an auto focus and lock it first, 917 * then wait for AWB to converge and lock it, then trigger a precapture 918 * metering sequence and wait for AE converged. After capture is received, the 919 * capture result and image are validated. If {@code addAeTriggerCancel} is true, 920 * a precapture trigger cancel will be inserted between two adjacent triggers, which 921 * should effective cancel the first trigger. 922 * </p> 923 * 924 * @param aeRegions AE regions for this capture 925 * @param awbRegions AWB regions for this capture 926 * @param afRegions AF regions for this capture 927 * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger. 928 * @param allocateBitmap If a set of bitmaps are allocated during the test for memory test. 929 * @param previewRequest The preview request builder to use, or null to use the default 930 * @param stillRequest The still capture request to use, or null to use the default 931 */ takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions, boolean addAeTriggerCancel, boolean allocateBitmap, CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest)932 private void takePictureTestByCamera( 933 MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, 934 MeteringRectangle[] afRegions, boolean addAeTriggerCancel, boolean allocateBitmap, 935 CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest) 936 throws Exception { 937 938 boolean hasFocuser = mStaticInfo.hasFocuser(); 939 940 Size maxStillSz = mOrderedStillSizes.get(0); 941 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 942 CaptureResult result; 943 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 944 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 945 if (previewRequest == null) { 946 previewRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 947 } 948 if (stillRequest == null) { 949 stillRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 950 } 951 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 952 maxStillSz, resultListener, imageListener, false /*isHeic*/); 953 954 // Set AE mode to ON_AUTO_FLASH if flash is available. 955 if (mStaticInfo.hasFlash()) { 956 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, 957 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 958 stillRequest.set(CaptureRequest.CONTROL_AE_MODE, 959 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 960 } 961 962 Camera2Focuser focuser = null; 963 /** 964 * Step 1: trigger an auto focus run, and wait for AF locked. 965 */ 966 boolean canSetAfRegion = hasFocuser && (afRegions != null) && 967 isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX); 968 if (hasFocuser) { 969 SimpleAutoFocusListener afListener = new SimpleAutoFocusListener(); 970 focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener, 971 mStaticInfo.getCharacteristics(), mHandler); 972 if (canSetAfRegion) { 973 previewRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions); 974 stillRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions); 975 } 976 focuser.startAutoFocus(afRegions); 977 afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS); 978 } 979 980 /** 981 * Have to get the current AF mode to be used for other 3A repeating 982 * request, otherwise, the new AF mode in AE/AWB request could be 983 * different with existing repeating requests being sent by focuser, 984 * then it could make AF unlocked too early. Beside that, for still 985 * capture, AF mode must not be different with the one in current 986 * repeating request, otherwise, the still capture itself would trigger 987 * an AF mode change, and the AF lock would be lost for this capture. 988 */ 989 int currentAfMode = CaptureRequest.CONTROL_AF_MODE_OFF; 990 if (hasFocuser) { 991 currentAfMode = focuser.getCurrentAfMode(); 992 } 993 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode); 994 stillRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode); 995 996 /** 997 * Step 2: AF is already locked, wait for AWB converged, then lock it. 998 */ 999 resultListener = new SimpleCaptureCallback(); 1000 boolean canSetAwbRegion = 1001 (awbRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX); 1002 if (canSetAwbRegion) { 1003 previewRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions); 1004 stillRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions); 1005 } 1006 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1007 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1008 waitForResultValue(resultListener, CaptureResult.CONTROL_AWB_STATE, 1009 CaptureResult.CONTROL_AWB_STATE_CONVERGED, NUM_RESULTS_WAIT_TIMEOUT); 1010 } else { 1011 // LEGACY Devices don't have the AWB_STATE reported in results, so just wait 1012 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1013 } 1014 boolean canSetAwbLock = mStaticInfo.isAwbLockSupported(); 1015 if (canSetAwbLock) { 1016 previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true); 1017 } 1018 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1019 // Validate the next result immediately for region and mode. 1020 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1021 mCollector.expectEquals("AWB mode in result and request should be same", 1022 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE), 1023 result.get(CaptureResult.CONTROL_AWB_MODE)); 1024 if (canSetAwbRegion && CameraTestUtils.isStabilizationOff(previewRequest.build())) { 1025 MeteringRectangle[] resultAwbRegions = 1026 getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS); 1027 mCollector.expectEquals("AWB regions in result and request should be same", 1028 awbRegions, resultAwbRegions); 1029 } 1030 1031 /** 1032 * Step 3: trigger an AE precapture metering sequence and wait for AE converged. 1033 */ 1034 resultListener = new SimpleCaptureCallback(); 1035 boolean canSetAeRegion = 1036 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX); 1037 if (canSetAeRegion) { 1038 previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions); 1039 stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions); 1040 } 1041 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1042 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1043 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1044 mSession.capture(previewRequest.build(), resultListener, mHandler); 1045 if (addAeTriggerCancel) { 1046 // Cancel the current precapture trigger, then send another trigger. 1047 // The camera device should behave as if the first trigger is not sent. 1048 // Wait one request to make the trigger start doing something before cancel. 1049 waitForNumResults(resultListener, /*numResultsWait*/ 1); 1050 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1051 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL); 1052 mSession.capture(previewRequest.build(), resultListener, mHandler); 1053 waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER, 1054 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL, 1055 NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1056 // Issue another trigger 1057 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1058 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1059 mSession.capture(previewRequest.build(), resultListener, mHandler); 1060 } 1061 waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1062 1063 // Validate the next result immediately for region and mode. 1064 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1065 mCollector.expectEquals("AE mode in result and request should be same", 1066 previewRequest.get(CaptureRequest.CONTROL_AE_MODE), 1067 result.get(CaptureResult.CONTROL_AE_MODE)); 1068 if (canSetAeRegion && CameraTestUtils.isStabilizationOff(previewRequest.build())) { 1069 MeteringRectangle[] resultAeRegions = 1070 getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS); 1071 1072 mCollector.expectMeteringRegionsAreSimilar( 1073 "AE regions in result and request should be similar", 1074 aeRegions, 1075 resultAeRegions, 1076 METERING_REGION_ERROR_PERCENT_DELTA); 1077 } 1078 1079 /** 1080 * Step 4: take a picture when all 3A are in good state. 1081 */ 1082 resultListener = new SimpleCaptureCallback(); 1083 CaptureRequest request = stillRequest.build(); 1084 mSession.capture(request, resultListener, mHandler); 1085 // Validate the next result immediately for region and mode. 1086 result = resultListener.getCaptureResultForRequest(request, WAIT_FOR_RESULT_TIMEOUT_MS); 1087 mCollector.expectEquals("AF mode in result and request should be same", 1088 stillRequest.get(CaptureRequest.CONTROL_AF_MODE), 1089 result.get(CaptureResult.CONTROL_AF_MODE)); 1090 if (canSetAfRegion && CameraTestUtils.isStabilizationOff(stillRequest.build())) { 1091 MeteringRectangle[] resultAfRegions = 1092 getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS); 1093 mCollector.expectMeteringRegionsAreSimilar( 1094 "AF regions in result and request should be similar", 1095 afRegions, 1096 resultAfRegions, 1097 METERING_REGION_ERROR_PERCENT_DELTA); 1098 } 1099 1100 if (hasFocuser) { 1101 // Unlock auto focus. 1102 focuser.cancelAutoFocus(); 1103 } 1104 1105 // validate image 1106 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1107 validateJpegCapture(image, maxStillSz); 1108 // Test if the system can allocate 3 bitmap successfully, per android CDD camera memory 1109 // requirements added by CDD 5.0 1110 if (allocateBitmap) { 1111 Bitmap bm[] = new Bitmap[MAX_ALLOCATED_BITMAPS]; 1112 for (int i = 0; i < MAX_ALLOCATED_BITMAPS; i++) { 1113 bm[i] = Bitmap.createBitmap( 1114 maxStillSz.getWidth(), maxStillSz.getHeight(), Config.ARGB_8888); 1115 assertNotNull("Created bitmap #" + i + " shouldn't be null", bm[i]); 1116 } 1117 } 1118 1119 // Free image resources 1120 image.close(); 1121 1122 stopPreview(); 1123 } 1124 1125 /** 1126 * Test touch region for focus by camera. 1127 */ touchForFocusTestByCamera()1128 private void touchForFocusTestByCamera() throws Exception { 1129 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1130 CaptureRequest.Builder requestBuilder = 1131 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1132 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 1133 startPreview(requestBuilder, maxPreviewSz, listener); 1134 1135 SimpleAutoFocusListener afListener = new SimpleAutoFocusListener(); 1136 Camera2Focuser focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener, 1137 mStaticInfo.getCharacteristics(), mHandler); 1138 ArrayList<MeteringRectangle[]> testAfRegions = get3ARegionTestCasesForCamera(); 1139 1140 for (MeteringRectangle[] afRegions : testAfRegions) { 1141 focuser.touchForAutoFocus(afRegions); 1142 afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS); 1143 focuser.cancelAutoFocus(); 1144 } 1145 } 1146 previewStillCombinationTestByCamera()1147 private void previewStillCombinationTestByCamera() throws Exception { 1148 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1149 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1150 1151 Size QCIF = new Size(176, 144); 1152 Size FULL_HD = new Size(1920, 1080); 1153 for (Size stillSz : mOrderedStillSizes) 1154 for (Size previewSz : mOrderedPreviewSizes) { 1155 if (VERBOSE) { 1156 Log.v(TAG, "Testing JPEG capture size " + stillSz.toString() 1157 + " with preview size " + previewSz.toString() + " for camera " 1158 + mCamera.getId()); 1159 } 1160 1161 // Skip testing QCIF + >FullHD combinations 1162 if (stillSz.equals(QCIF) && 1163 ((previewSz.getWidth() > FULL_HD.getWidth()) || 1164 (previewSz.getHeight() > FULL_HD.getHeight()))) { 1165 continue; 1166 } 1167 1168 if (previewSz.equals(QCIF) && 1169 ((stillSz.getWidth() > FULL_HD.getWidth()) || 1170 (stillSz.getHeight() > FULL_HD.getHeight()))) { 1171 continue; 1172 } 1173 1174 CaptureRequest.Builder previewRequest = 1175 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1176 CaptureRequest.Builder stillRequest = 1177 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1178 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, previewSz, 1179 stillSz, resultListener, imageListener, false /*isHeic*/); 1180 mSession.capture(stillRequest.build(), resultListener, mHandler); 1181 Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ? 1182 RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS); 1183 validateJpegCapture(image, stillSz); 1184 1185 // Free image resources 1186 image.close(); 1187 1188 // stopPreview must be called here to make sure next time a preview stream 1189 // is created with new size. 1190 stopPreview(); 1191 // Drain the results after each combination. Depending on the device the results 1192 // can be relatively big and could accumulate fairly quickly after many iterations. 1193 resultListener.drain(); 1194 } 1195 } 1196 1197 /** 1198 * Basic raw capture test for each camera. 1199 */ rawCaptureTestByCamera(CaptureRequest.Builder stillRequest)1200 private void rawCaptureTestByCamera(CaptureRequest.Builder stillRequest) throws Exception { 1201 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 1202 Size size = mStaticInfo.getRawDimensChecked(); 1203 1204 // Prepare raw capture and start preview. 1205 CaptureRequest.Builder previewBuilder = 1206 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1207 CaptureRequest.Builder rawBuilder = (stillRequest != null) ? stillRequest : 1208 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1209 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1210 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1211 prepareRawCaptureAndStartPreview(previewBuilder, rawBuilder, maxPreviewSz, size, 1212 resultListener, imageListener); 1213 1214 if (VERBOSE) { 1215 Log.v(TAG, "Testing Raw capture with size " + size.toString() 1216 + ", preview size " + maxPreviewSz); 1217 } 1218 1219 CaptureRequest rawRequest = rawBuilder.build(); 1220 mSession.capture(rawRequest, resultListener, mHandler); 1221 1222 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1223 validateRaw16Image(image, size); 1224 if (DEBUG) { 1225 byte[] rawBuffer = getDataFromImage(image); 1226 String rawFileName = mDebugFileNameBase + "/test" + "_" + size.toString() + "_cam" + 1227 mCamera.getId() + ".raw16"; 1228 Log.d(TAG, "Dump raw file into " + rawFileName); 1229 dumpFile(rawFileName, rawBuffer); 1230 } 1231 1232 // Free image resources 1233 image.close(); 1234 1235 stopPreview(); 1236 } 1237 fullRawCaptureTestByCamera(CaptureRequest.Builder stillRequest)1238 private void fullRawCaptureTestByCamera(CaptureRequest.Builder stillRequest) throws Exception { 1239 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 1240 Size maxStillSz = mOrderedStillSizes.get(0); 1241 1242 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1243 SimpleImageReaderListener jpegListener = new SimpleImageReaderListener(); 1244 SimpleImageReaderListener rawListener = new SimpleImageReaderListener(); 1245 1246 Size size = mStaticInfo.getRawDimensChecked(); 1247 1248 if (VERBOSE) { 1249 Log.v(TAG, "Testing multi capture with size " + size.toString() 1250 + ", preview size " + maxPreviewSz); 1251 } 1252 1253 // Prepare raw capture and start preview. 1254 CaptureRequest.Builder previewBuilder = 1255 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1256 CaptureRequest.Builder multiBuilder = (stillRequest != null) ? stillRequest : 1257 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1258 1259 ImageReader rawReader = null; 1260 ImageReader jpegReader = null; 1261 1262 try { 1263 // Create ImageReaders. 1264 rawReader = makeImageReader(size, 1265 ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler); 1266 jpegReader = makeImageReader(maxStillSz, 1267 ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler); 1268 updatePreviewSurface(maxPreviewSz); 1269 1270 // Configure output streams with preview and jpeg streams. 1271 List<Surface> outputSurfaces = new ArrayList<Surface>(); 1272 outputSurfaces.add(rawReader.getSurface()); 1273 outputSurfaces.add(jpegReader.getSurface()); 1274 outputSurfaces.add(mPreviewSurface); 1275 mSessionListener = new BlockingSessionCallback(); 1276 mSession = configureCameraSession(mCamera, outputSurfaces, 1277 mSessionListener, mHandler); 1278 1279 // Configure the requests. 1280 previewBuilder.addTarget(mPreviewSurface); 1281 multiBuilder.addTarget(mPreviewSurface); 1282 multiBuilder.addTarget(rawReader.getSurface()); 1283 multiBuilder.addTarget(jpegReader.getSurface()); 1284 1285 // Start preview. 1286 mSession.setRepeatingRequest(previewBuilder.build(), null, mHandler); 1287 1288 // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle. 1289 // TODO: Do proper 3A trigger and lock (see testTakePictureTest). 1290 Thread.sleep(3000); 1291 1292 multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 1293 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON); 1294 CaptureRequest multiRequest = multiBuilder.build(); 1295 1296 mSession.capture(multiRequest, resultListener, mHandler); 1297 1298 CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest, 1299 NUM_RESULTS_WAIT_TIMEOUT); 1300 Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1301 basicValidateBlobImage(jpegImage, maxStillSz, ImageFormat.JPEG); 1302 Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1303 validateRaw16Image(rawImage, size); 1304 verifyRawCaptureResult(multiRequest, result); 1305 1306 1307 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 1308 try (DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result)) { 1309 dngCreator.writeImage(outputStream, rawImage); 1310 } 1311 1312 if (DEBUG) { 1313 byte[] rawBuffer = outputStream.toByteArray(); 1314 String rawFileName = mDebugFileNameBase + "/raw16_" + TAG + size.toString() + 1315 "_cam_" + mCamera.getId() + ".dng"; 1316 Log.d(TAG, "Dump raw file into " + rawFileName); 1317 dumpFile(rawFileName, rawBuffer); 1318 1319 byte[] jpegBuffer = getDataFromImage(jpegImage); 1320 String jpegFileName = mDebugFileNameBase + "/jpeg_" + TAG + size.toString() + 1321 "_cam_" + mCamera.getId() + ".jpg"; 1322 Log.d(TAG, "Dump jpeg file into " + rawFileName); 1323 dumpFile(jpegFileName, jpegBuffer); 1324 } 1325 1326 stopPreview(); 1327 } finally { 1328 CameraTestUtils.closeImageReader(rawReader); 1329 CameraTestUtils.closeImageReader(jpegReader); 1330 rawReader = null; 1331 jpegReader = null; 1332 } 1333 } 1334 1335 /** 1336 * Validate that raw {@link CaptureResult}. 1337 * 1338 * @param rawRequest a {@link CaptureRequest} use to capture a RAW16 image. 1339 * @param rawResult the {@link CaptureResult} corresponding to the given request. 1340 */ verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult)1341 private void verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult) { 1342 assertNotNull(rawRequest); 1343 assertNotNull(rawResult); 1344 1345 if (!mStaticInfo.isMonochromeCamera()) { 1346 Rational[] empty = new Rational[] { Rational.ZERO, Rational.ZERO, Rational.ZERO}; 1347 Rational[] neutralColorPoint = mCollector.expectKeyValueNotNull("NeutralColorPoint", 1348 rawResult, CaptureResult.SENSOR_NEUTRAL_COLOR_POINT); 1349 if (neutralColorPoint != null) { 1350 mCollector.expectEquals("NeutralColorPoint length", empty.length, 1351 neutralColorPoint.length); 1352 mCollector.expectNotEquals("NeutralColorPoint cannot be all zeroes, ", empty, 1353 neutralColorPoint); 1354 mCollector.expectValuesGreaterOrEqual("NeutralColorPoint", neutralColorPoint, 1355 Rational.ZERO); 1356 } 1357 1358 mCollector.expectKeyValueGreaterOrEqual(rawResult, 1359 CaptureResult.SENSOR_GREEN_SPLIT, 0.0f); 1360 } 1361 1362 Pair<Double, Double>[] noiseProfile = mCollector.expectKeyValueNotNull("NoiseProfile", 1363 rawResult, CaptureResult.SENSOR_NOISE_PROFILE); 1364 if (noiseProfile != null) { 1365 int cfa = mStaticInfo.getCFAChecked(); 1366 int numCfaChannels = 0; 1367 switch (cfa) { 1368 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: 1369 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: 1370 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: 1371 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: 1372 numCfaChannels = 4; 1373 break; 1374 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO: 1375 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR: 1376 numCfaChannels = 1; 1377 break; 1378 default: 1379 Assert.fail("Invalid color filter arrangement " + cfa); 1380 break; 1381 } 1382 mCollector.expectEquals("NoiseProfile length", noiseProfile.length, numCfaChannels); 1383 for (Pair<Double, Double> p : noiseProfile) { 1384 mCollector.expectTrue("NoiseProfile coefficients " + p + 1385 " must have: S > 0, O >= 0", p.first > 0 && p.second >= 0); 1386 } 1387 } 1388 1389 Integer hotPixelMode = mCollector.expectKeyValueNotNull("HotPixelMode", rawResult, 1390 CaptureResult.HOT_PIXEL_MODE); 1391 Boolean hotPixelMapMode = mCollector.expectKeyValueNotNull("HotPixelMapMode", rawResult, 1392 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE); 1393 Point[] hotPixelMap = rawResult.get(CaptureResult.STATISTICS_HOT_PIXEL_MAP); 1394 1395 Size pixelArraySize = mStaticInfo.getPixelArraySizeChecked(); 1396 boolean[] availableHotPixelMapModes = mStaticInfo.getValueFromKeyNonNull( 1397 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES); 1398 1399 if (hotPixelMode != null) { 1400 Integer requestMode = mCollector.expectKeyValueNotNull(rawRequest, 1401 CaptureRequest.HOT_PIXEL_MODE); 1402 if (requestMode != null) { 1403 mCollector.expectKeyValueEquals(rawResult, CaptureResult.HOT_PIXEL_MODE, 1404 requestMode); 1405 } 1406 } 1407 1408 if (hotPixelMapMode != null) { 1409 Boolean requestMapMode = mCollector.expectKeyValueNotNull(rawRequest, 1410 CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE); 1411 if (requestMapMode != null) { 1412 mCollector.expectKeyValueEquals(rawResult, 1413 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE, requestMapMode); 1414 } 1415 1416 if (!hotPixelMapMode) { 1417 mCollector.expectTrue("HotPixelMap must be empty", hotPixelMap == null || 1418 hotPixelMap.length == 0); 1419 } else { 1420 mCollector.expectTrue("HotPixelMap must not be empty", hotPixelMap != null); 1421 mCollector.expectNotNull("AvailableHotPixelMapModes must not be null", 1422 availableHotPixelMapModes); 1423 if (availableHotPixelMapModes != null) { 1424 mCollector.expectContains("HotPixelMapMode", availableHotPixelMapModes, true); 1425 } 1426 1427 int height = pixelArraySize.getHeight(); 1428 int width = pixelArraySize.getWidth(); 1429 for (Point p : hotPixelMap) { 1430 mCollector.expectTrue("Hotpixel " + p + " must be in pixelArray " + 1431 pixelArraySize, p.x >= 0 && p.x < width && p.y >= 0 && p.y < height); 1432 } 1433 } 1434 } 1435 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 1436 1437 } 1438 1439 /** 1440 * Issue a still capture and validate the exif information. 1441 * <p> 1442 * TODO: Differentiate full and limited device, some of the checks rely on 1443 * per frame control and synchronization, most of them don't. 1444 * </p> 1445 */ stillExifTestByCamera(int format, Size stillSize)1446 private void stillExifTestByCamera(int format, Size stillSize) throws Exception { 1447 assertTrue(format == ImageFormat.JPEG || format == ImageFormat.HEIC); 1448 boolean isHeic = (format == ImageFormat.HEIC); 1449 1450 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 1451 if (VERBOSE) { 1452 Log.v(TAG, "Testing exif with size " + stillSize.toString() 1453 + ", preview size " + maxPreviewSz); 1454 } 1455 1456 // prepare capture and start preview. 1457 CaptureRequest.Builder previewBuilder = 1458 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1459 CaptureRequest.Builder stillBuilder = 1460 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1461 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1462 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1463 prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize, 1464 resultListener, imageListener, isHeic); 1465 1466 // Set the jpeg keys, then issue a capture 1467 Size[] thumbnailSizes = mStaticInfo.getAvailableThumbnailSizesChecked(); 1468 Size maxThumbnailSize = thumbnailSizes[thumbnailSizes.length - 1]; 1469 Size[] testThumbnailSizes = new Size[EXIF_TEST_DATA.length]; 1470 Arrays.fill(testThumbnailSizes, maxThumbnailSize); 1471 // Make sure thumbnail size (0, 0) is covered. 1472 testThumbnailSizes[0] = new Size(0, 0); 1473 1474 for (int i = 0; i < EXIF_TEST_DATA.length; i++) { 1475 setJpegKeys(stillBuilder, EXIF_TEST_DATA[i], testThumbnailSizes[i], mCollector); 1476 1477 // Capture a jpeg/heic image. 1478 CaptureRequest request = stillBuilder.build(); 1479 mSession.capture(request, resultListener, mHandler); 1480 CaptureResult stillResult = 1481 resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 1482 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1483 1484 verifyJpegKeys(image, stillResult, stillSize, testThumbnailSizes[i], EXIF_TEST_DATA[i], 1485 mStaticInfo, mAllStaticInfo, mCollector, mDebugFileNameBase, format); 1486 1487 // Free image resources 1488 image.close(); 1489 } 1490 1491 // Check that after clearing JPEG_GPS_LOCATION with null, 1492 // the value reflects the null value. 1493 stillBuilder.set(CaptureRequest.JPEG_GPS_LOCATION, null); 1494 Assert.assertNull("JPEG_GPS_LOCATION value should be null if set to null", 1495 stillBuilder.get(CaptureRequest.JPEG_GPS_LOCATION)); 1496 } 1497 1498 /** 1499 * Issue a still capture and validate the dynamic depth output. 1500 */ stillDynamicDepthTestByCamera(int format, Size stillSize)1501 private void stillDynamicDepthTestByCamera(int format, Size stillSize) throws Exception { 1502 assertTrue(format == ImageFormat.DEPTH_JPEG); 1503 1504 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 1505 if (VERBOSE) { 1506 Log.v(TAG, "Testing dynamic depth with size " + stillSize.toString() 1507 + ", preview size " + maxPreviewSz); 1508 } 1509 1510 // prepare capture and start preview. 1511 CaptureRequest.Builder previewBuilder = 1512 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1513 CaptureRequest.Builder stillBuilder = 1514 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1515 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1516 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1517 prepareCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize, 1518 ImageFormat.DEPTH_JPEG, resultListener, /*sessionListener*/null, 1519 MAX_READER_IMAGES, imageListener); 1520 1521 // Capture a few dynamic depth images and check whether they are valid jpegs. 1522 for (int i = 0; i < MAX_READER_IMAGES; i++) { 1523 CaptureRequest request = stillBuilder.build(); 1524 mSession.capture(request, resultListener, mHandler); 1525 CaptureResult stillResult = 1526 resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 1527 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1528 assertNotNull("Unable to acquire next image", image); 1529 CameraTestUtils.validateImage(image, stillSize.getWidth(), stillSize.getHeight(), 1530 format, null /*filePath*/); 1531 1532 // Free image resources 1533 image.close(); 1534 } 1535 } 1536 aeCompensationTestByCamera()1537 private void aeCompensationTestByCamera() throws Exception { 1538 Range<Integer> compensationRange = mStaticInfo.getAeCompensationRangeChecked(); 1539 // Skip the test if exposure compensation is not supported. 1540 if (compensationRange.equals(Range.create(0, 0))) { 1541 return; 1542 } 1543 1544 Rational step = mStaticInfo.getAeCompensationStepChecked(); 1545 float stepF = (float) step.getNumerator() / step.getDenominator(); 1546 int stepsPerEv = (int) Math.round(1.0 / stepF); 1547 int numSteps = (compensationRange.getUpper() - compensationRange.getLower()) / stepsPerEv; 1548 1549 Size maxStillSz = mOrderedStillSizes.get(0); 1550 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 1551 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1552 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1553 CaptureRequest.Builder previewRequest = 1554 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1555 CaptureRequest.Builder stillRequest = 1556 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1557 boolean canSetAeLock = mStaticInfo.isAeLockSupported(); 1558 boolean canReadSensorSettings = mStaticInfo.isCapabilitySupported( 1559 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS); 1560 1561 if (canSetAeLock) { 1562 stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true); 1563 } 1564 1565 CaptureResult normalResult; 1566 CaptureResult compensatedResult; 1567 1568 boolean canReadExposureValueRange = mStaticInfo.areKeysAvailable( 1569 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 1570 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); 1571 boolean canVerifyExposureValue = canReadSensorSettings && canReadExposureValueRange; 1572 long minExposureValue = -1; 1573 long maxExposureValuePreview = -1; 1574 long maxExposureValueStill = -1; 1575 long maxPostRawSensitivity = 100; 1576 Range<Integer> postRawSensitivityRange = mStaticInfo.getCharacteristics().get( 1577 CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE); 1578 if (postRawSensitivityRange != null) { 1579 maxPostRawSensitivity = postRawSensitivityRange.getUpper(); 1580 } 1581 1582 if (canReadExposureValueRange) { 1583 // Minimum exposure settings is mostly static while maximum exposure setting depends on 1584 // frame rate range which in turn depends on capture request. 1585 minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() * 1586 mStaticInfo.getExposureMinimumOrDefault() / 1000; 1587 long maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault(); 1588 long maxExposureTimeUs = mStaticInfo.getExposureMaximumOrDefault() / 1000; 1589 maxExposureValuePreview = getMaxExposureValue(previewRequest, maxExposureTimeUs, 1590 maxSensitivity); 1591 maxExposureValueStill = getMaxExposureValue(stillRequest, maxExposureTimeUs, 1592 maxSensitivity); 1593 } 1594 1595 // Set the max number of images to be same as the burst count, as the verification 1596 // could be much slower than producing rate, and we don't want to starve producer. 1597 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 1598 maxStillSz, resultListener, numSteps, imageListener, false /*isHeic*/); 1599 1600 for (int i = 0; i <= numSteps; i++) { 1601 int exposureCompensation = i * stepsPerEv + compensationRange.getLower(); 1602 double expectedRatio = Math.pow(2.0, exposureCompensation / stepsPerEv); 1603 1604 // Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED. 1605 waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1606 normalResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1607 1608 long normalExposureValue = -1; 1609 if (canVerifyExposureValue) { 1610 // get and check if current exposure value is valid, with maxPostRawSensitivity 1611 // in mind. 1612 normalExposureValue = getExposureValue(normalResult); 1613 mCollector.expectInRange("Exposure setting out of bound", normalExposureValue, 1614 minExposureValue, maxExposureValuePreview * maxPostRawSensitivity / 100); 1615 1616 // Only run the test if expectedExposureValue is within valid range. Do not 1617 // scale the range by maxPostRawSensitivity to avoid clipping. 1618 long expectedExposureValue = (long) (normalExposureValue * expectedRatio); 1619 if (expectedExposureValue < minExposureValue || 1620 expectedExposureValue > maxExposureValueStill) { 1621 continue; 1622 } 1623 Log.v(TAG, "Expect ratio: " + expectedRatio + 1624 " normalExposureValue: " + normalExposureValue + 1625 " expectedExposureValue: " + expectedExposureValue + 1626 " minExposureValue: " + minExposureValue + 1627 " maxExposureValuePreview: " + maxExposureValuePreview + 1628 " maxExposureValueStill: " + maxExposureValueStill); 1629 } 1630 1631 // Now issue exposure compensation and wait for AE locked. AE could take a few 1632 // frames to go back to locked state 1633 previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 1634 exposureCompensation); 1635 if (canSetAeLock) { 1636 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true); 1637 } 1638 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1639 if (canSetAeLock) { 1640 waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1641 } else { 1642 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1643 } 1644 1645 // Issue still capture 1646 if (VERBOSE) { 1647 Log.v(TAG, "Verifying capture result for ae compensation value " 1648 + exposureCompensation); 1649 } 1650 1651 stillRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureCompensation); 1652 CaptureRequest request = stillRequest.build(); 1653 mSession.capture(request, resultListener, mHandler); 1654 1655 compensatedResult = resultListener.getCaptureResultForRequest( 1656 request, WAIT_FOR_RESULT_TIMEOUT_MS); 1657 1658 if (canVerifyExposureValue) { 1659 // Verify the exposure value compensates as requested, with maxPostRawSensitivity 1660 // in mind. 1661 long compensatedExposureValue = getExposureValue(compensatedResult); 1662 mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue, 1663 minExposureValue, maxExposureValueStill * maxPostRawSensitivity / 100); 1664 double observedRatio = (double) compensatedExposureValue / normalExposureValue; 1665 double error = observedRatio / expectedRatio; 1666 String errorString = String.format( 1667 "Exposure compensation ratio exceeds error tolerence:" + 1668 " expected(%f) observed(%f)." + 1669 " Normal exposure time %d us, sensitivity %d." + 1670 " Compensated exposure time %d us, sensitivity %d", 1671 expectedRatio, observedRatio, 1672 (int) (getValueNotNull( 1673 normalResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000), 1674 getValueNotNull(normalResult, CaptureResult.SENSOR_SENSITIVITY), 1675 (int) (getValueNotNull( 1676 compensatedResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000), 1677 getValueNotNull(compensatedResult, CaptureResult.SENSOR_SENSITIVITY)); 1678 mCollector.expectInRange(errorString, error, 1679 1.0 - AE_COMPENSATION_ERROR_TOLERANCE, 1680 1.0 + AE_COMPENSATION_ERROR_TOLERANCE); 1681 } 1682 1683 mCollector.expectEquals("Exposure compensation result should match requested value.", 1684 exposureCompensation, 1685 compensatedResult.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION)); 1686 if (canSetAeLock) { 1687 mCollector.expectTrue("Exposure lock should be set", 1688 compensatedResult.get(CaptureResult.CONTROL_AE_LOCK)); 1689 } 1690 1691 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1692 validateJpegCapture(image, maxStillSz); 1693 image.close(); 1694 1695 // Recover AE compensation and lock 1696 previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0); 1697 if (canSetAeLock) { 1698 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false); 1699 } 1700 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1701 } 1702 } 1703 getExposureValue(CaptureResult result)1704 private long getExposureValue(CaptureResult result) throws Exception { 1705 int expTimeUs = (int) (getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000); 1706 int sensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY); 1707 Integer postRawSensitivity = result.get(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST); 1708 if (postRawSensitivity != null) { 1709 return (long) sensitivity * postRawSensitivity / 100 * expTimeUs; 1710 } 1711 return (long) sensitivity * expTimeUs; 1712 } 1713 getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs, long maxSensitivity)1714 private long getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs, 1715 long maxSensitivity) throws Exception { 1716 Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); 1717 long maxFrameDurationUs = Math.round(1000000.0 / fpsRange.getLower()); 1718 long currentMaxExposureTimeUs = Math.min(maxFrameDurationUs, maxExposureTimeUs); 1719 return currentMaxExposureTimeUs * maxSensitivity; 1720 } 1721 1722 1723 //---------------------------------------------------------------- 1724 //---------Below are common functions for all tests.-------------- 1725 //---------------------------------------------------------------- 1726 /** 1727 * Validate standard raw (RAW16) capture image. 1728 * 1729 * @param image The raw16 format image captured 1730 * @param rawSize The expected raw size 1731 */ validateRaw16Image(Image image, Size rawSize)1732 private static void validateRaw16Image(Image image, Size rawSize) { 1733 CameraTestUtils.validateImage(image, rawSize.getWidth(), rawSize.getHeight(), 1734 ImageFormat.RAW_SENSOR, /*filePath*/null); 1735 } 1736 1737 /** 1738 * Validate JPEG capture image object correctness and test. 1739 * <p> 1740 * In addition to image object correctness, this function also does the decoding 1741 * test, which is slower. 1742 * </p> 1743 * 1744 * @param image The JPEG image to be verified. 1745 * @param jpegSize The JPEG capture size to be verified against. 1746 */ validateJpegCapture(Image image, Size jpegSize)1747 private static void validateJpegCapture(Image image, Size jpegSize) { 1748 CameraTestUtils.validateImage(image, jpegSize.getWidth(), jpegSize.getHeight(), 1749 ImageFormat.JPEG, /*filePath*/null); 1750 } 1751 1752 private static class SimpleAutoFocusListener implements Camera2Focuser.AutoFocusListener { 1753 final ConditionVariable focusDone = new ConditionVariable(); 1754 @Override onAutoFocusLocked(boolean success)1755 public void onAutoFocusLocked(boolean success) { 1756 focusDone.open(); 1757 } 1758 waitForAutoFocusDone(long timeoutMs)1759 public void waitForAutoFocusDone(long timeoutMs) { 1760 if (focusDone.block(timeoutMs)) { 1761 focusDone.close(); 1762 } else { 1763 throw new TimeoutRuntimeException("Wait for auto focus done timed out after " 1764 + timeoutMs + "ms"); 1765 } 1766 } 1767 } 1768 1769 /** 1770 * Get 5 3A region test cases, each with one square region in it. 1771 * The first one is at center, the other four are at corners of 1772 * active array rectangle. 1773 * 1774 * @return array of test 3A regions 1775 */ get3ARegionTestCasesForCamera()1776 private ArrayList<MeteringRectangle[]> get3ARegionTestCasesForCamera() { 1777 final int TEST_3A_REGION_NUM = 5; 1778 final int DEFAULT_REGION_WEIGHT = 30; 1779 final int DEFAULT_REGION_SCALE_RATIO = 8; 1780 ArrayList<MeteringRectangle[]> testCases = 1781 new ArrayList<MeteringRectangle[]>(TEST_3A_REGION_NUM); 1782 final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked(); 1783 int regionWidth = activeArraySize.width() / DEFAULT_REGION_SCALE_RATIO - 1; 1784 int regionHeight = activeArraySize.height() / DEFAULT_REGION_SCALE_RATIO - 1; 1785 int centerX = activeArraySize.width() / 2; 1786 int centerY = activeArraySize.height() / 2; 1787 int bottomRightX = activeArraySize.width() - 1; 1788 int bottomRightY = activeArraySize.height() - 1; 1789 1790 // Center region 1791 testCases.add( 1792 new MeteringRectangle[] { 1793 new MeteringRectangle( 1794 centerX - regionWidth / 2, // x 1795 centerY - regionHeight / 2, // y 1796 regionWidth, // width 1797 regionHeight, // height 1798 DEFAULT_REGION_WEIGHT)}); 1799 1800 // Upper left corner 1801 testCases.add( 1802 new MeteringRectangle[] { 1803 new MeteringRectangle( 1804 0, // x 1805 0, // y 1806 regionWidth, // width 1807 regionHeight, // height 1808 DEFAULT_REGION_WEIGHT)}); 1809 1810 // Upper right corner 1811 testCases.add( 1812 new MeteringRectangle[] { 1813 new MeteringRectangle( 1814 bottomRightX - regionWidth, // x 1815 0, // y 1816 regionWidth, // width 1817 regionHeight, // height 1818 DEFAULT_REGION_WEIGHT)}); 1819 1820 // Bottom left corner 1821 testCases.add( 1822 new MeteringRectangle[] { 1823 new MeteringRectangle( 1824 0, // x 1825 bottomRightY - regionHeight, // y 1826 regionWidth, // width 1827 regionHeight, // height 1828 DEFAULT_REGION_WEIGHT)}); 1829 1830 // Bottom right corner 1831 testCases.add( 1832 new MeteringRectangle[] { 1833 new MeteringRectangle( 1834 bottomRightX - regionWidth, // x 1835 bottomRightY - regionHeight, // y 1836 regionWidth, // width 1837 regionHeight, // height 1838 DEFAULT_REGION_WEIGHT)}); 1839 1840 if (VERBOSE) { 1841 StringBuilder sb = new StringBuilder(); 1842 for (MeteringRectangle[] mr : testCases) { 1843 sb.append("{"); 1844 sb.append(Arrays.toString(mr)); 1845 sb.append("}, "); 1846 } 1847 if (sb.length() > 1) 1848 sb.setLength(sb.length() - 2); // Remove the redundant comma and space at the end 1849 Log.v(TAG, "Generated test regions are: " + sb.toString()); 1850 } 1851 1852 return testCases; 1853 } 1854 isRegionsSupportedFor3A(int index)1855 private boolean isRegionsSupportedFor3A(int index) { 1856 int maxRegions = 0; 1857 switch (index) { 1858 case MAX_REGIONS_AE_INDEX: 1859 maxRegions = mStaticInfo.getAeMaxRegionsChecked(); 1860 break; 1861 case MAX_REGIONS_AWB_INDEX: 1862 maxRegions = mStaticInfo.getAwbMaxRegionsChecked(); 1863 break; 1864 case MAX_REGIONS_AF_INDEX: 1865 maxRegions = mStaticInfo.getAfMaxRegionsChecked(); 1866 break; 1867 default: 1868 throw new IllegalArgumentException("Unknown algorithm index"); 1869 } 1870 boolean isRegionsSupported = maxRegions > 0; 1871 if (index == MAX_REGIONS_AF_INDEX && isRegionsSupported) { 1872 mCollector.expectTrue( 1873 "Device reports non-zero max AF region count for a camera without focuser!", 1874 mStaticInfo.hasFocuser()); 1875 isRegionsSupported = isRegionsSupported && mStaticInfo.hasFocuser(); 1876 } 1877 1878 return isRegionsSupported; 1879 } 1880 } 1881