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