1 /* 2 * Copyright 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.content.Context; 22 import android.graphics.ImageFormat; 23 import android.graphics.SurfaceTexture; 24 import android.hardware.camera2.CameraCaptureSession; 25 import android.hardware.camera2.CameraCharacteristics; 26 import android.hardware.camera2.CameraDevice; 27 import android.hardware.camera2.CameraManager; 28 import android.hardware.camera2.CaptureRequest; 29 import android.hardware.camera2.CaptureResult; 30 import android.hardware.camera2.TotalCaptureResult; 31 import android.hardware.camera2.CaptureFailure; 32 import android.hardware.camera2.cts.helpers.StaticMetadata; 33 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 34 import android.hardware.camera2.params.InputConfiguration; 35 import android.hardware.camera2.params.OisSample; 36 import android.hardware.camera2.params.OutputConfiguration; 37 import android.hardware.camera2.params.MandatoryStreamCombination; 38 import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation; 39 import android.hardware.camera2.params.SessionConfiguration; 40 import android.hardware.camera2.params.StreamConfigurationMap; 41 import android.media.Image; 42 import android.media.ImageReader; 43 import android.media.ImageWriter; 44 import android.util.Log; 45 import android.util.Size; 46 import android.view.Surface; 47 48 import com.android.ex.camera2.blocking.BlockingSessionCallback; 49 50 import java.util.Arrays; 51 import java.util.ArrayList; 52 import java.util.Comparator; 53 import java.util.List; 54 import java.util.Map; 55 import java.util.Set; 56 57 import static junit.framework.Assert.assertTrue; 58 import static org.mockito.Mockito.*; 59 60 /** 61 * Tests exercising edge cases in camera setup, configuration, and usage. 62 */ 63 public class RobustnessTest extends Camera2AndroidTestCase { 64 private static final String TAG = "RobustnessTest"; 65 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 66 67 private static final int CONFIGURE_TIMEOUT = 5000; //ms 68 private static final int CAPTURE_TIMEOUT = 1000; //ms 69 70 // For testTriggerInteractions 71 private static final int PREVIEW_WARMUP_FRAMES = 60; 72 private static final int MAX_RESULT_STATE_CHANGE_WAIT_FRAMES = 100; 73 private static final int MAX_TRIGGER_SEQUENCE_FRAMES = 180; // 6 sec at 30 fps 74 private static final int MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES = 10; 75 76 /** 77 * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing 78 * a dimension other than one of the supported output dimensions. The buffers produced into 79 * this surface are expected have the dimensions of the closest possible buffer size in the 80 * available stream configurations for a surface with this format. 81 */ 82 public void testBadSurfaceDimensions() throws Exception { 83 for (String id : mCameraIds) { 84 try { 85 Log.i(TAG, "Testing Camera " + id); 86 openDevice(id); 87 88 List<Size> testSizes = null; 89 int format = mStaticInfo.isColorOutputSupported() ? 90 ImageFormat.YUV_420_888 : ImageFormat.DEPTH16; 91 92 testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager, 93 format, null); 94 95 // Find some size not supported by the camera 96 Size weirdSize = new Size(643, 577); 97 int count = 0; 98 while(testSizes.contains(weirdSize)) { 99 // Really, they can't all be supported... 100 weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1); 101 count++; 102 assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100); 103 } 104 105 // Setup imageReader with invalid dimension 106 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(), 107 weirdSize.getHeight(), format, 3); 108 109 // Setup ImageReaderListener 110 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 111 imageReader.setOnImageAvailableListener(imageListener, mHandler); 112 113 Surface surface = imageReader.getSurface(); 114 List<Surface> surfaces = new ArrayList<>(); 115 surfaces.add(surface); 116 117 // Setup a capture request and listener 118 CaptureRequest.Builder request = 119 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 120 request.addTarget(surface); 121 122 // Check that correct session callback is hit. 123 CameraCaptureSession.StateCallback sessionListener = 124 mock(CameraCaptureSession.StateCallback.class); 125 CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera, 126 surfaces, sessionListener, mHandler); 127 128 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()). 129 onConfigured(any(CameraCaptureSession.class)); 130 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()). 131 onReady(any(CameraCaptureSession.class)); 132 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class)); 133 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class)); 134 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class)); 135 136 CameraCaptureSession.CaptureCallback captureListener = 137 mock(CameraCaptureSession.CaptureCallback.class); 138 session.capture(request.build(), captureListener, mHandler); 139 140 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()). 141 onCaptureCompleted(any(CameraCaptureSession.class), 142 any(CaptureRequest.class), any(TotalCaptureResult.class)); 143 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class), 144 any(CaptureRequest.class), any(CaptureFailure.class)); 145 146 Image image = imageListener.getImage(CAPTURE_TIMEOUT); 147 int imageWidth = image.getWidth(); 148 int imageHeight = image.getHeight(); 149 Size actualSize = new Size(imageWidth, imageHeight); 150 151 assertTrue("Camera does not contain outputted image resolution " + actualSize, 152 testSizes.contains(actualSize)); 153 imageReader.close(); 154 } finally { 155 closeDevice(id); 156 } 157 } 158 } 159 160 /** 161 * Test for making sure the mandatory stream combinations work as expected. 162 */ 163 public void testMandatoryOutputCombinations() throws Exception { 164 for (String id : mCameraIds) { 165 openDevice(id); 166 MandatoryStreamCombination[] combinations = 167 mStaticInfo.getCharacteristics().get( 168 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 169 if (combinations == null) { 170 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 171 closeDevice(id); 172 continue; 173 } 174 175 try { 176 for (MandatoryStreamCombination combination : combinations) { 177 if (!combination.isReprocessable()) { 178 testMandatoryStreamCombination(id, mStaticInfo, 179 null/*physicalCameraId*/, combination); 180 } 181 } 182 183 // Make sure mandatory stream combinations for each physical camera work 184 // as expected. 185 if (mStaticInfo.isLogicalMultiCamera()) { 186 Set<String> physicalCameraIds = 187 mStaticInfo.getCharacteristics().getPhysicalCameraIds(); 188 for (String physicalId : physicalCameraIds) { 189 if (Arrays.asList(mCameraIds).contains(physicalId)) { 190 // If physicalId is advertised in camera ID list, do not need to test 191 // its stream combination through logical camera. 192 continue; 193 } 194 StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId); 195 MandatoryStreamCombination[] phyCombinations = 196 physicalStaticInfo.getCharacteristics().get( 197 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 198 199 for (MandatoryStreamCombination combination : phyCombinations) { 200 if (!combination.isReprocessable()) { 201 testMandatoryStreamCombination(id, physicalStaticInfo, 202 physicalId, combination); 203 } 204 } 205 } 206 } 207 208 } finally { 209 closeDevice(id); 210 } 211 } 212 } 213 214 private void setupConfigurationTargets(List<MandatoryStreamInformation> streamsInfo, 215 List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets, 216 List<ImageReader> yuvTargets, List<ImageReader> y8Targets, 217 List<ImageReader> rawTargets, List<ImageReader> heicTargets, 218 List<OutputConfiguration> outputConfigs, 219 int numBuffers, boolean substituteY8, boolean substituteHeic, 220 String overridePhysicalCameraId) { 221 222 ImageDropperListener imageDropperListener = new ImageDropperListener(); 223 224 for (MandatoryStreamInformation streamInfo : streamsInfo) { 225 if (streamInfo.isInput()) { 226 continue; 227 } 228 int format = streamInfo.getFormat(); 229 if (substituteY8 && (format == ImageFormat.YUV_420_888)) { 230 format = ImageFormat.Y8; 231 } else if (substituteHeic && (format == ImageFormat.JPEG)) { 232 format = ImageFormat.HEIC; 233 } 234 Surface newSurface; 235 Size[] availableSizes = new Size[streamInfo.getAvailableSizes().size()]; 236 availableSizes = streamInfo.getAvailableSizes().toArray(availableSizes); 237 Size targetSize = CameraTestUtils.getMaxSize(availableSizes); 238 239 switch (format) { 240 case ImageFormat.PRIVATE: { 241 SurfaceTexture target = new SurfaceTexture(/*random int*/1); 242 target.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight()); 243 OutputConfiguration config = new OutputConfiguration(new Surface(target)); 244 if (overridePhysicalCameraId != null) { 245 config.setPhysicalCameraId(overridePhysicalCameraId); 246 } 247 outputConfigs.add(config); 248 privTargets.add(target); 249 break; 250 } 251 case ImageFormat.JPEG: { 252 ImageReader target = ImageReader.newInstance(targetSize.getWidth(), 253 targetSize.getHeight(), format, numBuffers); 254 target.setOnImageAvailableListener(imageDropperListener, mHandler); 255 OutputConfiguration config = new OutputConfiguration(target.getSurface()); 256 if (overridePhysicalCameraId != null) { 257 config.setPhysicalCameraId(overridePhysicalCameraId); 258 } 259 outputConfigs.add(config); 260 jpegTargets.add(target); 261 break; 262 } 263 case ImageFormat.YUV_420_888: { 264 ImageReader target = ImageReader.newInstance(targetSize.getWidth(), 265 targetSize.getHeight(), format, numBuffers); 266 target.setOnImageAvailableListener(imageDropperListener, mHandler); 267 OutputConfiguration config = new OutputConfiguration(target.getSurface()); 268 if (overridePhysicalCameraId != null) { 269 config.setPhysicalCameraId(overridePhysicalCameraId); 270 } 271 outputConfigs.add(config); 272 yuvTargets.add(target); 273 break; 274 } 275 case ImageFormat.Y8: { 276 ImageReader target = ImageReader.newInstance(targetSize.getWidth(), 277 targetSize.getHeight(), format, numBuffers); 278 target.setOnImageAvailableListener(imageDropperListener, mHandler); 279 OutputConfiguration config = new OutputConfiguration(target.getSurface()); 280 if (overridePhysicalCameraId != null) { 281 config.setPhysicalCameraId(overridePhysicalCameraId); 282 } 283 outputConfigs.add(config); 284 y8Targets.add(target); 285 break; 286 } 287 case ImageFormat.RAW_SENSOR: { 288 // targetSize could be null in the logical camera case where only 289 // physical camera supports RAW stream. 290 if (targetSize != null) { 291 ImageReader target = ImageReader.newInstance(targetSize.getWidth(), 292 targetSize.getHeight(), format, numBuffers); 293 target.setOnImageAvailableListener(imageDropperListener, mHandler); 294 OutputConfiguration config = 295 new OutputConfiguration(target.getSurface()); 296 if (overridePhysicalCameraId != null) { 297 config.setPhysicalCameraId(overridePhysicalCameraId); 298 } 299 outputConfigs.add(config); 300 rawTargets.add(target); 301 } 302 break; 303 } 304 case ImageFormat.HEIC: { 305 ImageReader target = ImageReader.newInstance(targetSize.getWidth(), 306 targetSize.getHeight(), format, numBuffers); 307 target.setOnImageAvailableListener(imageDropperListener, mHandler); 308 OutputConfiguration config = new OutputConfiguration(target.getSurface()); 309 if (overridePhysicalCameraId != null) { 310 config.setPhysicalCameraId(overridePhysicalCameraId); 311 } 312 outputConfigs.add(config); 313 heicTargets.add(target); 314 break; 315 } 316 default: 317 fail("Unknown output format " + format); 318 } 319 } 320 } 321 322 private void testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, 323 String physicalCameraId, MandatoryStreamCombination combination) throws Exception { 324 // Check whether substituting YUV_888 format with Y8 format 325 boolean substituteY8 = false; 326 if (staticInfo.isMonochromeWithY8()) { 327 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 328 for (MandatoryStreamInformation streamInfo : streamsInfo) { 329 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) { 330 substituteY8 = true; 331 break; 332 } 333 } 334 } 335 336 // Check whether substituting JPEG format with HEIC format 337 boolean substituteHeic = false; 338 if (staticInfo.isHeicSupported()) { 339 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 340 for (MandatoryStreamInformation streamInfo : streamsInfo) { 341 if (streamInfo.getFormat() == ImageFormat.JPEG) { 342 substituteHeic = true; 343 break; 344 } 345 } 346 } 347 348 // Test camera output combination 349 String log = "Testing mandatory stream combination: " + combination.getDescription() + 350 " on camera: " + cameraId; 351 if (physicalCameraId != null) { 352 log += ", physical sub-camera: " + physicalCameraId; 353 } 354 Log.i(TAG, log); 355 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 356 /*substituteY8*/false, /*substituteHeic*/false); 357 358 if (substituteY8) { 359 Log.i(TAG, log + " with Y8"); 360 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 361 /*substituteY8*/true, /*substituteHeic*/false); 362 } 363 364 if (substituteHeic) { 365 Log.i(TAG, log + " with HEIC"); 366 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 367 /*substituteY8*/false, /*substituteHeic*/true); 368 } 369 } 370 371 private void testMandatoryStreamCombination(String cameraId, 372 StaticMetadata staticInfo, String physicalCameraId, 373 MandatoryStreamCombination combination, 374 boolean substituteY8, boolean substituteHeic) throws Exception { 375 376 // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS 377 final int TIMEOUT_FOR_RESULT_MS = (staticInfo.isHardwareLevelLegacy()) ? 2000 : 1000; 378 final int MIN_RESULT_COUNT = 3; 379 380 // Set up outputs 381 List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>(); 382 List<SurfaceTexture> privTargets = new ArrayList<SurfaceTexture>(); 383 List<ImageReader> jpegTargets = new ArrayList<ImageReader>(); 384 List<ImageReader> yuvTargets = new ArrayList<ImageReader>(); 385 List<ImageReader> y8Targets = new ArrayList<ImageReader>(); 386 List<ImageReader> rawTargets = new ArrayList<ImageReader>(); 387 List<ImageReader> heicTargets = new ArrayList<ImageReader>(); 388 389 setupConfigurationTargets(combination.getStreamsInformation(), privTargets, jpegTargets, 390 yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT, 391 substituteY8, substituteHeic, physicalCameraId); 392 393 boolean haveSession = false; 394 try { 395 CaptureRequest.Builder requestBuilder = 396 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 397 398 for (OutputConfiguration c : outputConfigs) { 399 requestBuilder.addTarget(c.getSurface()); 400 } 401 402 CameraCaptureSession.CaptureCallback mockCaptureCallback = 403 mock(CameraCaptureSession.CaptureCallback.class); 404 405 if (physicalCameraId == null) { 406 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 407 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 408 true/*defaultSupport*/, String.format( 409 "Session configuration query from combination: %s failed", 410 combination.getDescription())); 411 } else { 412 SessionConfigSupport sessionConfigSupport = isSessionConfigSupported( 413 mCamera, mHandler, outputConfigs, /*inputConfig*/ null, 414 SessionConfiguration.SESSION_REGULAR, false/*defaultSupport*/); 415 assertTrue( 416 String.format("Session configuration query from combination: %s failed", 417 combination.getDescription()), !sessionConfigSupport.error); 418 if (!sessionConfigSupport.callSupported) { 419 return; 420 } 421 assertTrue( 422 String.format("Session configuration must be supported for combination: " + 423 "%s", combination.getDescription()), sessionConfigSupport.configSupported); 424 } 425 426 createSessionByConfigs(outputConfigs); 427 haveSession = true; 428 CaptureRequest request = requestBuilder.build(); 429 mCameraSession.setRepeatingRequest(request, mockCaptureCallback, mHandler); 430 431 verify(mockCaptureCallback, 432 timeout(TIMEOUT_FOR_RESULT_MS * MIN_RESULT_COUNT).atLeast(MIN_RESULT_COUNT)) 433 .onCaptureCompleted( 434 eq(mCameraSession), 435 eq(request), 436 isA(TotalCaptureResult.class)); 437 verify(mockCaptureCallback, never()). 438 onCaptureFailed( 439 eq(mCameraSession), 440 eq(request), 441 isA(CaptureFailure.class)); 442 443 } catch (Throwable e) { 444 mCollector.addMessage(String.format("Mandatory stream combination: %s failed due: %s", 445 combination.getDescription(), e.getMessage())); 446 } 447 if (haveSession) { 448 try { 449 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 450 cameraId, combination.getDescription())); 451 stopCapture(/*fast*/false); 452 } catch (Throwable e) { 453 mCollector.addMessage( 454 String.format("Closing down for combination: %s failed due to: %s", 455 combination.getDescription(), e.getMessage())); 456 } 457 } 458 459 for (SurfaceTexture target : privTargets) { 460 target.release(); 461 } 462 for (ImageReader target : jpegTargets) { 463 target.close(); 464 } 465 for (ImageReader target : yuvTargets) { 466 target.close(); 467 } 468 for (ImageReader target : y8Targets) { 469 target.close(); 470 } 471 for (ImageReader target : rawTargets) { 472 target.close(); 473 } 474 for (ImageReader target : heicTargets) { 475 target.close(); 476 } 477 } 478 479 /** 480 * Test for making sure the required reprocess input/output combinations for each hardware 481 * level and capability work as expected. 482 */ 483 public void testMandatoryReprocessConfigurations() throws Exception { 484 for (String id : mCameraIds) { 485 openDevice(id); 486 MandatoryStreamCombination[] combinations = 487 mStaticInfo.getCharacteristics().get( 488 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 489 if (combinations == null) { 490 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 491 closeDevice(id); 492 continue; 493 } 494 495 try { 496 for (MandatoryStreamCombination combination : combinations) { 497 if (combination.isReprocessable()) { 498 Log.i(TAG, "Testing mandatory reprocessable stream combination: " + 499 combination.getDescription() + " on camera: " + id); 500 testMandatoryReprocessableStreamCombination(id, combination); 501 } 502 } 503 } finally { 504 closeDevice(id); 505 } 506 } 507 } 508 509 private void testMandatoryReprocessableStreamCombination(String cameraId, 510 MandatoryStreamCombination combination) { 511 // Test reprocess stream combination 512 testMandatoryReprocessableStreamCombination(cameraId, combination, 513 /*substituteY8*/false, /*substituteHeic*/false); 514 515 // Test substituting YUV_888 format with Y8 format in reprocess stream combination. 516 if (mStaticInfo.isMonochromeWithY8()) { 517 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 518 boolean substituteY8 = false; 519 for (MandatoryStreamInformation streamInfo : streamsInfo) { 520 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) { 521 substituteY8 = true; 522 } 523 } 524 if (substituteY8) { 525 testMandatoryReprocessableStreamCombination(cameraId, combination, 526 /*substituteY8*/true, /*substituteHeic*/false); 527 } 528 } 529 530 if (mStaticInfo.isHeicSupported()) { 531 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 532 boolean substituteHeic = false; 533 for (MandatoryStreamInformation streamInfo : streamsInfo) { 534 if (streamInfo.getFormat() == ImageFormat.JPEG) { 535 substituteHeic = true; 536 } 537 } 538 if (substituteHeic) { 539 testMandatoryReprocessableStreamCombination(cameraId, combination, 540 /*substituteY8*/false, /*substituteHeic*/true); 541 } 542 } 543 } 544 545 private void testMandatoryReprocessableStreamCombination(String cameraId, 546 MandatoryStreamCombination combination, boolean substituteY8, 547 boolean substituteHeic) { 548 549 final int TIMEOUT_FOR_RESULT_MS = 3000; 550 final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3; 551 552 List<SurfaceTexture> privTargets = new ArrayList<>(); 553 List<ImageReader> jpegTargets = new ArrayList<>(); 554 List<ImageReader> yuvTargets = new ArrayList<>(); 555 List<ImageReader> y8Targets = new ArrayList<>(); 556 List<ImageReader> rawTargets = new ArrayList<>(); 557 List<ImageReader> heicTargets = new ArrayList<>(); 558 ArrayList<Surface> outputSurfaces = new ArrayList<>(); 559 List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>(); 560 ImageReader inputReader = null; 561 ImageWriter inputWriter = null; 562 SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener(); 563 SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback(); 564 SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback(); 565 566 List<MandatoryStreamInformation> streamInfo = combination.getStreamsInformation(); 567 assertTrue("Reprocessable stream combinations should have at least 3 or more streams", 568 (streamInfo != null) && (streamInfo.size() >= 3)); 569 570 assertTrue("The first mandatory stream information in a reprocessable combination must " + 571 "always be input", streamInfo.get(0).isInput()); 572 573 List<Size> inputSizes = streamInfo.get(0).getAvailableSizes(); 574 int inputFormat = streamInfo.get(0).getFormat(); 575 if (substituteY8 && (inputFormat == ImageFormat.YUV_420_888)) { 576 inputFormat = ImageFormat.Y8; 577 } 578 579 Log.i(TAG, "testMandatoryReprocessableStreamCombination: " + 580 combination.getDescription() + ", substituteY8 = " + substituteY8 + 581 ", substituteHeic = " + substituteHeic); 582 try { 583 // The second stream information entry is the ZSL stream, which is configured 584 // separately. 585 setupConfigurationTargets(streamInfo.subList(2, streamInfo.size()), privTargets, 586 jpegTargets, yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs, 587 NUM_REPROCESS_CAPTURES_PER_CONFIG, substituteY8, substituteHeic, 588 null/*overridePhysicalCameraId*/); 589 590 outputSurfaces.ensureCapacity(outputConfigs.size()); 591 for (OutputConfiguration config : outputConfigs) { 592 outputSurfaces.add(config.getSurface()); 593 } 594 595 InputConfiguration inputConfig = new InputConfiguration(inputSizes.get(0).getWidth(), 596 inputSizes.get(0).getHeight(), inputFormat); 597 598 // For each config, YUV and JPEG outputs will be tested. (For YUV/Y8 reprocessing, 599 // the YUV/Y8 ImageReader for input is also used for output.) 600 final boolean inputIsYuv = inputConfig.getFormat() == ImageFormat.YUV_420_888; 601 final boolean inputIsY8 = inputConfig.getFormat() == ImageFormat.Y8; 602 final boolean useYuv = inputIsYuv || yuvTargets.size() > 0; 603 final boolean useY8 = inputIsY8 || y8Targets.size() > 0; 604 final int totalNumReprocessCaptures = NUM_REPROCESS_CAPTURES_PER_CONFIG * ( 605 ((inputIsYuv || inputIsY8) ? 1 : 0) + 606 (substituteHeic ? heicTargets.size() : jpegTargets.size()) + 607 (useYuv ? yuvTargets.size() : y8Targets.size())); 608 609 // It needs 1 input buffer for each reprocess capture + the number of buffers 610 // that will be used as outputs. 611 inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(), 612 inputConfig.getFormat(), 613 totalNumReprocessCaptures + NUM_REPROCESS_CAPTURES_PER_CONFIG); 614 inputReader.setOnImageAvailableListener(inputReaderListener, mHandler); 615 outputSurfaces.add(inputReader.getSurface()); 616 617 checkSessionConfigurationWithSurfaces(mCamera, mHandler, outputSurfaces, 618 inputConfig, SessionConfiguration.SESSION_REGULAR, /*defaultSupport*/ true, 619 String.format("Session configuration query %s failed", 620 combination.getDescription())); 621 622 // Verify we can create a reprocessable session with the input and all outputs. 623 BlockingSessionCallback sessionListener = new BlockingSessionCallback(); 624 CameraCaptureSession session = configureReprocessableCameraSession(mCamera, 625 inputConfig, outputSurfaces, sessionListener, mHandler); 626 inputWriter = ImageWriter.newInstance(session.getInputSurface(), 627 totalNumReprocessCaptures); 628 629 // Prepare a request for reprocess input 630 CaptureRequest.Builder builder = mCamera.createCaptureRequest( 631 CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 632 builder.addTarget(inputReader.getSurface()); 633 634 for (int i = 0; i < totalNumReprocessCaptures; i++) { 635 session.capture(builder.build(), inputCaptureListener, mHandler); 636 } 637 638 List<CaptureRequest> reprocessRequests = new ArrayList<>(); 639 List<Surface> reprocessOutputs = new ArrayList<>(); 640 if (inputIsYuv || inputIsY8) { 641 reprocessOutputs.add(inputReader.getSurface()); 642 } 643 644 for (ImageReader reader : jpegTargets) { 645 reprocessOutputs.add(reader.getSurface()); 646 } 647 648 for (ImageReader reader : heicTargets) { 649 reprocessOutputs.add(reader.getSurface()); 650 } 651 652 for (ImageReader reader : yuvTargets) { 653 reprocessOutputs.add(reader.getSurface()); 654 } 655 656 for (ImageReader reader : y8Targets) { 657 reprocessOutputs.add(reader.getSurface()); 658 } 659 660 for (int i = 0; i < NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) { 661 for (Surface output : reprocessOutputs) { 662 TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult( 663 TIMEOUT_FOR_RESULT_MS); 664 builder = mCamera.createReprocessCaptureRequest(result); 665 inputWriter.queueInputImage( 666 inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS)); 667 builder.addTarget(output); 668 reprocessRequests.add(builder.build()); 669 } 670 } 671 672 session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler); 673 674 for (int i = 0; i < reprocessOutputs.size() * NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) { 675 TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult( 676 TIMEOUT_FOR_RESULT_MS); 677 } 678 } catch (Throwable e) { 679 mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s", 680 combination.getDescription(), e.getMessage())); 681 } finally { 682 inputReaderListener.drain(); 683 reprocessOutputCaptureListener.drain(); 684 685 for (SurfaceTexture target : privTargets) { 686 target.release(); 687 } 688 689 for (ImageReader target : jpegTargets) { 690 target.close(); 691 } 692 693 for (ImageReader target : yuvTargets) { 694 target.close(); 695 } 696 697 for (ImageReader target : y8Targets) { 698 target.close(); 699 } 700 701 for (ImageReader target : rawTargets) { 702 target.close(); 703 } 704 705 for (ImageReader target : heicTargets) { 706 target.close(); 707 } 708 709 if (inputReader != null) { 710 inputReader.close(); 711 } 712 713 if (inputWriter != null) { 714 inputWriter.close(); 715 } 716 } 717 } 718 719 public void testBasicTriggerSequence() throws Exception { 720 721 for (String id : mCameraIds) { 722 Log.i(TAG, String.format("Testing Camera %s", id)); 723 724 try { 725 // Legacy devices do not support precapture trigger; don't test devices that 726 // can't focus 727 StaticMetadata staticInfo = mAllStaticInfo.get(id); 728 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 729 continue; 730 } 731 // Depth-only devices won't support AE 732 if (!staticInfo.isColorOutputSupported()) { 733 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 734 continue; 735 } 736 737 openDevice(id); 738 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 739 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 740 741 for (int afMode : availableAfModes) { 742 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 743 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 744 // Only test AF modes that have meaningful trigger behavior 745 continue; 746 } 747 748 for (int aeMode : availableAeModes) { 749 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 750 // Only test AE modes that have meaningful trigger behavior 751 continue; 752 } 753 754 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 755 756 CaptureRequest.Builder previewRequest = 757 prepareTriggerTestSession(preview, aeMode, afMode); 758 759 SimpleCaptureCallback captureListener = 760 new CameraTestUtils.SimpleCaptureCallback(); 761 762 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 763 mHandler); 764 765 // Cancel triggers 766 767 cancelTriggersAndWait(previewRequest, captureListener, afMode); 768 769 // 770 // Standard sequence - AF trigger then AE trigger 771 772 if (VERBOSE) { 773 Log.v(TAG, String.format("Triggering AF")); 774 } 775 776 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 777 CaptureRequest.CONTROL_AF_TRIGGER_START); 778 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 779 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 780 781 CaptureRequest triggerRequest = previewRequest.build(); 782 mCameraSession.capture(triggerRequest, captureListener, mHandler); 783 784 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 785 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 786 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 787 boolean focusComplete = false; 788 789 for (int i = 0; 790 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete; 791 i++) { 792 793 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 794 795 CaptureResult focusResult = captureListener.getCaptureResult( 796 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 797 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE); 798 } 799 800 assertTrue("Focusing never completed!", focusComplete); 801 802 // Standard sequence - Part 2 AE trigger 803 804 if (VERBOSE) { 805 Log.v(TAG, String.format("Triggering AE")); 806 } 807 808 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 809 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 810 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 811 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 812 813 triggerRequest = previewRequest.build(); 814 mCameraSession.capture(triggerRequest, captureListener, mHandler); 815 816 triggerResult = captureListener.getCaptureResultForRequest( 817 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 818 819 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 820 821 boolean precaptureComplete = false; 822 823 for (int i = 0; 824 i < MAX_TRIGGER_SEQUENCE_FRAMES && !precaptureComplete; 825 i++) { 826 827 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 828 829 CaptureResult precaptureResult = captureListener.getCaptureResult( 830 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 831 aeState = precaptureResult.get(CaptureResult.CONTROL_AE_STATE); 832 } 833 834 assertTrue("Precapture sequence never completed!", precaptureComplete); 835 836 for (int i = 0; i < MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES; i++) { 837 CaptureResult postPrecaptureResult = captureListener.getCaptureResult( 838 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 839 aeState = postPrecaptureResult.get(CaptureResult.CONTROL_AE_STATE); 840 assertTrue("Late transition to PRECAPTURE state seen", 841 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 842 } 843 844 // Done 845 846 stopCapture(/*fast*/ false); 847 preview.release(); 848 } 849 850 } 851 852 } finally { 853 closeDevice(id); 854 } 855 } 856 857 } 858 859 public void testSimultaneousTriggers() throws Exception { 860 for (String id : mCameraIds) { 861 Log.i(TAG, String.format("Testing Camera %s", id)); 862 863 try { 864 // Legacy devices do not support precapture trigger; don't test devices that 865 // can't focus 866 StaticMetadata staticInfo = mAllStaticInfo.get(id); 867 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 868 continue; 869 } 870 // Depth-only devices won't support AE 871 if (!staticInfo.isColorOutputSupported()) { 872 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 873 continue; 874 } 875 876 openDevice(id); 877 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 878 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 879 880 for (int afMode : availableAfModes) { 881 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 882 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 883 // Only test AF modes that have meaningful trigger behavior 884 continue; 885 } 886 887 for (int aeMode : availableAeModes) { 888 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 889 // Only test AE modes that have meaningful trigger behavior 890 continue; 891 } 892 893 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 894 895 CaptureRequest.Builder previewRequest = 896 prepareTriggerTestSession(preview, aeMode, afMode); 897 898 SimpleCaptureCallback captureListener = 899 new CameraTestUtils.SimpleCaptureCallback(); 900 901 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 902 mHandler); 903 904 // Cancel triggers 905 906 cancelTriggersAndWait(previewRequest, captureListener, afMode); 907 908 // 909 // Trigger AF and AE together 910 911 if (VERBOSE) { 912 Log.v(TAG, String.format("Triggering AF and AE together")); 913 } 914 915 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 916 CaptureRequest.CONTROL_AF_TRIGGER_START); 917 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 918 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 919 920 CaptureRequest triggerRequest = previewRequest.build(); 921 mCameraSession.capture(triggerRequest, captureListener, mHandler); 922 923 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 924 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 925 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 926 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 927 928 boolean precaptureComplete = false; 929 boolean focusComplete = false; 930 931 for (int i = 0; 932 i < MAX_TRIGGER_SEQUENCE_FRAMES && 933 !(focusComplete && precaptureComplete); 934 i++) { 935 936 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 937 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 938 939 CaptureResult sequenceResult = captureListener.getCaptureResult( 940 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 941 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 942 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 943 } 944 945 assertTrue("Precapture sequence never completed!", precaptureComplete); 946 assertTrue("Focus sequence never completed!", focusComplete); 947 948 // Done 949 950 stopCapture(/*fast*/ false); 951 preview.release(); 952 953 } 954 } 955 } finally { 956 closeDevice(id); 957 } 958 } 959 } 960 961 public void testAfThenAeTrigger() throws Exception { 962 for (String id : mCameraIds) { 963 Log.i(TAG, String.format("Testing Camera %s", id)); 964 965 try { 966 // Legacy devices do not support precapture trigger; don't test devices that 967 // can't focus 968 StaticMetadata staticInfo = mAllStaticInfo.get(id); 969 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 970 continue; 971 } 972 // Depth-only devices won't support AE 973 if (!staticInfo.isColorOutputSupported()) { 974 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 975 continue; 976 } 977 978 openDevice(id); 979 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 980 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 981 982 for (int afMode : availableAfModes) { 983 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 984 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 985 // Only test AF modes that have meaningful trigger behavior 986 continue; 987 } 988 989 for (int aeMode : availableAeModes) { 990 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 991 // Only test AE modes that have meaningful trigger behavior 992 continue; 993 } 994 995 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 996 997 CaptureRequest.Builder previewRequest = 998 prepareTriggerTestSession(preview, aeMode, afMode); 999 1000 SimpleCaptureCallback captureListener = 1001 new CameraTestUtils.SimpleCaptureCallback(); 1002 1003 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1004 mHandler); 1005 1006 // Cancel triggers 1007 1008 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1009 1010 // 1011 // AF with AE a request later 1012 1013 if (VERBOSE) { 1014 Log.v(TAG, "Trigger AF, then AE trigger on next request"); 1015 } 1016 1017 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1018 CaptureRequest.CONTROL_AF_TRIGGER_START); 1019 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1020 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1021 1022 CaptureRequest triggerRequest = previewRequest.build(); 1023 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1024 1025 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1026 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1027 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1028 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1029 1030 CaptureRequest triggerRequest2 = previewRequest.build(); 1031 mCameraSession.capture(triggerRequest2, captureListener, mHandler); 1032 1033 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1034 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1035 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1036 1037 boolean precaptureComplete = false; 1038 boolean focusComplete = false; 1039 1040 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1041 1042 triggerResult = captureListener.getCaptureResultForRequest( 1043 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1044 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1045 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1046 1047 for (int i = 0; 1048 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1049 !(focusComplete && precaptureComplete); 1050 i++) { 1051 1052 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1053 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1054 1055 CaptureResult sequenceResult = captureListener.getCaptureResult( 1056 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1057 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1058 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1059 } 1060 1061 assertTrue("Precapture sequence never completed!", precaptureComplete); 1062 assertTrue("Focus sequence never completed!", focusComplete); 1063 1064 // Done 1065 1066 stopCapture(/*fast*/ false); 1067 preview.release(); 1068 1069 } 1070 } 1071 } finally { 1072 closeDevice(id); 1073 } 1074 } 1075 } 1076 1077 public void testAeThenAfTrigger() throws Exception { 1078 for (String id : mCameraIds) { 1079 Log.i(TAG, String.format("Testing Camera %s", id)); 1080 1081 try { 1082 // Legacy devices do not support precapture trigger; don't test devices that 1083 // can't focus 1084 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1085 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1086 continue; 1087 } 1088 // Depth-only devices won't support AE 1089 if (!staticInfo.isColorOutputSupported()) { 1090 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1091 continue; 1092 } 1093 1094 openDevice(id); 1095 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1096 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1097 1098 for (int afMode : availableAfModes) { 1099 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1100 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1101 // Only test AF modes that have meaningful trigger behavior 1102 continue; 1103 } 1104 1105 for (int aeMode : availableAeModes) { 1106 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1107 // Only test AE modes that have meaningful trigger behavior 1108 continue; 1109 } 1110 1111 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1112 1113 CaptureRequest.Builder previewRequest = 1114 prepareTriggerTestSession(preview, aeMode, afMode); 1115 1116 SimpleCaptureCallback captureListener = 1117 new CameraTestUtils.SimpleCaptureCallback(); 1118 1119 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1120 mHandler); 1121 1122 // Cancel triggers 1123 1124 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1125 1126 // 1127 // AE with AF a request later 1128 1129 if (VERBOSE) { 1130 Log.v(TAG, "Trigger AE, then AF trigger on next request"); 1131 } 1132 1133 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1134 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1135 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1136 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1137 1138 CaptureRequest triggerRequest = previewRequest.build(); 1139 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1140 1141 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1142 CaptureRequest.CONTROL_AF_TRIGGER_START); 1143 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1144 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1145 1146 CaptureRequest triggerRequest2 = previewRequest.build(); 1147 mCameraSession.capture(triggerRequest2, captureListener, mHandler); 1148 1149 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1150 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1151 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1152 1153 boolean precaptureComplete = false; 1154 boolean focusComplete = false; 1155 1156 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1157 1158 triggerResult = captureListener.getCaptureResultForRequest( 1159 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1160 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1161 aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1162 1163 for (int i = 0; 1164 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1165 !(focusComplete && precaptureComplete); 1166 i++) { 1167 1168 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1169 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1170 1171 CaptureResult sequenceResult = captureListener.getCaptureResult( 1172 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1173 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1174 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1175 } 1176 1177 assertTrue("Precapture sequence never completed!", precaptureComplete); 1178 assertTrue("Focus sequence never completed!", focusComplete); 1179 1180 // Done 1181 1182 stopCapture(/*fast*/ false); 1183 preview.release(); 1184 1185 } 1186 } 1187 } finally { 1188 closeDevice(id); 1189 } 1190 } 1191 } 1192 1193 public void testAeAndAfCausality() throws Exception { 1194 1195 for (String id : mCameraIds) { 1196 Log.i(TAG, String.format("Testing Camera %s", id)); 1197 1198 try { 1199 // Legacy devices do not support precapture trigger; don't test devices that 1200 // can't focus 1201 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1202 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1203 continue; 1204 } 1205 // Depth-only devices won't support AE 1206 if (!staticInfo.isColorOutputSupported()) { 1207 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1208 continue; 1209 } 1210 1211 openDevice(id); 1212 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1213 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1214 final int maxPipelineDepth = mStaticInfo.getCharacteristics().get( 1215 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH); 1216 1217 for (int afMode : availableAfModes) { 1218 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1219 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1220 // Only test AF modes that have meaningful trigger behavior 1221 continue; 1222 } 1223 for (int aeMode : availableAeModes) { 1224 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1225 // Only test AE modes that have meaningful trigger behavior 1226 continue; 1227 } 1228 1229 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1230 1231 CaptureRequest.Builder previewRequest = 1232 prepareTriggerTestSession(preview, aeMode, afMode); 1233 1234 SimpleCaptureCallback captureListener = 1235 new CameraTestUtils.SimpleCaptureCallback(); 1236 1237 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1238 mHandler); 1239 1240 List<CaptureRequest> triggerRequests = 1241 new ArrayList<CaptureRequest>(maxPipelineDepth+1); 1242 for (int i = 0; i < maxPipelineDepth; i++) { 1243 triggerRequests.add(previewRequest.build()); 1244 } 1245 1246 // Cancel triggers 1247 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1248 1249 // 1250 // Standard sequence - Part 1 AF trigger 1251 1252 if (VERBOSE) { 1253 Log.v(TAG, String.format("Triggering AF")); 1254 } 1255 1256 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1257 CaptureRequest.CONTROL_AF_TRIGGER_START); 1258 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1259 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1260 triggerRequests.add(previewRequest.build()); 1261 1262 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1263 1264 TotalCaptureResult[] triggerResults = 1265 captureListener.getTotalCaptureResultsForRequests( 1266 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1267 for (int i = 0; i < maxPipelineDepth; i++) { 1268 TotalCaptureResult triggerResult = triggerResults[i]; 1269 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1270 int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER); 1271 1272 verifyStartingAfState(afMode, afState); 1273 assertTrue(String.format("In AF mode %s, previous AF_TRIGGER must not " 1274 + "be START before TRIGGER_START", 1275 StaticMetadata.getAfModeName(afMode)), 1276 afTrigger != CaptureResult.CONTROL_AF_TRIGGER_START); 1277 } 1278 1279 int afState = 1280 triggerResults[maxPipelineDepth].get(CaptureResult.CONTROL_AF_STATE); 1281 boolean focusComplete = false; 1282 for (int i = 0; 1283 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete; 1284 i++) { 1285 1286 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1287 1288 CaptureResult focusResult = captureListener.getCaptureResult( 1289 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1290 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE); 1291 } 1292 1293 assertTrue("Focusing never completed!", focusComplete); 1294 1295 // Standard sequence - Part 2 AE trigger 1296 1297 if (VERBOSE) { 1298 Log.v(TAG, String.format("Triggering AE")); 1299 } 1300 // Remove AF trigger request 1301 triggerRequests.remove(maxPipelineDepth); 1302 1303 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1304 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1305 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1306 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1307 triggerRequests.add(previewRequest.build()); 1308 1309 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1310 1311 triggerResults = captureListener.getTotalCaptureResultsForRequests( 1312 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1313 1314 for (int i = 0; i < maxPipelineDepth; i++) { 1315 TotalCaptureResult triggerResult = triggerResults[i]; 1316 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1317 int aeTrigger = triggerResult.get( 1318 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER); 1319 1320 assertTrue(String.format("In AE mode %s, previous AE_TRIGGER must not " 1321 + "be START before TRIGGER_START", 1322 StaticMetadata.getAeModeName(aeMode)), 1323 aeTrigger != CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1324 assertTrue(String.format("In AE mode %s, previous AE_STATE must not be" 1325 + " PRECAPTURE_TRIGGER before TRIGGER_START", 1326 StaticMetadata.getAeModeName(aeMode)), 1327 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 1328 } 1329 1330 // Stand sequence - Part 3 Cancel AF trigger 1331 if (VERBOSE) { 1332 Log.v(TAG, String.format("Cancel AF trigger")); 1333 } 1334 // Remove AE trigger request 1335 triggerRequests.remove(maxPipelineDepth); 1336 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1337 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 1338 triggerRequests.add(previewRequest.build()); 1339 1340 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1341 triggerResults = captureListener.getTotalCaptureResultsForRequests( 1342 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1343 for (int i = 0; i < maxPipelineDepth; i++) { 1344 TotalCaptureResult triggerResult = triggerResults[i]; 1345 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1346 int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER); 1347 1348 assertTrue( 1349 String.format("In AF mode %s, previous AF_TRIGGER must not " + 1350 "be CANCEL before TRIGGER_CANCEL", 1351 StaticMetadata.getAfModeName(afMode)), 1352 afTrigger != CaptureResult.CONTROL_AF_TRIGGER_CANCEL); 1353 assertTrue( 1354 String.format("In AF mode %s, previous AF_STATE must be LOCKED" 1355 + " before CANCEL, but is %s", 1356 StaticMetadata.getAfModeName(afMode), 1357 StaticMetadata.AF_STATE_NAMES[afState]), 1358 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1359 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1360 } 1361 1362 stopCapture(/*fast*/ false); 1363 preview.release(); 1364 } 1365 1366 } 1367 1368 } finally { 1369 closeDevice(id); 1370 } 1371 } 1372 1373 } 1374 1375 public void testAbandonRepeatingRequestSurface() throws Exception { 1376 for (String id : mCameraIds) { 1377 Log.i(TAG, String.format( 1378 "Testing Camera %s for abandoning surface of a repeating request", id)); 1379 1380 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1381 if (!staticInfo.isColorOutputSupported()) { 1382 Log.i(TAG, "Camera " + id + " does not support color output, skipping"); 1383 continue; 1384 } 1385 1386 openDevice(id); 1387 1388 try { 1389 1390 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1391 Surface previewSurface = new Surface(preview); 1392 1393 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1394 SimpleCaptureCallback captureListener = new CameraTestUtils.SimpleCaptureCallback(); 1395 1396 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1397 captureListener, mHandler); 1398 1399 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) { 1400 captureListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1401 } 1402 1403 // Abandon preview surface. 1404 preview.release(); 1405 1406 // Check onCaptureSequenceCompleted is received. 1407 long sequenceLastFrameNumber = captureListener.getCaptureSequenceLastFrameNumber( 1408 sequenceId, CAPTURE_TIMEOUT); 1409 1410 mCameraSession.stopRepeating(); 1411 1412 // Find the last frame number received in results and failures. 1413 long lastFrameNumber = -1; 1414 while (captureListener.hasMoreResults()) { 1415 TotalCaptureResult result = captureListener.getTotalCaptureResult( 1416 CAPTURE_TIMEOUT); 1417 if (lastFrameNumber < result.getFrameNumber()) { 1418 lastFrameNumber = result.getFrameNumber(); 1419 } 1420 } 1421 1422 while (captureListener.hasMoreFailures()) { 1423 ArrayList<CaptureFailure> failures = captureListener.getCaptureFailures( 1424 /*maxNumFailures*/ 1); 1425 for (CaptureFailure failure : failures) { 1426 if (lastFrameNumber < failure.getFrameNumber()) { 1427 lastFrameNumber = failure.getFrameNumber(); 1428 } 1429 } 1430 } 1431 1432 // Verify the last frame number received from capture sequence completed matches the 1433 // the last frame number of the results and failures. 1434 assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " + 1435 "(%d) doesn't match the last frame number received from " + 1436 "results/failures (%d)", sequenceLastFrameNumber, lastFrameNumber), 1437 sequenceLastFrameNumber, lastFrameNumber); 1438 } finally { 1439 closeDevice(id); 1440 } 1441 } 1442 } 1443 1444 public void testConfigureAbandonedSurface() throws Exception { 1445 for (String id : mCameraIds) { 1446 Log.i(TAG, String.format( 1447 "Testing Camera %s for configuring abandoned surface", id)); 1448 1449 openDevice(id); 1450 try { 1451 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1452 Surface previewSurface = new Surface(preview); 1453 1454 // Abandon preview SurfaceTexture. 1455 preview.release(); 1456 1457 try { 1458 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1459 fail("Configuring abandoned surfaces must fail!"); 1460 } catch (IllegalArgumentException e) { 1461 // expected 1462 Log.i(TAG, "normal session check passed"); 1463 } 1464 1465 // Try constrained high speed session/requests 1466 if (!mStaticInfo.isConstrainedHighSpeedVideoSupported()) { 1467 continue; 1468 } 1469 1470 List<Surface> surfaces = new ArrayList<>(); 1471 surfaces.add(previewSurface); 1472 CameraCaptureSession.StateCallback sessionListener = 1473 mock(CameraCaptureSession.StateCallback.class); 1474 1475 try { 1476 mCamera.createConstrainedHighSpeedCaptureSession(surfaces, 1477 sessionListener, mHandler); 1478 fail("Configuring abandoned surfaces in high speed session must fail!"); 1479 } catch (IllegalArgumentException e) { 1480 // expected 1481 Log.i(TAG, "high speed session check 1 passed"); 1482 } 1483 1484 // Also try abandone the Surface directly 1485 previewSurface.release(); 1486 1487 try { 1488 mCamera.createConstrainedHighSpeedCaptureSession(surfaces, 1489 sessionListener, mHandler); 1490 fail("Configuring abandoned surfaces in high speed session must fail!"); 1491 } catch (IllegalArgumentException e) { 1492 // expected 1493 Log.i(TAG, "high speed session check 2 passed"); 1494 } 1495 } finally { 1496 closeDevice(id); 1497 } 1498 } 1499 } 1500 1501 public void testAfSceneChange() throws Exception { 1502 final int NUM_FRAMES_VERIFIED = 3; 1503 1504 for (String id : mCameraIds) { 1505 Log.i(TAG, String.format("Testing Camera %s for AF scene change", id)); 1506 1507 StaticMetadata staticInfo = 1508 new StaticMetadata(mCameraManager.getCameraCharacteristics(id)); 1509 if (!staticInfo.isAfSceneChangeSupported()) { 1510 continue; 1511 } 1512 1513 openDevice(id); 1514 1515 try { 1516 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1517 Surface previewSurface = new Surface(preview); 1518 1519 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1520 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback(); 1521 1522 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1523 1524 // Test AF scene change in each AF mode. 1525 for (int afMode : availableAfModes) { 1526 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode); 1527 1528 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1529 previewListener, mHandler); 1530 1531 // Verify that AF scene change is NOT_DETECTED or DETECTED. 1532 for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) { 1533 TotalCaptureResult result = 1534 previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1535 mCollector.expectKeyValueIsIn(result, 1536 CaptureResult.CONTROL_AF_SCENE_CHANGE, 1537 CaptureResult.CONTROL_AF_SCENE_CHANGE_DETECTED, 1538 CaptureResult.CONTROL_AF_SCENE_CHANGE_NOT_DETECTED); 1539 } 1540 1541 mCameraSession.stopRepeating(); 1542 previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT); 1543 previewListener.drain(); 1544 } 1545 } finally { 1546 closeDevice(id); 1547 } 1548 } 1549 } 1550 1551 public void testOisDataMode() throws Exception { 1552 final int NUM_FRAMES_VERIFIED = 3; 1553 1554 for (String id : mCameraIds) { 1555 Log.i(TAG, String.format("Testing Camera %s for OIS mode", id)); 1556 1557 StaticMetadata staticInfo = 1558 new StaticMetadata(mCameraManager.getCameraCharacteristics(id)); 1559 if (!staticInfo.isOisDataModeSupported()) { 1560 continue; 1561 } 1562 1563 openDevice(id); 1564 1565 try { 1566 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1567 Surface previewSurface = new Surface(preview); 1568 1569 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1570 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback(); 1571 1572 int[] availableOisDataModes = staticInfo.getCharacteristics().get( 1573 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES); 1574 1575 // Test each OIS data mode 1576 for (int oisMode : availableOisDataModes) { 1577 previewRequest.set(CaptureRequest.STATISTICS_OIS_DATA_MODE, oisMode); 1578 1579 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1580 previewListener, mHandler); 1581 1582 // Check OIS data in each mode. 1583 for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) { 1584 TotalCaptureResult result = 1585 previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1586 1587 OisSample[] oisSamples = result.get(CaptureResult.STATISTICS_OIS_SAMPLES); 1588 1589 if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_OFF) { 1590 mCollector.expectKeyValueEquals(result, 1591 CaptureResult.STATISTICS_OIS_DATA_MODE, 1592 CaptureResult.STATISTICS_OIS_DATA_MODE_OFF); 1593 mCollector.expectTrue("OIS samples reported in OIS_DATA_MODE_OFF", 1594 oisSamples == null || oisSamples.length == 0); 1595 1596 } else if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_ON) { 1597 mCollector.expectKeyValueEquals(result, 1598 CaptureResult.STATISTICS_OIS_DATA_MODE, 1599 CaptureResult.STATISTICS_OIS_DATA_MODE_ON); 1600 mCollector.expectTrue("OIS samples not reported in OIS_DATA_MODE_ON", 1601 oisSamples != null && oisSamples.length != 0); 1602 } else { 1603 mCollector.addMessage(String.format("Invalid OIS mode: %d", oisMode)); 1604 } 1605 } 1606 1607 mCameraSession.stopRepeating(); 1608 previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT); 1609 previewListener.drain(); 1610 } 1611 } finally { 1612 closeDevice(id); 1613 } 1614 } 1615 } 1616 1617 private CaptureRequest.Builder preparePreviewTestSession(SurfaceTexture preview) 1618 throws Exception { 1619 Surface previewSurface = new Surface(preview); 1620 1621 preview.setDefaultBufferSize(640, 480); 1622 1623 ArrayList<Surface> sessionOutputs = new ArrayList<>(); 1624 sessionOutputs.add(previewSurface); 1625 1626 createSession(sessionOutputs); 1627 1628 CaptureRequest.Builder previewRequest = 1629 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1630 1631 previewRequest.addTarget(previewSurface); 1632 1633 return previewRequest; 1634 } 1635 1636 private CaptureRequest.Builder prepareTriggerTestSession( 1637 SurfaceTexture preview, int aeMode, int afMode) throws Exception { 1638 Log.i(TAG, String.format("Testing AE mode %s, AF mode %s", 1639 StaticMetadata.getAeModeName(aeMode), 1640 StaticMetadata.getAfModeName(afMode))); 1641 1642 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1643 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, aeMode); 1644 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode); 1645 1646 return previewRequest; 1647 } 1648 1649 private void cancelTriggersAndWait(CaptureRequest.Builder previewRequest, 1650 SimpleCaptureCallback captureListener, int afMode) throws Exception { 1651 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1652 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 1653 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1654 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL); 1655 1656 CaptureRequest triggerRequest = previewRequest.build(); 1657 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1658 1659 // Wait for a few frames to initialize 3A 1660 1661 CaptureResult previewResult = null; 1662 int afState; 1663 int aeState; 1664 1665 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) { 1666 previewResult = captureListener.getCaptureResult( 1667 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1668 if (VERBOSE) { 1669 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE); 1670 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE); 1671 Log.v(TAG, String.format("AF state: %s, AE state: %s", 1672 StaticMetadata.AF_STATE_NAMES[afState], 1673 StaticMetadata.AE_STATE_NAMES[aeState])); 1674 } 1675 } 1676 1677 // Verify starting states 1678 1679 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE); 1680 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE); 1681 1682 verifyStartingAfState(afMode, afState); 1683 1684 // After several frames, AE must no longer be in INACTIVE state 1685 assertTrue(String.format("AE state must be SEARCHING, CONVERGED, " + 1686 "or FLASH_REQUIRED, is %s", StaticMetadata.AE_STATE_NAMES[aeState]), 1687 aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING || 1688 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED || 1689 aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED); 1690 } 1691 1692 private void verifyStartingAfState(int afMode, int afState) { 1693 switch (afMode) { 1694 case CaptureResult.CONTROL_AF_MODE_AUTO: 1695 case CaptureResult.CONTROL_AF_MODE_MACRO: 1696 assertTrue(String.format("AF state not INACTIVE, is %s", 1697 StaticMetadata.AF_STATE_NAMES[afState]), 1698 afState == CaptureResult.CONTROL_AF_STATE_INACTIVE); 1699 break; 1700 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 1701 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 1702 // After several frames, AF must no longer be in INACTIVE state 1703 assertTrue(String.format("In AF mode %s, AF state not PASSIVE_SCAN" + 1704 ", PASSIVE_FOCUSED, or PASSIVE_UNFOCUSED, is %s", 1705 StaticMetadata.getAfModeName(afMode), 1706 StaticMetadata.AF_STATE_NAMES[afState]), 1707 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN || 1708 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED || 1709 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED); 1710 break; 1711 default: 1712 fail("unexpected af mode"); 1713 } 1714 } 1715 1716 private boolean verifyAfSequence(int afMode, int afState, boolean focusComplete) { 1717 if (focusComplete) { 1718 assertTrue(String.format("AF Mode %s: Focus lock lost after convergence: AF state: %s", 1719 StaticMetadata.getAfModeName(afMode), 1720 StaticMetadata.AF_STATE_NAMES[afState]), 1721 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1722 afState ==CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1723 return focusComplete; 1724 } 1725 if (VERBOSE) { 1726 Log.v(TAG, String.format("AF mode: %s, AF state: %s", 1727 StaticMetadata.getAfModeName(afMode), 1728 StaticMetadata.AF_STATE_NAMES[afState])); 1729 } 1730 switch (afMode) { 1731 case CaptureResult.CONTROL_AF_MODE_AUTO: 1732 case CaptureResult.CONTROL_AF_MODE_MACRO: 1733 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 1734 StaticMetadata.getAfModeName(afMode), 1735 StaticMetadata.AF_STATE_NAMES[afState]), 1736 afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN || 1737 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1738 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1739 focusComplete = 1740 (afState != CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN); 1741 break; 1742 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 1743 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 1744 StaticMetadata.getAfModeName(afMode), 1745 StaticMetadata.AF_STATE_NAMES[afState]), 1746 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN || 1747 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1748 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1749 focusComplete = 1750 (afState != CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN); 1751 break; 1752 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 1753 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 1754 StaticMetadata.getAfModeName(afMode), 1755 StaticMetadata.AF_STATE_NAMES[afState]), 1756 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1757 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1758 focusComplete = true; 1759 break; 1760 default: 1761 fail("Unexpected AF mode: " + StaticMetadata.getAfModeName(afMode)); 1762 } 1763 return focusComplete; 1764 } 1765 1766 private boolean verifyAeSequence(int aeState, boolean precaptureComplete) { 1767 if (precaptureComplete) { 1768 assertTrue("Precapture state seen after convergence", 1769 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 1770 return precaptureComplete; 1771 } 1772 if (VERBOSE) { 1773 Log.v(TAG, String.format("AE state: %s", StaticMetadata.AE_STATE_NAMES[aeState])); 1774 } 1775 switch (aeState) { 1776 case CaptureResult.CONTROL_AE_STATE_PRECAPTURE: 1777 // scan still continuing 1778 break; 1779 case CaptureResult.CONTROL_AE_STATE_CONVERGED: 1780 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 1781 // completed 1782 precaptureComplete = true; 1783 break; 1784 default: 1785 fail(String.format("Precapture sequence transitioned to " 1786 + "state %s incorrectly!", StaticMetadata.AE_STATE_NAMES[aeState])); 1787 break; 1788 } 1789 return precaptureComplete; 1790 } 1791 1792 } 1793