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