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.SessionConfigSupport; 20 import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 21 import static android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener; 22 import static android.hardware.camera2.cts.CameraTestUtils.StreamCombinationTargets; 23 import static android.hardware.camera2.cts.CameraTestUtils.assertEquals; 24 import static android.hardware.camera2.cts.CameraTestUtils.assertNotNull; 25 import static android.hardware.camera2.cts.CameraTestUtils.assertNull; 26 import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationSupported; 27 import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationWithSurfaces; 28 import static android.hardware.camera2.cts.CameraTestUtils.configureReprocessableCameraSession; 29 import static android.hardware.camera2.cts.CameraTestUtils.fail; 30 import static android.hardware.camera2.cts.CameraTestUtils.getUnavailablePhysicalCameras; 31 import static android.hardware.camera2.cts.CameraTestUtils.isSessionConfigSupported; 32 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes; 33 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.JPEG; 34 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.MAXIMUM; 35 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.MAX_RES; 36 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.PREVIEW; 37 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.PRIV; 38 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.RAW; 39 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.RECORD; 40 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.S1440P_4_3; 41 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.S720P; 42 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.USE_CASE_PREVIEW; 43 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.USE_CASE_PREVIEW_VIDEO_STILL; 44 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.USE_CASE_STILL_CAPTURE; 45 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.USE_CASE_VIDEO_CALL; 46 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.USE_CASE_VIDEO_RECORD; 47 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.USE_CASE_CROPPED_RAW; 48 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.VGA; 49 import static android.hardware.camera2.cts.CameraTestUtils.MaxStreamSizes.YUV; 50 51 import static junit.framework.Assert.assertFalse; 52 import static junit.framework.Assert.assertTrue; 53 54 import static org.mockito.Mockito.any; 55 import static org.mockito.Mockito.eq; 56 import static org.mockito.Mockito.isA; 57 import static org.mockito.Mockito.mock; 58 import static org.mockito.Mockito.never; 59 import static org.mockito.Mockito.timeout; 60 import static org.mockito.Mockito.verify; 61 62 import android.graphics.ImageFormat; 63 import android.graphics.Rect; 64 import android.graphics.SurfaceTexture; 65 import android.hardware.camera2.CameraCaptureSession; 66 import android.hardware.camera2.CameraCharacteristics; 67 import android.hardware.camera2.CameraDevice; 68 import android.hardware.camera2.CameraMetadata; 69 import android.hardware.camera2.CaptureFailure; 70 import android.hardware.camera2.CaptureRequest; 71 import android.hardware.camera2.CaptureResult; 72 import android.hardware.camera2.TotalCaptureResult; 73 import android.hardware.camera2.cts.helpers.StaticMetadata; 74 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 75 import android.hardware.camera2.params.DynamicRangeProfiles; 76 import android.hardware.camera2.params.InputConfiguration; 77 import android.hardware.camera2.params.MandatoryStreamCombination; 78 import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation; 79 import android.hardware.camera2.params.OisSample; 80 import android.hardware.camera2.params.OutputConfiguration; 81 import android.hardware.camera2.params.SessionConfiguration; 82 import android.hardware.camera2.params.StreamConfigurationMap; 83 import android.media.Image; 84 import android.media.ImageReader; 85 import android.media.ImageWriter; 86 import android.util.Log; 87 import android.util.Pair; 88 import android.util.Size; 89 import android.view.Surface; 90 91 import com.android.ex.camera2.blocking.BlockingSessionCallback; 92 93 import org.junit.Test; 94 import org.junit.runner.RunWith; 95 import org.junit.runners.Parameterized; 96 97 import java.util.ArrayList; 98 import java.util.Arrays; 99 import java.util.HashSet; 100 import java.util.Iterator; 101 import java.util.List; 102 import java.util.Set; 103 104 /** 105 * Tests exercising edge cases in camera setup, configuration, and usage. 106 */ 107 108 @RunWith(Parameterized.class) 109 public class RobustnessTest extends Camera2AndroidTestCase { 110 private static final String TAG = "RobustnessTest"; 111 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 112 113 private static final int CONFIGURE_TIMEOUT = 5000; //ms 114 private static final int CAPTURE_TIMEOUT = 1500; //ms 115 116 // For testTriggerInteractions 117 private static final int PREVIEW_WARMUP_FRAMES = 60; 118 private static final int MAX_RESULT_STATE_CHANGE_WAIT_FRAMES = 100; 119 private static final int MAX_TRIGGER_SEQUENCE_FRAMES = 180; // 6 sec at 30 fps 120 private static final int MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES = 10; 121 122 /** 123 * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing 124 * a dimension other than one of the supported output dimensions. The buffers produced into 125 * this surface are expected have the dimensions of the closest possible buffer size in the 126 * available stream configurations for a surface with this format. 127 */ 128 @Test testBadSurfaceDimensions()129 public void testBadSurfaceDimensions() throws Exception { 130 for (String id : getCameraIdsUnderTest()) { 131 try { 132 Log.i(TAG, "Testing Camera " + id); 133 openDevice(id); 134 135 List<Size> testSizes = null; 136 int format = mStaticInfo.isColorOutputSupported() ? 137 ImageFormat.YUV_420_888 : ImageFormat.DEPTH16; 138 139 testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager, 140 format, null); 141 142 // Find some size not supported by the camera 143 Size weirdSize = new Size(643, 577); 144 int count = 0; 145 while(testSizes.contains(weirdSize)) { 146 // Really, they can't all be supported... 147 weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1); 148 count++; 149 assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100); 150 } 151 152 // Setup imageReader with invalid dimension 153 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(), 154 weirdSize.getHeight(), format, 3); 155 156 // Setup ImageReaderListener 157 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 158 imageReader.setOnImageAvailableListener(imageListener, mHandler); 159 160 Surface surface = imageReader.getSurface(); 161 List<Surface> surfaces = new ArrayList<>(); 162 surfaces.add(surface); 163 164 // Setup a capture request and listener 165 CaptureRequest.Builder request = 166 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 167 request.addTarget(surface); 168 169 // Check that correct session callback is hit. 170 CameraCaptureSession.StateCallback sessionListener = 171 mock(CameraCaptureSession.StateCallback.class); 172 CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera, 173 surfaces, sessionListener, mHandler); 174 175 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()). 176 onConfigured(any(CameraCaptureSession.class)); 177 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()). 178 onReady(any(CameraCaptureSession.class)); 179 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class)); 180 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class)); 181 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class)); 182 183 CameraCaptureSession.CaptureCallback captureListener = 184 mock(CameraCaptureSession.CaptureCallback.class); 185 session.capture(request.build(), captureListener, mHandler); 186 187 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()). 188 onCaptureCompleted(any(CameraCaptureSession.class), 189 any(CaptureRequest.class), any(TotalCaptureResult.class)); 190 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class), 191 any(CaptureRequest.class), any(CaptureFailure.class)); 192 193 Image image = imageListener.getImage(CAPTURE_TIMEOUT); 194 int imageWidth = image.getWidth(); 195 int imageHeight = image.getHeight(); 196 Size actualSize = new Size(imageWidth, imageHeight); 197 198 assertTrue("Camera does not contain outputted image resolution " + actualSize, 199 testSizes.contains(actualSize)); 200 imageReader.close(); 201 } finally { 202 closeDevice(id); 203 } 204 } 205 } 206 207 /** 208 * Test for making sure the mandatory stream combinations work as expected. 209 */ 210 @Test testMandatoryOutputCombinations()211 public void testMandatoryOutputCombinations() throws Exception { 212 testMandatoryOutputCombinations(/*maxResolution*/false); 213 } 214 215 /** 216 * Test for making sure the mandatory stream combinations work as expected. 217 */ testMandatoryOutputCombinations(boolean maxResolution)218 private void testMandatoryOutputCombinations(boolean maxResolution) throws Exception { 219 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 220 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS; 221 222 if (maxResolution) { 223 ck = CameraCharacteristics.SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS; 224 } 225 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 226 Set<Pair<String, String>> unavailablePhysicalCameras = getUnavailablePhysicalCameras( 227 mCameraManager, mHandler); 228 for (String id : cameraIdsUnderTest) { 229 openDevice(id); 230 MandatoryStreamCombination[] combinations = mStaticInfo.getCharacteristics().get(ck); 231 232 if (combinations == null) { 233 String maxResolutionStr = maxResolution ? " " : " maximum resolution "; 234 Log.i(TAG, "No mandatory" + maxResolutionStr + "stream combinations for camera: " + 235 id + " skip test"); 236 closeDevice(id); 237 continue; 238 } 239 240 try { 241 for (MandatoryStreamCombination combination : combinations) { 242 if (!combination.isReprocessable()) { 243 if (maxResolution) { 244 testMandatoryStreamCombination(id, mStaticInfo, 245 /*physicalCameraId*/ null, combination, /*substituteY8*/false, 246 /*substituteHeic*/false, /*maxResolution*/true); 247 } else { 248 testMandatoryStreamCombination(id, mStaticInfo, 249 null/*physicalCameraId*/, combination); 250 } 251 } 252 } 253 254 // Make sure mandatory stream combinations for each physical camera work 255 // as expected. 256 if (mStaticInfo.isLogicalMultiCamera()) { 257 Set<String> physicalCameraIds = 258 mStaticInfo.getCharacteristics().getPhysicalCameraIds(); 259 for (String physicalId : physicalCameraIds) { 260 if (Arrays.asList(cameraIdsUnderTest).contains(physicalId)) { 261 // If physicalId is advertised in camera ID list, do not need to test 262 // its stream combination through logical camera. 263 continue; 264 } 265 if (unavailablePhysicalCameras.contains(new Pair<>(id, physicalId))) { 266 // If physicalId is unavailable, do not attempt to test its 267 // stream combinations. 268 continue; 269 } 270 271 StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId); 272 273 MandatoryStreamCombination[] phyCombinations = 274 physicalStaticInfo.getCharacteristics().get(ck); 275 276 if (phyCombinations == null) { 277 Log.i(TAG, "No mandatory stream combinations for physical camera device: " + id + " skip test"); 278 continue; 279 } 280 281 for (MandatoryStreamCombination combination : phyCombinations) { 282 if (!combination.isReprocessable()) { 283 if (maxResolution) { 284 testMandatoryStreamCombination(id, physicalStaticInfo, 285 physicalId, combination, /*substituteY8*/false, 286 /*substituteHeic*/false, /*maxResolution*/true); 287 } else { 288 testMandatoryStreamCombination(id, physicalStaticInfo, 289 physicalId, combination); 290 } 291 } 292 } 293 } 294 } 295 296 } finally { 297 closeDevice(id); 298 } 299 } 300 } 301 302 303 /** 304 * Test for making sure the mandatory stream combinations work as expected. 305 */ 306 @Test testMandatoryMaximumResolutionOutputCombinations()307 public void testMandatoryMaximumResolutionOutputCombinations() throws Exception { 308 testMandatoryOutputCombinations(/*maxResolution*/ true); 309 } 310 311 /** 312 * Test for making sure the mandatory use case stream combinations work as expected. 313 */ 314 @Test testMandatoryUseCaseOutputCombinations()315 public void testMandatoryUseCaseOutputCombinations() throws Exception { 316 for (String id : getCameraIdsUnderTest()) { 317 StaticMetadata info = mAllStaticInfo.get(id); 318 CameraCharacteristics chars = info.getCharacteristics(); 319 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 320 CameraCharacteristics.SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS; 321 MandatoryStreamCombination[] combinations = chars.get(ck); 322 323 if (!info.isCapabilitySupported( 324 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) { 325 assertNull(combinations); 326 Log.i(TAG, "Camera id " + id + " doesn't support stream use case, skip test"); 327 continue; 328 } 329 330 assertNotNull(combinations); 331 openDevice(id); 332 333 try { 334 Rect preCorrectionActiveArrayRect = info.getPreCorrectedActiveArraySizeChecked(); 335 for (MandatoryStreamCombination combination : combinations) { 336 Log.i(TAG, "Testing fixed mandatory output combination with stream use case: " + 337 combination.getDescription() + " on camera: " + id); 338 CaptureRequest.Builder requestBuilder = 339 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 340 testMandatoryOutputCombinationWithPresetKeys(id, combination, requestBuilder, 341 preCorrectionActiveArrayRect); 342 } 343 } finally { 344 closeDevice(id); 345 } 346 } 347 } 348 349 @Test testMandatoryPreviewStabilizationOutputCombinations()350 public void testMandatoryPreviewStabilizationOutputCombinations() throws Exception { 351 for (String id : getCameraIdsUnderTest()) { 352 StaticMetadata info = mAllStaticInfo.get(id); 353 boolean previewStabilizationSupported = isPreviewStabilizationSupported(info); 354 CameraCharacteristics chars = info.getCharacteristics(); 355 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 356 CameraCharacteristics 357 .SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS; 358 MandatoryStreamCombination[] combinations = chars.get(ck); 359 360 if (combinations == null) { 361 assertFalse("Preview stabilization supported by camera id: " + id 362 + " but null mandatory streams", previewStabilizationSupported); 363 Log.i(TAG, "Camera id " + id + " doesn't support preview stabilization, skip test"); 364 continue; 365 } else { 366 assertTrue("Preview stabilization not supported by camera id: " + id 367 + " but non-null mandatory streams", previewStabilizationSupported); 368 } 369 370 openDevice(id); 371 372 try { 373 for (MandatoryStreamCombination combination : combinations) { 374 Log.i(TAG, "Testing fixed mandatory output combination with preview" 375 + "stabilization case: " + combination.getDescription() + " on camera: " 376 + id); 377 CaptureRequest.Builder requestBuilder = 378 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 379 requestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, 380 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION); 381 testMandatoryOutputCombinationWithPresetKeys(id, combination, requestBuilder, 382 /*preCorrectionActiveArrayRect*/null); 383 } 384 } finally { 385 closeDevice(id); 386 } 387 } 388 } 389 isPreviewStabilizationSupported(StaticMetadata info)390 private boolean isPreviewStabilizationSupported(StaticMetadata info) { 391 int[] availableVideoStabilizationModes = info.getAvailableVideoStabilizationModesChecked(); 392 if (availableVideoStabilizationModes == null) { 393 return false; 394 } 395 for (int mode : availableVideoStabilizationModes) { 396 if (mode == CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) { 397 return true; 398 } 399 } 400 return false; 401 } 402 testMandatoryOutputCombinationWithPresetKeys(String cameraId, MandatoryStreamCombination combination, CaptureRequest.Builder requestBuilderWithKeys, Rect preCorrectionActiveArrayRect)403 private void testMandatoryOutputCombinationWithPresetKeys(String cameraId, 404 MandatoryStreamCombination combination, CaptureRequest.Builder requestBuilderWithKeys, 405 Rect preCorrectionActiveArrayRect) { 406 final int TIMEOUT_FOR_RESULT_MS = 1000; 407 final int MIN_RESULT_COUNT = 3; 408 409 // Setup outputs 410 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 411 List<Surface> outputSurfaces = new ArrayList<Surface>(); 412 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 413 StreamCombinationTargets targets = new StreamCombinationTargets(); 414 415 CameraTestUtils.setupConfigurationTargets(combination.getStreamsInformation(), 416 targets, outputConfigs, outputSurfaces, uhOutputSurfaces, MIN_RESULT_COUNT, 417 /*substituteY8*/ false, /*substituteHeic*/false, 418 /*physicalCameraId*/ null, 419 /*multiResStreamConfig*/null, mHandler, 420 /*dynamicRangeProfiles*/ null); 421 422 boolean haveSession = false; 423 try { 424 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 425 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 426 mCameraManager, true/*defaultSupport*/, 427 String.format("Session configuration query from combination: %s failed", 428 combination.getDescription())); 429 430 createSessionByConfigs(outputConfigs); 431 haveSession = true; 432 for (Surface s : outputSurfaces) { 433 requestBuilderWithKeys.addTarget(s); 434 } 435 boolean croppedRawUseCase = false; 436 for (OutputConfiguration c : outputConfigs) { 437 if (c.getStreamUseCase() == 438 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW) { 439 croppedRawUseCase = true; 440 break; 441 } 442 } 443 444 CaptureRequest request = requestBuilderWithKeys.build(); 445 CameraTestUtils.SimpleCaptureCallback captureCallback = 446 new CameraTestUtils.SimpleCaptureCallback(); 447 448 449 mCameraSession.setRepeatingRequest(request, captureCallback, mHandler); 450 451 for (int i = 0; i < MIN_RESULT_COUNT; i++) { 452 // Makes sure that we received an onCaptureCompleted and not an onCaptureFailed. 453 TotalCaptureResult result = 454 captureCallback.getTotalCaptureResultForRequest(request, 455 /*numResultsWait*/ 0); 456 validateResultMandatoryConditions(result, croppedRawUseCase, 457 preCorrectionActiveArrayRect); 458 } 459 if (captureCallback.hasMoreFailures()) { 460 mCollector.addMessage("No capture failures expected, but there was a failure"); 461 } 462 463 } catch (Throwable e) { 464 mCollector.addMessage( 465 String.format("Closing down for combination: %s failed due to: %s", 466 combination.getDescription(), e.getMessage())); 467 } 468 469 if (haveSession) { 470 try { 471 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 472 cameraId, combination.getDescription())); 473 stopCapture(/*fast*/false); 474 } catch (Throwable e) { 475 mCollector.addMessage( 476 String.format("Closing down for combination: %s failed due to: %s", 477 combination.getDescription(), e.getMessage())); 478 } 479 } 480 481 targets.close(); 482 } 483 validateResultMandatoryConditions(TotalCaptureResult result, boolean croppedRawUseCase, Rect preCorrectionActiveArrayRect)484 private void validateResultMandatoryConditions(TotalCaptureResult result, 485 boolean croppedRawUseCase, Rect preCorrectionActiveArrayRect) { 486 // validate more conditions here 487 if (croppedRawUseCase) { 488 Rect rawCropRegion = result.get(CaptureResult.SCALER_RAW_CROP_REGION); 489 if (rawCropRegion == null) { 490 mCollector.addMessage("SCALER_RAW_CROP_REGION should not be null " + 491 "when CROPPED_RAW stream use case is used."); 492 } 493 if (!(preCorrectionActiveArrayRect.width() >= rawCropRegion.width() 494 && preCorrectionActiveArrayRect.height() >= rawCropRegion.height())) { 495 mCollector.addMessage("RAW_CROP_REGION dimensions should be <= pre correction" 496 + " array dimensions. SCALER_RAW_CROP_REGION : " 497 + rawCropRegion.flattenToString() + " pre correction active array is " 498 + preCorrectionActiveArrayRect.flattenToString()); 499 } 500 } 501 } 502 testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, String physicalCameraId, MandatoryStreamCombination combination)503 private void testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, 504 String physicalCameraId, MandatoryStreamCombination combination) throws Exception { 505 // Check whether substituting YUV_888 format with Y8 format 506 boolean substituteY8 = false; 507 if (staticInfo.isMonochromeWithY8()) { 508 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 509 for (MandatoryStreamInformation streamInfo : streamsInfo) { 510 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) { 511 substituteY8 = true; 512 break; 513 } 514 } 515 } 516 517 // Check whether substituting JPEG format with HEIC format 518 boolean substituteHeic = false; 519 if (staticInfo.isHeicSupported()) { 520 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 521 for (MandatoryStreamInformation streamInfo : streamsInfo) { 522 if (streamInfo.getFormat() == ImageFormat.JPEG) { 523 substituteHeic = true; 524 break; 525 } 526 } 527 } 528 529 // Test camera output combination 530 String log = "Testing mandatory stream combination: " + combination.getDescription() + 531 " on camera: " + cameraId; 532 if (physicalCameraId != null) { 533 log += ", physical sub-camera: " + physicalCameraId; 534 } 535 Log.i(TAG, log); 536 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 537 /*substituteY8*/false, /*substituteHeic*/false, /*maxResolution*/false); 538 539 if (substituteY8) { 540 Log.i(TAG, log + " with Y8"); 541 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 542 /*substituteY8*/true, /*substituteHeic*/false, /*maxResolution*/false); 543 } 544 545 if (substituteHeic) { 546 Log.i(TAG, log + " with HEIC"); 547 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 548 /*substituteY8*/false, /*substituteHeic*/true, /**maxResolution*/ false); 549 } 550 } 551 testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, String physicalCameraId, MandatoryStreamCombination combination, boolean substituteY8, boolean substituteHeic, boolean ultraHighResolution)552 private void testMandatoryStreamCombination(String cameraId, 553 StaticMetadata staticInfo, String physicalCameraId, 554 MandatoryStreamCombination combination, 555 boolean substituteY8, boolean substituteHeic, boolean ultraHighResolution) 556 throws Exception { 557 // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS 558 // TODO: This needs to be adjusted based on feedback 559 final int TIMEOUT_MULTIPLIER = ultraHighResolution ? 2 : 1; 560 final int TIMEOUT_FOR_RESULT_MS = 561 ((staticInfo.isHardwareLevelLegacy()) ? 2000 : 1000) * TIMEOUT_MULTIPLIER; 562 final int MIN_RESULT_COUNT = 3; 563 564 // Set up outputs 565 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 566 List<Surface> outputSurfaces = new ArrayList<Surface>(); 567 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 568 StreamCombinationTargets targets = new StreamCombinationTargets(); 569 570 CameraTestUtils.setupConfigurationTargets(combination.getStreamsInformation(), 571 targets, outputConfigs, outputSurfaces, uhOutputSurfaces, MIN_RESULT_COUNT, 572 substituteY8, substituteHeic, physicalCameraId, /*multiResStreamConfig*/null, 573 mHandler); 574 575 boolean haveSession = false; 576 try { 577 CaptureRequest.Builder requestBuilder = 578 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 579 CaptureRequest.Builder uhRequestBuilder = 580 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 581 582 for (Surface s : outputSurfaces) { 583 requestBuilder.addTarget(s); 584 } 585 586 for (Surface s : uhOutputSurfaces) { 587 uhRequestBuilder.addTarget(s); 588 } 589 // We need to explicitly set the sensor pixel mode to default since we're mixing default 590 // and max resolution requests in the same capture session. 591 requestBuilder.set(CaptureRequest.SENSOR_PIXEL_MODE, 592 CameraMetadata.SENSOR_PIXEL_MODE_DEFAULT); 593 if (ultraHighResolution) { 594 uhRequestBuilder.set(CaptureRequest.SENSOR_PIXEL_MODE, 595 CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION); 596 } 597 CameraCaptureSession.CaptureCallback mockCaptureCallback = 598 mock(CameraCaptureSession.CaptureCallback.class); 599 600 if (physicalCameraId == null) { 601 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 602 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 603 mCameraManager, true/*defaultSupport*/, String.format( 604 "Session configuration query from combination: %s failed", 605 combination.getDescription())); 606 } else { 607 SessionConfigSupport sessionConfigSupport = isSessionConfigSupported( 608 mCamera, mHandler, outputConfigs, /*inputConfig*/ null, 609 SessionConfiguration.SESSION_REGULAR, mCameraManager, 610 false/*defaultSupport*/); 611 assertTrue( 612 String.format("Session configuration query from combination: %s failed", 613 combination.getDescription()), !sessionConfigSupport.error); 614 if (!sessionConfigSupport.callSupported) { 615 return; 616 } 617 assertTrue( 618 String.format("Session configuration must be supported for combination: " + 619 "%s", combination.getDescription()), sessionConfigSupport.configSupported); 620 } 621 622 createSessionByConfigs(outputConfigs); 623 haveSession = true; 624 CaptureRequest request = requestBuilder.build(); 625 CaptureRequest uhRequest = uhRequestBuilder.build(); 626 mCameraSession.setRepeatingRequest(request, mockCaptureCallback, mHandler); 627 if (ultraHighResolution) { 628 mCameraSession.capture(uhRequest, mockCaptureCallback, mHandler); 629 } 630 verify(mockCaptureCallback, 631 timeout(TIMEOUT_FOR_RESULT_MS * MIN_RESULT_COUNT).atLeast(MIN_RESULT_COUNT)) 632 .onCaptureCompleted( 633 eq(mCameraSession), 634 eq(request), 635 isA(TotalCaptureResult.class)); 636 if (ultraHighResolution) { 637 verify(mockCaptureCallback, 638 timeout(TIMEOUT_FOR_RESULT_MS).atLeast(1)) 639 .onCaptureCompleted( 640 eq(mCameraSession), 641 eq(uhRequest), 642 isA(TotalCaptureResult.class)); 643 } 644 645 verify(mockCaptureCallback, never()). 646 onCaptureFailed( 647 eq(mCameraSession), 648 eq(request), 649 isA(CaptureFailure.class)); 650 651 } catch (Throwable e) { 652 mCollector.addMessage(String.format("Mandatory stream combination: %s failed due: %s", 653 combination.getDescription(), e.getMessage())); 654 } 655 if (haveSession) { 656 try { 657 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 658 cameraId, combination.getDescription())); 659 stopCapture(/*fast*/false); 660 } catch (Throwable e) { 661 mCollector.addMessage( 662 String.format("Closing down for combination: %s failed due to: %s", 663 combination.getDescription(), e.getMessage())); 664 } 665 } 666 667 targets.close(); 668 } 669 670 /** 671 * Test for making sure the required 10-bit stream combinations work as expected. 672 * Since we have too many possible combinations between different 8-bit vs. 10-bit as well 673 * as 10-bit dynamic profiles and in order to maximize the coverage within some reasonable 674 * amount of iterations, the test case will configure 8-bit and 10-bit outputs randomly. In case 675 * we have 10-bit output, then the dynamic range profile will also be randomly picked. 676 */ 677 @Test testMandatory10BitStreamCombinations()678 public void testMandatory10BitStreamCombinations() throws Exception { 679 for (String id : getCameraIdsUnderTest()) { 680 openDevice(id); 681 CameraCharacteristics chars = mStaticInfo.getCharacteristics(); 682 if (!CameraTestUtils.hasCapability( 683 chars, CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) { 684 Log.i(TAG, "Camera id " + id + " doesn't support 10-bit output, skip test"); 685 closeDevice(id); 686 continue; 687 } 688 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 689 CameraCharacteristics.SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS; 690 691 MandatoryStreamCombination[] combinations = chars.get(ck); 692 assertNotNull(combinations); 693 694 try { 695 for (MandatoryStreamCombination combination : combinations) { 696 Log.i(TAG, "Testing fixed mandatory 10-bit output stream combination: " + 697 combination.getDescription() + " on camera: " + id); 698 DynamicRangeProfiles profiles = mStaticInfo.getCharacteristics().get( 699 CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES); 700 assertNotNull(profiles); 701 702 // First we want to make sure that a fixed set of 10-bit streams 703 // is functional 704 for (Long profile : profiles.getSupportedProfiles()) { 705 if (profile != DynamicRangeProfiles.STANDARD) { 706 ArrayList<Long> testProfiles = new ArrayList<Long>(); 707 testProfiles.add(profile); 708 testMandatory10BitStreamCombination(id, combination, profiles, 709 testProfiles); 710 } 711 } 712 713 Log.i(TAG, "Testing random mandatory 10-bit output stream combination: " + 714 combination.getDescription() + " on camera: " + id); 715 // Next try out a random mix of standard 8-bit and 10-bit profiles. 716 // The number of possible combinations is quite big and testing them 717 // all on physical hardware can become unfeasible. 718 ArrayList<Long> testProfiles = new ArrayList<>( 719 profiles.getSupportedProfiles()); 720 testMandatory10BitStreamCombination(id, combination, profiles, testProfiles); 721 } 722 } finally { 723 closeDevice(id); 724 } 725 } 726 } 727 testMandatory10BitStreamCombination(String cameraId, MandatoryStreamCombination combination, DynamicRangeProfiles profiles, List<Long> testProfiles)728 private void testMandatory10BitStreamCombination(String cameraId, 729 MandatoryStreamCombination combination, DynamicRangeProfiles profiles, 730 List<Long> testProfiles) { 731 final int TIMEOUT_FOR_RESULT_MS = 1000; 732 final int MIN_RESULT_COUNT = 3; 733 734 // Setup outputs 735 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 736 List<Surface> outputSurfaces = new ArrayList<Surface>(); 737 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 738 StreamCombinationTargets targets = new StreamCombinationTargets(); 739 740 CameraTestUtils.setupConfigurationTargets(combination.getStreamsInformation(), 741 targets, outputConfigs, outputSurfaces, uhOutputSurfaces, MIN_RESULT_COUNT, 742 /*substituteY8*/ false, /*substituteHeic*/false, 743 /*physicalCameraId*/ null, 744 /*multiResStreamConfig*/null, mHandler, 745 testProfiles); 746 747 try { 748 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 749 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 750 mCameraManager, true/*defaultSupport*/, 751 String.format("Session configuration query from combination: %s failed", 752 combination.getDescription())); 753 754 createSessionByConfigs(outputConfigs); 755 756 boolean constraintPresent = false; 757 List<Surface> constrainedOutputs = new ArrayList<>(outputSurfaces); 758 759 while (!outputSurfaces.isEmpty()) { 760 CaptureRequest.Builder requestBuilder = 761 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 762 // Check to see how many outputs can be combined in to a single request including 763 // the first output surface and respecting the advertised constraints 764 Iterator<OutputConfiguration> it = outputConfigs.iterator(); 765 OutputConfiguration config = it.next(); 766 HashSet<Long> currentProfiles = new HashSet<>(); 767 currentProfiles.add(config.getDynamicRangeProfile()); 768 requestBuilder.addTarget(config.getSurface()); 769 outputSurfaces.remove(config.getSurface()); 770 it.remove(); 771 while (it.hasNext()) { 772 config = it.next(); 773 Long currentProfile = config.getDynamicRangeProfile(); 774 Set<Long> newLimitations = profiles.getProfileCaptureRequestConstraints( 775 currentProfile); 776 if (newLimitations.isEmpty() || (newLimitations.containsAll(currentProfiles))) { 777 currentProfiles.add(currentProfile); 778 requestBuilder.addTarget(config.getSurface()); 779 outputSurfaces.remove(config.getSurface()); 780 it.remove(); 781 } else if (!constraintPresent && !newLimitations.isEmpty() && 782 !newLimitations.containsAll(currentProfiles)) { 783 constraintPresent = true; 784 } 785 } 786 787 CaptureRequest request = requestBuilder.build(); 788 CameraCaptureSession.CaptureCallback mockCaptureCallback = 789 mock(CameraCaptureSession.CaptureCallback.class); 790 mCameraSession.capture(request, mockCaptureCallback, mHandler); 791 verify(mockCaptureCallback, 792 timeout(TIMEOUT_FOR_RESULT_MS).atLeastOnce()) 793 .onCaptureCompleted( 794 eq(mCameraSession), 795 eq(request), 796 isA(TotalCaptureResult.class)); 797 798 verify(mockCaptureCallback, never()). 799 onCaptureFailed( 800 eq(mCameraSession), 801 eq(request), 802 isA(CaptureFailure.class)); 803 } 804 805 if (constraintPresent) { 806 // Capture requests that include output surfaces with dynamic range profiles that 807 // cannot be combined must throw a corresponding exception 808 CaptureRequest.Builder requestBuilder = 809 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 810 for (Surface s : constrainedOutputs) { 811 requestBuilder.addTarget(s); 812 } 813 814 CaptureRequest request = requestBuilder.build(); 815 CameraCaptureSession.CaptureCallback mockCaptureCallback = 816 mock(CameraCaptureSession.CaptureCallback.class); 817 try { 818 mCameraSession.capture(request, mockCaptureCallback, mHandler); 819 fail("Capture request to outputs with incompatible dynamic range profiles " 820 + "must always fail!"); 821 } catch (IllegalArgumentException e) { 822 // Expected 823 } 824 } 825 826 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 827 cameraId, combination.getDescription())); 828 } catch (Throwable e) { 829 mCollector.addMessage( 830 String.format("Closing down for combination: %s failed due to: %s", 831 combination.getDescription(), e.getMessage())); 832 } 833 834 targets.close(); 835 } 836 837 /** 838 * Test for making sure the required reprocess input/output combinations for each hardware 839 * level and capability work as expected. 840 */ 841 @Test testMandatoryReprocessConfigurations()842 public void testMandatoryReprocessConfigurations() throws Exception { 843 testMandatoryReprocessConfigurations(/*maxResolution*/false); 844 } 845 846 /** 847 * Test for making sure the required reprocess input/output combinations for each hardware 848 * level and capability work as expected. 849 */ 850 @Test testMandatoryMaximumResolutionReprocessConfigurations()851 public void testMandatoryMaximumResolutionReprocessConfigurations() throws Exception { 852 testMandatoryReprocessConfigurations(/*maxResolution*/true); 853 } 854 855 /** 856 * Test for making sure the required reprocess input/output combinations for each hardware 857 * level and capability work as expected. 858 */ testMandatoryReprocessConfigurations(boolean maxResolution)859 public void testMandatoryReprocessConfigurations(boolean maxResolution) throws Exception { 860 for (String id : getCameraIdsUnderTest()) { 861 openDevice(id); 862 CameraCharacteristics chars = mStaticInfo.getCharacteristics(); 863 if (maxResolution && !CameraTestUtils.hasCapability( 864 chars, CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING)) { 865 Log.i(TAG, "Camera id " + id + "doesn't support REMOSAIC_REPROCESSING, skip test"); 866 closeDevice(id); 867 continue; 868 } 869 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 870 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS; 871 872 if (maxResolution) { 873 ck = CameraCharacteristics.SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS; 874 } 875 876 MandatoryStreamCombination[] combinations = chars.get(ck); 877 if (combinations == null) { 878 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 879 closeDevice(id); 880 continue; 881 } 882 883 try { 884 for (MandatoryStreamCombination combination : combinations) { 885 if (combination.isReprocessable()) { 886 Log.i(TAG, "Testing mandatory reprocessable stream combination: " + 887 combination.getDescription() + " on camera: " + id); 888 testMandatoryReprocessableStreamCombination(id, combination, maxResolution); 889 } 890 } 891 } finally { 892 closeDevice(id); 893 } 894 } 895 } 896 testMandatoryReprocessableStreamCombination(String cameraId, MandatoryStreamCombination combination, boolean maxResolution)897 private void testMandatoryReprocessableStreamCombination(String cameraId, 898 MandatoryStreamCombination combination, boolean maxResolution) throws Exception { 899 // Test reprocess stream combination 900 testMandatoryReprocessableStreamCombination(cameraId, combination, 901 /*substituteY8*/false, /*substituteHeic*/false, maxResolution/*maxResolution*/); 902 if (maxResolution) { 903 // Maximum resolution mode doesn't guarantee HEIC and Y8 streams. 904 return; 905 } 906 907 // Test substituting YUV_888 format with Y8 format in reprocess stream combination. 908 if (mStaticInfo.isMonochromeWithY8()) { 909 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 910 boolean substituteY8 = false; 911 for (MandatoryStreamInformation streamInfo : streamsInfo) { 912 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) { 913 substituteY8 = true; 914 } 915 } 916 if (substituteY8) { 917 testMandatoryReprocessableStreamCombination(cameraId, combination, 918 /*substituteY8*/true, /*substituteHeic*/false, false/*maxResolution*/); 919 } 920 } 921 922 if (mStaticInfo.isHeicSupported()) { 923 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 924 boolean substituteHeic = false; 925 for (MandatoryStreamInformation streamInfo : streamsInfo) { 926 if (streamInfo.getFormat() == ImageFormat.JPEG) { 927 substituteHeic = true; 928 } 929 } 930 if (substituteHeic) { 931 testMandatoryReprocessableStreamCombination(cameraId, combination, 932 /*substituteY8*/false, /*substituteHeic*/true, false/*maxResolution*/); 933 } 934 } 935 } 936 testMandatoryReprocessableStreamCombination(String cameraId, MandatoryStreamCombination combination, boolean substituteY8, boolean substituteHeic, boolean maxResolution)937 private void testMandatoryReprocessableStreamCombination(String cameraId, 938 MandatoryStreamCombination combination, boolean substituteY8, 939 boolean substituteHeic, boolean maxResolution) throws Exception { 940 941 final int TIMEOUT_MULTIPLIER = maxResolution ? 2 : 1; 942 final int TIMEOUT_FOR_RESULT_MS = 5000 * TIMEOUT_MULTIPLIER; 943 final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3; 944 945 StreamCombinationTargets targets = new StreamCombinationTargets(); 946 ArrayList<Surface> defaultOutputSurfaces = new ArrayList<>(); 947 ArrayList<Surface> allOutputSurfaces = new ArrayList<>(); 948 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 949 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 950 ImageReader inputReader = null; 951 ImageWriter inputWriter = null; 952 SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener(); 953 SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback(); 954 SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback(); 955 956 List<MandatoryStreamInformation> streamInfo = combination.getStreamsInformation(); 957 assertTrue("Reprocessable stream combinations should have at least 3 or more streams", 958 (streamInfo != null) && (streamInfo.size() >= 3)); 959 960 assertTrue("The first mandatory stream information in a reprocessable combination must " + 961 "always be input", streamInfo.get(0).isInput()); 962 963 List<Size> inputSizes = streamInfo.get(0).getAvailableSizes(); 964 int inputFormat = streamInfo.get(0).getFormat(); 965 if (substituteY8 && (inputFormat == ImageFormat.YUV_420_888)) { 966 inputFormat = ImageFormat.Y8; 967 } 968 969 Log.i(TAG, "testMandatoryReprocessableStreamCombination: " + 970 combination.getDescription() + ", substituteY8 = " + substituteY8 + 971 ", substituteHeic = " + substituteHeic); 972 try { 973 // The second stream information entry is the ZSL stream, which is configured 974 // separately. 975 List<MandatoryStreamInformation> mandatoryStreamInfos = null; 976 mandatoryStreamInfos = new ArrayList<MandatoryStreamInformation>(); 977 mandatoryStreamInfos = streamInfo.subList(2, streamInfo.size()); 978 CameraTestUtils.setupConfigurationTargets(mandatoryStreamInfos, targets, 979 outputConfigs, defaultOutputSurfaces, uhOutputSurfaces, 980 NUM_REPROCESS_CAPTURES_PER_CONFIG, 981 substituteY8, substituteHeic, null/*overridePhysicalCameraId*/, 982 /*multiResStreamConfig*/null, mHandler); 983 allOutputSurfaces.addAll(defaultOutputSurfaces); 984 allOutputSurfaces.addAll(uhOutputSurfaces); 985 InputConfiguration inputConfig = new InputConfiguration(inputSizes.get(0).getWidth(), 986 inputSizes.get(0).getHeight(), inputFormat); 987 988 // For each config, YUV and JPEG outputs will be tested. (For YUV/Y8 reprocessing, 989 // the YUV/Y8 ImageReader for input is also used for output.) 990 final boolean inputIsYuv = inputConfig.getFormat() == ImageFormat.YUV_420_888; 991 final boolean inputIsY8 = inputConfig.getFormat() == ImageFormat.Y8; 992 final boolean useYuv = inputIsYuv || targets.mYuvTargets.size() > 0; 993 final boolean useY8 = inputIsY8 || targets.mY8Targets.size() > 0; 994 final int totalNumReprocessCaptures = NUM_REPROCESS_CAPTURES_PER_CONFIG * 995 (maxResolution ? 1 : (((inputIsYuv || inputIsY8) ? 1 : 0) + 996 (substituteHeic ? targets.mHeicTargets.size() : targets.mJpegTargets.size()) + 997 (useYuv ? targets.mYuvTargets.size() : targets.mY8Targets.size()))); 998 999 // It needs 1 input buffer for each reprocess capture + the number of buffers 1000 // that will be used as outputs. 1001 inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(), 1002 inputConfig.getFormat(), 1003 totalNumReprocessCaptures + NUM_REPROCESS_CAPTURES_PER_CONFIG); 1004 inputReader.setOnImageAvailableListener(inputReaderListener, mHandler); 1005 allOutputSurfaces.add(inputReader.getSurface()); 1006 1007 checkSessionConfigurationWithSurfaces(mCamera, mHandler, allOutputSurfaces, 1008 inputConfig, SessionConfiguration.SESSION_REGULAR, mCameraManager, 1009 /*defaultSupport*/ true, String.format("Session configuration query %s failed", 1010 combination.getDescription())); 1011 1012 // Verify we can create a reprocessable session with the input and all outputs. 1013 BlockingSessionCallback sessionListener = new BlockingSessionCallback(); 1014 CameraCaptureSession session = configureReprocessableCameraSession(mCamera, 1015 inputConfig, allOutputSurfaces, sessionListener, mHandler); 1016 inputWriter = ImageWriter.newInstance(session.getInputSurface(), 1017 totalNumReprocessCaptures); 1018 1019 // Prepare a request for reprocess input 1020 CaptureRequest.Builder builder = mCamera.createCaptureRequest( 1021 CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 1022 builder.addTarget(inputReader.getSurface()); 1023 if (maxResolution) { 1024 builder.set(CaptureRequest.SENSOR_PIXEL_MODE, 1025 CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION); 1026 } 1027 1028 for (int i = 0; i < totalNumReprocessCaptures; i++) { 1029 session.capture(builder.build(), inputCaptureListener, mHandler); 1030 } 1031 1032 List<CaptureRequest> reprocessRequests = new ArrayList<>(); 1033 List<Surface> reprocessOutputs = new ArrayList<>(); 1034 1035 if (maxResolution) { 1036 if (uhOutputSurfaces.size() == 0) { // RAW -> RAW reprocessing 1037 reprocessOutputs.add(inputReader.getSurface()); 1038 } else { 1039 for (Surface surface : uhOutputSurfaces) { 1040 reprocessOutputs.add(surface); 1041 } 1042 } 1043 } else { 1044 if (inputIsYuv || inputIsY8) { 1045 reprocessOutputs.add(inputReader.getSurface()); 1046 } 1047 1048 for (ImageReader reader : targets.mJpegTargets) { 1049 reprocessOutputs.add(reader.getSurface()); 1050 } 1051 1052 for (ImageReader reader : targets.mHeicTargets) { 1053 reprocessOutputs.add(reader.getSurface()); 1054 } 1055 1056 for (ImageReader reader : targets.mYuvTargets) { 1057 reprocessOutputs.add(reader.getSurface()); 1058 } 1059 1060 for (ImageReader reader : targets.mY8Targets) { 1061 reprocessOutputs.add(reader.getSurface()); 1062 } 1063 } 1064 1065 for (int i = 0; i < NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) { 1066 for (Surface output : reprocessOutputs) { 1067 TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult( 1068 TIMEOUT_FOR_RESULT_MS); 1069 builder = mCamera.createReprocessCaptureRequest(result); 1070 inputWriter.queueInputImage( 1071 inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS)); 1072 builder.addTarget(output); 1073 reprocessRequests.add(builder.build()); 1074 } 1075 } 1076 1077 session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler); 1078 1079 for (int i = 0; i < reprocessOutputs.size() * NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) { 1080 TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult( 1081 TIMEOUT_FOR_RESULT_MS); 1082 } 1083 } catch (Throwable e) { 1084 mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s", 1085 combination.getDescription(), e.getMessage())); 1086 } finally { 1087 inputReaderListener.drain(); 1088 reprocessOutputCaptureListener.drain(); 1089 targets.close(); 1090 1091 if (inputReader != null) { 1092 inputReader.close(); 1093 } 1094 1095 if (inputWriter != null) { 1096 inputWriter.close(); 1097 } 1098 } 1099 } 1100 1101 @Test testBasicTriggerSequence()1102 public void testBasicTriggerSequence() throws Exception { 1103 1104 for (String id : getCameraIdsUnderTest()) { 1105 Log.i(TAG, String.format("Testing Camera %s", id)); 1106 1107 try { 1108 // Legacy devices do not support precapture trigger; don't test devices that 1109 // can't focus 1110 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1111 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1112 continue; 1113 } 1114 // Depth-only devices won't support AE 1115 if (!staticInfo.isColorOutputSupported()) { 1116 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1117 continue; 1118 } 1119 1120 openDevice(id); 1121 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1122 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1123 1124 for (int afMode : availableAfModes) { 1125 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1126 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1127 // Only test AF modes that have meaningful trigger behavior 1128 continue; 1129 } 1130 1131 for (int aeMode : availableAeModes) { 1132 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1133 // Only test AE modes that have meaningful trigger behavior 1134 continue; 1135 } 1136 1137 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1138 1139 CaptureRequest.Builder previewRequest = 1140 prepareTriggerTestSession(preview, aeMode, afMode); 1141 1142 SimpleCaptureCallback captureListener = 1143 new CameraTestUtils.SimpleCaptureCallback(); 1144 1145 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1146 mHandler); 1147 1148 // Cancel triggers 1149 1150 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1151 1152 // 1153 // Standard sequence - AF trigger then AE trigger 1154 1155 if (VERBOSE) { 1156 Log.v(TAG, String.format("Triggering AF")); 1157 } 1158 1159 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1160 CaptureRequest.CONTROL_AF_TRIGGER_START); 1161 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1162 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1163 1164 CaptureRequest triggerRequest = previewRequest.build(); 1165 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1166 1167 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1168 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1169 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1170 boolean focusComplete = false; 1171 1172 for (int i = 0; 1173 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete; 1174 i++) { 1175 1176 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1177 1178 CaptureResult focusResult = captureListener.getCaptureResult( 1179 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1180 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE); 1181 } 1182 1183 assertTrue("Focusing never completed!", focusComplete); 1184 1185 // Standard sequence - Part 2 AE trigger 1186 1187 if (VERBOSE) { 1188 Log.v(TAG, String.format("Triggering AE")); 1189 } 1190 1191 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1192 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1193 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1194 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1195 1196 triggerRequest = previewRequest.build(); 1197 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1198 1199 triggerResult = captureListener.getCaptureResultForRequest( 1200 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1201 1202 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1203 1204 boolean precaptureComplete = false; 1205 1206 for (int i = 0; 1207 i < MAX_TRIGGER_SEQUENCE_FRAMES && !precaptureComplete; 1208 i++) { 1209 1210 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1211 1212 CaptureResult precaptureResult = captureListener.getCaptureResult( 1213 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1214 aeState = precaptureResult.get(CaptureResult.CONTROL_AE_STATE); 1215 } 1216 1217 assertTrue("Precapture sequence never completed!", precaptureComplete); 1218 1219 for (int i = 0; i < MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES; i++) { 1220 CaptureResult postPrecaptureResult = captureListener.getCaptureResult( 1221 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1222 aeState = postPrecaptureResult.get(CaptureResult.CONTROL_AE_STATE); 1223 assertTrue("Late transition to PRECAPTURE state seen", 1224 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 1225 } 1226 1227 // Done 1228 1229 stopCapture(/*fast*/ false); 1230 preview.release(); 1231 } 1232 1233 } 1234 1235 } finally { 1236 closeDevice(id); 1237 } 1238 } 1239 1240 } 1241 1242 @Test testSimultaneousTriggers()1243 public void testSimultaneousTriggers() throws Exception { 1244 for (String id : getCameraIdsUnderTest()) { 1245 Log.i(TAG, String.format("Testing Camera %s", id)); 1246 1247 try { 1248 // Legacy devices do not support precapture trigger; don't test devices that 1249 // can't focus 1250 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1251 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1252 continue; 1253 } 1254 // Depth-only devices won't support AE 1255 if (!staticInfo.isColorOutputSupported()) { 1256 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1257 continue; 1258 } 1259 1260 openDevice(id); 1261 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1262 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1263 1264 for (int afMode : availableAfModes) { 1265 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1266 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1267 // Only test AF modes that have meaningful trigger behavior 1268 continue; 1269 } 1270 1271 for (int aeMode : availableAeModes) { 1272 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1273 // Only test AE modes that have meaningful trigger behavior 1274 continue; 1275 } 1276 1277 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1278 1279 CaptureRequest.Builder previewRequest = 1280 prepareTriggerTestSession(preview, aeMode, afMode); 1281 1282 SimpleCaptureCallback captureListener = 1283 new CameraTestUtils.SimpleCaptureCallback(); 1284 1285 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1286 mHandler); 1287 1288 // Cancel triggers 1289 1290 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1291 1292 // 1293 // Trigger AF and AE together 1294 1295 if (VERBOSE) { 1296 Log.v(TAG, String.format("Triggering AF and AE together")); 1297 } 1298 1299 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1300 CaptureRequest.CONTROL_AF_TRIGGER_START); 1301 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1302 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1303 1304 CaptureRequest triggerRequest = previewRequest.build(); 1305 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1306 1307 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1308 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1309 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1310 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1311 1312 boolean precaptureComplete = false; 1313 boolean focusComplete = false; 1314 1315 for (int i = 0; 1316 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1317 !(focusComplete && precaptureComplete); 1318 i++) { 1319 1320 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1321 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1322 1323 CaptureResult sequenceResult = captureListener.getCaptureResult( 1324 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1325 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1326 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1327 } 1328 1329 assertTrue("Precapture sequence never completed!", precaptureComplete); 1330 assertTrue("Focus sequence never completed!", focusComplete); 1331 1332 // Done 1333 1334 stopCapture(/*fast*/ false); 1335 preview.release(); 1336 1337 } 1338 } 1339 } finally { 1340 closeDevice(id); 1341 } 1342 } 1343 } 1344 1345 @Test testAfThenAeTrigger()1346 public void testAfThenAeTrigger() throws Exception { 1347 for (String id : getCameraIdsUnderTest()) { 1348 Log.i(TAG, String.format("Testing Camera %s", id)); 1349 1350 try { 1351 // Legacy devices do not support precapture trigger; don't test devices that 1352 // can't focus 1353 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1354 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1355 continue; 1356 } 1357 // Depth-only devices won't support AE 1358 if (!staticInfo.isColorOutputSupported()) { 1359 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1360 continue; 1361 } 1362 1363 openDevice(id); 1364 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1365 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1366 1367 for (int afMode : availableAfModes) { 1368 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1369 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1370 // Only test AF modes that have meaningful trigger behavior 1371 continue; 1372 } 1373 1374 for (int aeMode : availableAeModes) { 1375 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1376 // Only test AE modes that have meaningful trigger behavior 1377 continue; 1378 } 1379 1380 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1381 1382 CaptureRequest.Builder previewRequest = 1383 prepareTriggerTestSession(preview, aeMode, afMode); 1384 1385 SimpleCaptureCallback captureListener = 1386 new CameraTestUtils.SimpleCaptureCallback(); 1387 1388 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1389 mHandler); 1390 1391 // Cancel triggers 1392 1393 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1394 1395 // 1396 // AF with AE a request later 1397 1398 if (VERBOSE) { 1399 Log.v(TAG, "Trigger AF, then AE trigger on next request"); 1400 } 1401 1402 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1403 CaptureRequest.CONTROL_AF_TRIGGER_START); 1404 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1405 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1406 1407 CaptureRequest triggerRequest = previewRequest.build(); 1408 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1409 1410 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1411 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1412 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1413 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1414 1415 CaptureRequest triggerRequest2 = previewRequest.build(); 1416 mCameraSession.capture(triggerRequest2, captureListener, mHandler); 1417 1418 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1419 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1420 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1421 1422 boolean precaptureComplete = false; 1423 boolean focusComplete = false; 1424 1425 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1426 1427 triggerResult = captureListener.getCaptureResultForRequest( 1428 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1429 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1430 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1431 1432 for (int i = 0; 1433 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1434 !(focusComplete && precaptureComplete); 1435 i++) { 1436 1437 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1438 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1439 1440 CaptureResult sequenceResult = captureListener.getCaptureResult( 1441 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1442 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1443 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1444 } 1445 1446 assertTrue("Precapture sequence never completed!", precaptureComplete); 1447 assertTrue("Focus sequence never completed!", focusComplete); 1448 1449 // Done 1450 1451 stopCapture(/*fast*/ false); 1452 preview.release(); 1453 1454 } 1455 } 1456 } finally { 1457 closeDevice(id); 1458 } 1459 } 1460 } 1461 1462 @Test testAeThenAfTrigger()1463 public void testAeThenAfTrigger() throws Exception { 1464 for (String id : getCameraIdsUnderTest()) { 1465 Log.i(TAG, String.format("Testing Camera %s", id)); 1466 1467 try { 1468 // Legacy devices do not support precapture trigger; don't test devices that 1469 // can't focus 1470 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1471 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1472 continue; 1473 } 1474 // Depth-only devices won't support AE 1475 if (!staticInfo.isColorOutputSupported()) { 1476 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1477 continue; 1478 } 1479 1480 openDevice(id); 1481 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1482 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1483 1484 for (int afMode : availableAfModes) { 1485 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1486 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1487 // Only test AF modes that have meaningful trigger behavior 1488 continue; 1489 } 1490 1491 for (int aeMode : availableAeModes) { 1492 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1493 // Only test AE modes that have meaningful trigger behavior 1494 continue; 1495 } 1496 1497 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1498 1499 CaptureRequest.Builder previewRequest = 1500 prepareTriggerTestSession(preview, aeMode, afMode); 1501 1502 SimpleCaptureCallback captureListener = 1503 new CameraTestUtils.SimpleCaptureCallback(); 1504 1505 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1506 mHandler); 1507 1508 // Cancel triggers 1509 1510 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1511 1512 // 1513 // AE with AF a request later 1514 1515 if (VERBOSE) { 1516 Log.v(TAG, "Trigger AE, then AF trigger on next request"); 1517 } 1518 1519 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1520 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1521 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1522 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1523 1524 CaptureRequest triggerRequest = previewRequest.build(); 1525 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1526 1527 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1528 CaptureRequest.CONTROL_AF_TRIGGER_START); 1529 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1530 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1531 1532 CaptureRequest triggerRequest2 = previewRequest.build(); 1533 mCameraSession.capture(triggerRequest2, captureListener, mHandler); 1534 1535 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1536 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1537 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1538 1539 boolean precaptureComplete = false; 1540 boolean focusComplete = false; 1541 1542 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1543 1544 triggerResult = captureListener.getCaptureResultForRequest( 1545 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1546 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1547 aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1548 1549 for (int i = 0; 1550 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1551 !(focusComplete && precaptureComplete); 1552 i++) { 1553 1554 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1555 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1556 1557 CaptureResult sequenceResult = captureListener.getCaptureResult( 1558 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1559 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1560 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1561 } 1562 1563 assertTrue("Precapture sequence never completed!", precaptureComplete); 1564 assertTrue("Focus sequence never completed!", focusComplete); 1565 1566 // Done 1567 1568 stopCapture(/*fast*/ false); 1569 preview.release(); 1570 1571 } 1572 } 1573 } finally { 1574 closeDevice(id); 1575 } 1576 } 1577 } 1578 1579 @Test testAeAndAfCausality()1580 public void testAeAndAfCausality() throws Exception { 1581 1582 for (String id : getCameraIdsUnderTest()) { 1583 Log.i(TAG, String.format("Testing Camera %s", id)); 1584 1585 try { 1586 // Legacy devices do not support precapture trigger; don't test devices that 1587 // can't focus 1588 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1589 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1590 continue; 1591 } 1592 // Depth-only devices won't support AE 1593 if (!staticInfo.isColorOutputSupported()) { 1594 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1595 continue; 1596 } 1597 1598 openDevice(id); 1599 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1600 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1601 final int maxPipelineDepth = mStaticInfo.getCharacteristics().get( 1602 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH); 1603 1604 for (int afMode : availableAfModes) { 1605 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1606 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1607 // Only test AF modes that have meaningful trigger behavior 1608 continue; 1609 } 1610 for (int aeMode : availableAeModes) { 1611 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1612 // Only test AE modes that have meaningful trigger behavior 1613 continue; 1614 } 1615 1616 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1617 1618 CaptureRequest.Builder previewRequest = 1619 prepareTriggerTestSession(preview, aeMode, afMode); 1620 1621 SimpleCaptureCallback captureListener = 1622 new CameraTestUtils.SimpleCaptureCallback(); 1623 1624 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1625 mHandler); 1626 1627 List<CaptureRequest> triggerRequests = 1628 new ArrayList<CaptureRequest>(maxPipelineDepth+1); 1629 for (int i = 0; i < maxPipelineDepth; i++) { 1630 triggerRequests.add(previewRequest.build()); 1631 } 1632 1633 // Cancel triggers 1634 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1635 1636 // 1637 // Standard sequence - Part 1 AF trigger 1638 1639 if (VERBOSE) { 1640 Log.v(TAG, String.format("Triggering AF")); 1641 } 1642 1643 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1644 CaptureRequest.CONTROL_AF_TRIGGER_START); 1645 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1646 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1647 triggerRequests.add(previewRequest.build()); 1648 1649 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1650 1651 TotalCaptureResult[] triggerResults = 1652 captureListener.getTotalCaptureResultsForRequests( 1653 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1654 for (int i = 0; i < maxPipelineDepth; i++) { 1655 TotalCaptureResult triggerResult = triggerResults[i]; 1656 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1657 int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER); 1658 1659 verifyStartingAfState(afMode, afState); 1660 assertTrue(String.format("In AF mode %s, previous AF_TRIGGER must not " 1661 + "be START before TRIGGER_START", 1662 StaticMetadata.getAfModeName(afMode)), 1663 afTrigger != CaptureResult.CONTROL_AF_TRIGGER_START); 1664 } 1665 1666 int afState = 1667 triggerResults[maxPipelineDepth].get(CaptureResult.CONTROL_AF_STATE); 1668 boolean focusComplete = false; 1669 for (int i = 0; 1670 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete; 1671 i++) { 1672 1673 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1674 1675 CaptureResult focusResult = captureListener.getCaptureResult( 1676 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1677 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE); 1678 } 1679 1680 assertTrue("Focusing never completed!", focusComplete); 1681 1682 // Standard sequence - Part 2 AE trigger 1683 1684 if (VERBOSE) { 1685 Log.v(TAG, String.format("Triggering AE")); 1686 } 1687 // Remove AF trigger request 1688 triggerRequests.remove(maxPipelineDepth); 1689 1690 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1691 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1692 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1693 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1694 triggerRequests.add(previewRequest.build()); 1695 1696 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1697 1698 triggerResults = captureListener.getTotalCaptureResultsForRequests( 1699 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1700 1701 for (int i = 0; i < maxPipelineDepth; i++) { 1702 TotalCaptureResult triggerResult = triggerResults[i]; 1703 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1704 int aeTrigger = triggerResult.get( 1705 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER); 1706 1707 assertTrue(String.format("In AE mode %s, previous AE_TRIGGER must not " 1708 + "be START before TRIGGER_START", 1709 StaticMetadata.getAeModeName(aeMode)), 1710 aeTrigger != CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1711 assertTrue(String.format("In AE mode %s, previous AE_STATE must not be" 1712 + " PRECAPTURE_TRIGGER before TRIGGER_START", 1713 StaticMetadata.getAeModeName(aeMode)), 1714 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 1715 } 1716 1717 // Stand sequence - Part 3 Cancel AF trigger 1718 if (VERBOSE) { 1719 Log.v(TAG, String.format("Cancel AF trigger")); 1720 } 1721 // Remove AE trigger request 1722 triggerRequests.remove(maxPipelineDepth); 1723 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1724 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 1725 triggerRequests.add(previewRequest.build()); 1726 1727 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1728 triggerResults = captureListener.getTotalCaptureResultsForRequests( 1729 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1730 for (int i = 0; i < maxPipelineDepth; i++) { 1731 TotalCaptureResult triggerResult = triggerResults[i]; 1732 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1733 int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER); 1734 1735 assertTrue( 1736 String.format("In AF mode %s, previous AF_TRIGGER must not " + 1737 "be CANCEL before TRIGGER_CANCEL", 1738 StaticMetadata.getAfModeName(afMode)), 1739 afTrigger != CaptureResult.CONTROL_AF_TRIGGER_CANCEL); 1740 assertTrue( 1741 String.format("In AF mode %s, previous AF_STATE must be LOCKED" 1742 + " before CANCEL, but is %s", 1743 StaticMetadata.getAfModeName(afMode), 1744 StaticMetadata.AF_STATE_NAMES[afState]), 1745 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1746 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1747 } 1748 1749 stopCapture(/*fast*/ false); 1750 preview.release(); 1751 } 1752 1753 } 1754 1755 } finally { 1756 closeDevice(id); 1757 } 1758 } 1759 1760 } 1761 1762 @Test testAbandonRepeatingRequestSurface()1763 public void testAbandonRepeatingRequestSurface() throws Exception { 1764 for (String id : getCameraIdsUnderTest()) { 1765 Log.i(TAG, String.format( 1766 "Testing Camera %s for abandoning surface of a repeating request", id)); 1767 1768 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1769 if (!staticInfo.isColorOutputSupported()) { 1770 Log.i(TAG, "Camera " + id + " does not support color output, skipping"); 1771 continue; 1772 } 1773 1774 openDevice(id); 1775 1776 try { 1777 1778 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1779 Surface previewSurface = new Surface(preview); 1780 1781 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1782 SimpleCaptureCallback captureListener = new CameraTestUtils.SimpleCaptureCallback(); 1783 1784 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1785 captureListener, mHandler); 1786 1787 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) { 1788 captureListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1789 } 1790 1791 // Abandon preview surface. 1792 preview.release(); 1793 1794 // Check onCaptureSequenceCompleted is received. 1795 long sequenceLastFrameNumber = captureListener.getCaptureSequenceLastFrameNumber( 1796 sequenceId, CAPTURE_TIMEOUT); 1797 1798 mCameraSession.stopRepeating(); 1799 1800 // Find the last frame number received in results and failures. 1801 long lastFrameNumber = -1; 1802 while (captureListener.hasMoreResults()) { 1803 TotalCaptureResult result = captureListener.getTotalCaptureResult( 1804 CAPTURE_TIMEOUT); 1805 if (lastFrameNumber < result.getFrameNumber()) { 1806 lastFrameNumber = result.getFrameNumber(); 1807 } 1808 } 1809 1810 while (captureListener.hasMoreFailures()) { 1811 ArrayList<CaptureFailure> failures = captureListener.getCaptureFailures( 1812 /*maxNumFailures*/ 1); 1813 for (CaptureFailure failure : failures) { 1814 if (lastFrameNumber < failure.getFrameNumber()) { 1815 lastFrameNumber = failure.getFrameNumber(); 1816 } 1817 } 1818 } 1819 1820 // Verify the last frame number received from capture sequence completed matches the 1821 // the last frame number of the results and failures. 1822 assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " + 1823 "(%d) doesn't match the last frame number received from " + 1824 "results/failures (%d)", sequenceLastFrameNumber, lastFrameNumber), 1825 sequenceLastFrameNumber, lastFrameNumber); 1826 } finally { 1827 closeDevice(id); 1828 } 1829 } 1830 } 1831 1832 @Test testConfigureInvalidSensorPixelModes()1833 public void testConfigureInvalidSensorPixelModes() throws Exception { 1834 for (String id : getCameraIdsUnderTest()) { 1835 // Go through given, stream configuration map, add the incorrect sensor pixel mode 1836 // to an OutputConfiguration, make sure the session configuration fails. 1837 CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(id); 1838 StreamConfigurationMap defaultStreamConfigMap = 1839 chars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1840 StreamConfigurationMap maxStreamConfigMap = 1841 chars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 1842 openDevice(id); 1843 try { 1844 verifyBasicSensorPixelModes(id, maxStreamConfigMap, defaultStreamConfigMap, 1845 /*maxResolution*/ false); 1846 verifyBasicSensorPixelModes(id, maxStreamConfigMap, defaultStreamConfigMap, 1847 /*maxResolution*/ true); 1848 } finally { 1849 closeDevice(id); 1850 } 1851 } 1852 } 1853 1854 @Test testConfigureAbandonedSurface()1855 public void testConfigureAbandonedSurface() throws Exception { 1856 for (String id : getCameraIdsUnderTest()) { 1857 Log.i(TAG, String.format( 1858 "Testing Camera %s for configuring abandoned surface", id)); 1859 1860 openDevice(id); 1861 try { 1862 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1863 Surface previewSurface = new Surface(preview); 1864 1865 // Abandon preview SurfaceTexture. 1866 preview.release(); 1867 1868 try { 1869 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1870 fail("Configuring abandoned surfaces must fail!"); 1871 } catch (IllegalArgumentException e) { 1872 // expected 1873 Log.i(TAG, "normal session check passed"); 1874 } 1875 1876 // Try constrained high speed session/requests 1877 if (!mStaticInfo.isConstrainedHighSpeedVideoSupported()) { 1878 continue; 1879 } 1880 1881 List<Surface> surfaces = new ArrayList<>(); 1882 surfaces.add(previewSurface); 1883 CameraCaptureSession.StateCallback sessionListener = 1884 mock(CameraCaptureSession.StateCallback.class); 1885 1886 try { 1887 mCamera.createConstrainedHighSpeedCaptureSession(surfaces, 1888 sessionListener, mHandler); 1889 fail("Configuring abandoned surfaces in high speed session must fail!"); 1890 } catch (IllegalArgumentException e) { 1891 // expected 1892 Log.i(TAG, "high speed session check 1 passed"); 1893 } 1894 1895 // Also try abandone the Surface directly 1896 previewSurface.release(); 1897 1898 try { 1899 mCamera.createConstrainedHighSpeedCaptureSession(surfaces, 1900 sessionListener, mHandler); 1901 fail("Configuring abandoned surfaces in high speed session must fail!"); 1902 } catch (IllegalArgumentException e) { 1903 // expected 1904 Log.i(TAG, "high speed session check 2 passed"); 1905 } 1906 } finally { 1907 closeDevice(id); 1908 } 1909 } 1910 } 1911 1912 @Test testAfSceneChange()1913 public void testAfSceneChange() throws Exception { 1914 final int NUM_FRAMES_VERIFIED = 3; 1915 1916 for (String id : getCameraIdsUnderTest()) { 1917 Log.i(TAG, String.format("Testing Camera %s for AF scene change", id)); 1918 1919 StaticMetadata staticInfo = 1920 new StaticMetadata(mCameraManager.getCameraCharacteristics(id)); 1921 if (!staticInfo.isAfSceneChangeSupported()) { 1922 continue; 1923 } 1924 1925 openDevice(id); 1926 1927 try { 1928 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1929 Surface previewSurface = new Surface(preview); 1930 1931 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1932 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback(); 1933 1934 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1935 1936 // Test AF scene change in each AF mode. 1937 for (int afMode : availableAfModes) { 1938 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode); 1939 1940 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1941 previewListener, mHandler); 1942 1943 // Verify that AF scene change is NOT_DETECTED or DETECTED. 1944 for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) { 1945 TotalCaptureResult result = 1946 previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1947 mCollector.expectKeyValueIsIn(result, 1948 CaptureResult.CONTROL_AF_SCENE_CHANGE, 1949 CaptureResult.CONTROL_AF_SCENE_CHANGE_DETECTED, 1950 CaptureResult.CONTROL_AF_SCENE_CHANGE_NOT_DETECTED); 1951 } 1952 1953 mCameraSession.stopRepeating(); 1954 previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT); 1955 previewListener.drain(); 1956 } 1957 } finally { 1958 closeDevice(id); 1959 } 1960 } 1961 } 1962 1963 @Test testOisDataMode()1964 public void testOisDataMode() throws Exception { 1965 final int NUM_FRAMES_VERIFIED = 3; 1966 1967 for (String id : getCameraIdsUnderTest()) { 1968 Log.i(TAG, String.format("Testing Camera %s for OIS mode", id)); 1969 1970 StaticMetadata staticInfo = 1971 new StaticMetadata(mCameraManager.getCameraCharacteristics(id)); 1972 if (!staticInfo.isOisDataModeSupported()) { 1973 continue; 1974 } 1975 1976 openDevice(id); 1977 1978 try { 1979 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1980 Surface previewSurface = new Surface(preview); 1981 1982 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1983 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback(); 1984 1985 int[] availableOisDataModes = staticInfo.getCharacteristics().get( 1986 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES); 1987 1988 // Test each OIS data mode 1989 for (int oisMode : availableOisDataModes) { 1990 previewRequest.set(CaptureRequest.STATISTICS_OIS_DATA_MODE, oisMode); 1991 1992 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1993 previewListener, mHandler); 1994 1995 // Check OIS data in each mode. 1996 for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) { 1997 TotalCaptureResult result = 1998 previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1999 2000 OisSample[] oisSamples = result.get(CaptureResult.STATISTICS_OIS_SAMPLES); 2001 2002 boolean physicalDeviceSupportsOIS = true; 2003 if (staticInfo.isLogicalMultiCamera() && 2004 staticInfo.isActivePhysicalCameraIdSupported()) { 2005 String physicalId = result.get( 2006 CaptureResult.LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID); 2007 assertNotNull(physicalId); 2008 StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId); 2009 physicalDeviceSupportsOIS = physicalStaticInfo.isOisDataModeSupported(); 2010 } 2011 2012 if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_OFF || 2013 !physicalDeviceSupportsOIS) { 2014 mCollector.expectKeyValueEquals(result, 2015 CaptureResult.STATISTICS_OIS_DATA_MODE, 2016 CaptureResult.STATISTICS_OIS_DATA_MODE_OFF); 2017 mCollector.expectTrue("OIS samples reported in OIS_DATA_MODE_OFF", 2018 oisSamples == null || oisSamples.length == 0); 2019 2020 } else if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_ON) { 2021 mCollector.expectKeyValueEquals(result, 2022 CaptureResult.STATISTICS_OIS_DATA_MODE, 2023 CaptureResult.STATISTICS_OIS_DATA_MODE_ON); 2024 mCollector.expectTrue("OIS samples not reported in OIS_DATA_MODE_ON", 2025 oisSamples != null && oisSamples.length != 0); 2026 } else { 2027 mCollector.addMessage(String.format("Invalid OIS mode: %d", oisMode)); 2028 } 2029 } 2030 2031 mCameraSession.stopRepeating(); 2032 previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT); 2033 previewListener.drain(); 2034 } 2035 } finally { 2036 closeDevice(id); 2037 } 2038 } 2039 } 2040 preparePreviewTestSession(SurfaceTexture preview)2041 private CaptureRequest.Builder preparePreviewTestSession(SurfaceTexture preview) 2042 throws Exception { 2043 Surface previewSurface = new Surface(preview); 2044 2045 preview.setDefaultBufferSize(640, 480); 2046 2047 ArrayList<Surface> sessionOutputs = new ArrayList<>(); 2048 sessionOutputs.add(previewSurface); 2049 2050 createSession(sessionOutputs); 2051 2052 CaptureRequest.Builder previewRequest = 2053 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 2054 2055 previewRequest.addTarget(previewSurface); 2056 2057 return previewRequest; 2058 } 2059 prepareTriggerTestSession( SurfaceTexture preview, int aeMode, int afMode)2060 private CaptureRequest.Builder prepareTriggerTestSession( 2061 SurfaceTexture preview, int aeMode, int afMode) throws Exception { 2062 Log.i(TAG, String.format("Testing AE mode %s, AF mode %s", 2063 StaticMetadata.getAeModeName(aeMode), 2064 StaticMetadata.getAfModeName(afMode))); 2065 2066 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 2067 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, aeMode); 2068 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode); 2069 2070 return previewRequest; 2071 } 2072 cancelTriggersAndWait(CaptureRequest.Builder previewRequest, SimpleCaptureCallback captureListener, int afMode)2073 private void cancelTriggersAndWait(CaptureRequest.Builder previewRequest, 2074 SimpleCaptureCallback captureListener, int afMode) throws Exception { 2075 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 2076 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 2077 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 2078 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL); 2079 2080 CaptureRequest triggerRequest = previewRequest.build(); 2081 mCameraSession.capture(triggerRequest, captureListener, mHandler); 2082 2083 // Wait for a few frames to initialize 3A 2084 2085 CaptureResult previewResult = null; 2086 int afState; 2087 int aeState; 2088 2089 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) { 2090 previewResult = captureListener.getCaptureResult( 2091 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 2092 if (VERBOSE) { 2093 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE); 2094 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE); 2095 Log.v(TAG, String.format("AF state: %s, AE state: %s", 2096 StaticMetadata.AF_STATE_NAMES[afState], 2097 StaticMetadata.AE_STATE_NAMES[aeState])); 2098 } 2099 } 2100 2101 // Verify starting states 2102 2103 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE); 2104 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE); 2105 2106 verifyStartingAfState(afMode, afState); 2107 2108 // After several frames, AE must no longer be in INACTIVE state 2109 assertTrue(String.format("AE state must be SEARCHING, CONVERGED, " + 2110 "or FLASH_REQUIRED, is %s", StaticMetadata.AE_STATE_NAMES[aeState]), 2111 aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING || 2112 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED || 2113 aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED); 2114 } 2115 configsContain(StreamConfigurationMap configs, int format, Size size)2116 private boolean configsContain(StreamConfigurationMap configs, int format, Size size) { 2117 Size[] sizes = configs.getOutputSizes(format); 2118 if (sizes == null) { 2119 return false; 2120 } 2121 return Arrays.asList(sizes).contains(size); 2122 } 2123 verifyBasicSensorPixelModes(String id, StreamConfigurationMap maxResConfigs, StreamConfigurationMap defaultConfigs, boolean maxResolution)2124 private void verifyBasicSensorPixelModes(String id, StreamConfigurationMap maxResConfigs, 2125 StreamConfigurationMap defaultConfigs, boolean maxResolution) throws Exception { 2126 // Go through StreamConfiguration map, set up OutputConfiguration and add the opposite 2127 // sensorPixelMode. 2128 final int MIN_RESULT_COUNT = 3; 2129 assertTrue("Default stream config map must be present for id: " + id, 2130 defaultConfigs != null); 2131 if (maxResConfigs == null) { 2132 Log.i(TAG, "camera id " + id + " has no StreamConfigurationMap for max resolution " + 2133 ", skipping verifyBasicSensorPixelModes"); 2134 return; 2135 } 2136 StreamConfigurationMap chosenConfigs = maxResolution ? maxResConfigs : defaultConfigs; 2137 StreamConfigurationMap otherConfigs = maxResolution ? defaultConfigs : maxResConfigs; 2138 OutputConfiguration outputConfig = null; 2139 for (int format : chosenConfigs.getOutputFormats()) { 2140 Size targetSize = CameraTestUtils.getMaxSize(chosenConfigs.getOutputSizes(format)); 2141 if (configsContain(otherConfigs, format, targetSize)) { 2142 // Since both max res and default stream configuration maps contain this size, 2143 // both sensor pixel modes are valid. 2144 Log.v(TAG, "camera id " + id + " 'other' configs with maxResolution" + 2145 maxResolution + " contains the format: " + format + " size: " + targetSize + 2146 " skipping"); 2147 continue; 2148 } 2149 // Create outputConfiguration with this size and format 2150 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 2151 SurfaceTexture textureTarget = null; 2152 ImageReader readerTarget = null; 2153 if (format == ImageFormat.PRIVATE) { 2154 textureTarget = new SurfaceTexture(1); 2155 textureTarget.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight()); 2156 outputConfig = new OutputConfiguration(new Surface(textureTarget)); 2157 } else { 2158 readerTarget = ImageReader.newInstance(targetSize.getWidth(), 2159 targetSize.getHeight(), format, MIN_RESULT_COUNT); 2160 readerTarget.setOnImageAvailableListener(imageListener, mHandler); 2161 outputConfig = new OutputConfiguration(readerTarget.getSurface()); 2162 } 2163 try { 2164 int invalidSensorPixelMode = 2165 maxResolution ? CameraMetadata.SENSOR_PIXEL_MODE_DEFAULT : 2166 CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION; 2167 2168 outputConfig.addSensorPixelModeUsed(invalidSensorPixelMode); 2169 CameraCaptureSession.StateCallback sessionListener = 2170 mock(CameraCaptureSession.StateCallback.class); 2171 List<OutputConfiguration> outputs = new ArrayList<>(); 2172 outputs.add(outputConfig); 2173 CameraCaptureSession session = 2174 CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputs, 2175 sessionListener, mHandler); 2176 String desc = "verifyBasicSensorPixelModes : Format : " + format + " size: " + 2177 targetSize.toString() + " maxResolution : " + maxResolution; 2178 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce().description(desc)). 2179 onConfigureFailed(any(CameraCaptureSession.class)); 2180 verify(sessionListener, never().description(desc)). 2181 onConfigured(any(CameraCaptureSession.class)); 2182 2183 // Remove the invalid sensor pixel mode, session configuration should succeed 2184 sessionListener = mock(CameraCaptureSession.StateCallback.class); 2185 outputConfig.removeSensorPixelModeUsed(invalidSensorPixelMode); 2186 CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputs, 2187 sessionListener, mHandler); 2188 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce().description(desc)). 2189 onConfigured(any(CameraCaptureSession.class)); 2190 verify(sessionListener, never().description(desc)). 2191 onConfigureFailed(any(CameraCaptureSession.class)); 2192 } finally { 2193 if (textureTarget != null) { 2194 textureTarget.release(); 2195 } 2196 2197 if (readerTarget != null) { 2198 readerTarget.close(); 2199 } 2200 } 2201 } 2202 } 2203 verifyStartingAfState(int afMode, int afState)2204 private void verifyStartingAfState(int afMode, int afState) { 2205 switch (afMode) { 2206 case CaptureResult.CONTROL_AF_MODE_AUTO: 2207 case CaptureResult.CONTROL_AF_MODE_MACRO: 2208 assertTrue(String.format("AF state not INACTIVE, is %s", 2209 StaticMetadata.AF_STATE_NAMES[afState]), 2210 afState == CaptureResult.CONTROL_AF_STATE_INACTIVE); 2211 break; 2212 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 2213 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 2214 // After several frames, AF must no longer be in INACTIVE state 2215 assertTrue(String.format("In AF mode %s, AF state not PASSIVE_SCAN" + 2216 ", PASSIVE_FOCUSED, or PASSIVE_UNFOCUSED, is %s", 2217 StaticMetadata.getAfModeName(afMode), 2218 StaticMetadata.AF_STATE_NAMES[afState]), 2219 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN || 2220 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED || 2221 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED); 2222 break; 2223 default: 2224 fail("unexpected af mode"); 2225 } 2226 } 2227 verifyAfSequence(int afMode, int afState, boolean focusComplete)2228 private boolean verifyAfSequence(int afMode, int afState, boolean focusComplete) { 2229 if (focusComplete) { 2230 assertTrue(String.format("AF Mode %s: Focus lock lost after convergence: AF state: %s", 2231 StaticMetadata.getAfModeName(afMode), 2232 StaticMetadata.AF_STATE_NAMES[afState]), 2233 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2234 afState ==CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2235 return focusComplete; 2236 } 2237 if (VERBOSE) { 2238 Log.v(TAG, String.format("AF mode: %s, AF state: %s", 2239 StaticMetadata.getAfModeName(afMode), 2240 StaticMetadata.AF_STATE_NAMES[afState])); 2241 } 2242 switch (afMode) { 2243 case CaptureResult.CONTROL_AF_MODE_AUTO: 2244 case CaptureResult.CONTROL_AF_MODE_MACRO: 2245 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 2246 StaticMetadata.getAfModeName(afMode), 2247 StaticMetadata.AF_STATE_NAMES[afState]), 2248 afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN || 2249 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2250 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2251 focusComplete = 2252 (afState != CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN); 2253 break; 2254 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 2255 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 2256 StaticMetadata.getAfModeName(afMode), 2257 StaticMetadata.AF_STATE_NAMES[afState]), 2258 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN || 2259 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2260 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2261 focusComplete = 2262 (afState != CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN); 2263 break; 2264 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 2265 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 2266 StaticMetadata.getAfModeName(afMode), 2267 StaticMetadata.AF_STATE_NAMES[afState]), 2268 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2269 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2270 focusComplete = true; 2271 break; 2272 default: 2273 fail("Unexpected AF mode: " + StaticMetadata.getAfModeName(afMode)); 2274 } 2275 return focusComplete; 2276 } 2277 verifyAeSequence(int aeState, boolean precaptureComplete)2278 private boolean verifyAeSequence(int aeState, boolean precaptureComplete) { 2279 if (precaptureComplete) { 2280 assertTrue("Precapture state seen after convergence", 2281 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 2282 return precaptureComplete; 2283 } 2284 if (VERBOSE) { 2285 Log.v(TAG, String.format("AE state: %s", StaticMetadata.AE_STATE_NAMES[aeState])); 2286 } 2287 switch (aeState) { 2288 case CaptureResult.CONTROL_AE_STATE_PRECAPTURE: 2289 // scan still continuing 2290 break; 2291 case CaptureResult.CONTROL_AE_STATE_CONVERGED: 2292 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 2293 // completed 2294 precaptureComplete = true; 2295 break; 2296 default: 2297 fail(String.format("Precapture sequence transitioned to " 2298 + "state %s incorrectly!", StaticMetadata.AE_STATE_NAMES[aeState])); 2299 break; 2300 } 2301 return precaptureComplete; 2302 } 2303 2304 /** 2305 * Test for making sure that all expected mandatory stream combinations are present and 2306 * advertised accordingly. 2307 */ 2308 @Test testVerifyMandatoryOutputCombinationTables()2309 public void testVerifyMandatoryOutputCombinationTables() throws Exception { 2310 final int[][] legacyCombinations = { 2311 // Simple preview, GPU video processing, or no-preview video recording 2312 {PRIV, MAXIMUM}, 2313 // No-viewfinder still image capture 2314 {JPEG, MAXIMUM}, 2315 // In-application video/image processing 2316 {YUV, MAXIMUM}, 2317 // Standard still imaging. 2318 {PRIV, PREVIEW, JPEG, MAXIMUM}, 2319 // In-app processing plus still capture. 2320 {YUV, PREVIEW, JPEG, MAXIMUM}, 2321 // Standard recording. 2322 {PRIV, PREVIEW, PRIV, PREVIEW}, 2323 // Preview plus in-app processing. 2324 {PRIV, PREVIEW, YUV, PREVIEW}, 2325 // Still capture plus in-app processing. 2326 {PRIV, PREVIEW, YUV, PREVIEW, JPEG, MAXIMUM} 2327 }; 2328 2329 final int[][] limitedCombinations = { 2330 // High-resolution video recording with preview. 2331 {PRIV, PREVIEW, PRIV, RECORD }, 2332 // High-resolution in-app video processing with preview. 2333 {PRIV, PREVIEW, YUV , RECORD }, 2334 // Two-input in-app video processing. 2335 {YUV , PREVIEW, YUV , RECORD }, 2336 // High-resolution recording with video snapshot. 2337 {PRIV, PREVIEW, PRIV, RECORD, JPEG, RECORD }, 2338 // High-resolution in-app processing with video snapshot. 2339 {PRIV, PREVIEW, YUV, RECORD, JPEG, RECORD }, 2340 // Two-input in-app processing with still capture. 2341 {YUV , PREVIEW, YUV, PREVIEW, JPEG, MAXIMUM } 2342 }; 2343 2344 final int[][] burstCombinations = { 2345 // Maximum-resolution GPU processing with preview. 2346 {PRIV, PREVIEW, PRIV, MAXIMUM }, 2347 // Maximum-resolution in-app processing with preview. 2348 {PRIV, PREVIEW, YUV, MAXIMUM }, 2349 // Maximum-resolution two-input in-app processing. 2350 {YUV, PREVIEW, YUV, MAXIMUM }, 2351 }; 2352 2353 final int[][] fullCombinations = { 2354 // Video recording with maximum-size video snapshot. 2355 {PRIV, PREVIEW, PRIV, PREVIEW, JPEG, MAXIMUM }, 2356 // Standard video recording plus maximum-resolution in-app processing. 2357 {YUV, VGA, PRIV, PREVIEW, YUV, MAXIMUM }, 2358 // Preview plus two-input maximum-resolution in-app processing. 2359 {YUV, VGA, YUV, PREVIEW, YUV, MAXIMUM } 2360 }; 2361 2362 final int[][] rawCombinations = { 2363 // No-preview DNG capture. 2364 {RAW, MAXIMUM }, 2365 // Standard DNG capture. 2366 {PRIV, PREVIEW, RAW, MAXIMUM }, 2367 // In-app processing plus DNG capture. 2368 {YUV, PREVIEW, RAW, MAXIMUM }, 2369 // Video recording with DNG capture. 2370 {PRIV, PREVIEW, PRIV, PREVIEW, RAW, MAXIMUM}, 2371 // Preview with in-app processing and DNG capture. 2372 {PRIV, PREVIEW, YUV, PREVIEW, RAW, MAXIMUM}, 2373 // Two-input in-app processing plus DNG capture. 2374 {YUV, PREVIEW, YUV, PREVIEW, RAW, MAXIMUM}, 2375 // Still capture with simultaneous JPEG and DNG. 2376 {PRIV, PREVIEW, JPEG, MAXIMUM, RAW, MAXIMUM}, 2377 // In-app processing with simultaneous JPEG and DNG. 2378 {YUV, PREVIEW, JPEG, MAXIMUM, RAW, MAXIMUM} 2379 }; 2380 2381 final int[][] level3Combinations = { 2382 // In-app viewfinder analysis with dynamic selection of output format 2383 {PRIV, PREVIEW, PRIV, VGA, YUV, MAXIMUM, RAW, MAXIMUM}, 2384 // In-app viewfinder analysis with dynamic selection of output format 2385 {PRIV, PREVIEW, PRIV, VGA, JPEG, MAXIMUM, RAW, MAXIMUM} 2386 }; 2387 2388 final int[][] concurrentStreamCombinations = { 2389 //In-app video / image processing. 2390 {YUV, S1440P_4_3}, 2391 // In-app viewfinder analysis. 2392 {PRIV, S1440P_4_3}, 2393 // No viewfinder still image capture. 2394 {JPEG, S1440P_4_3}, 2395 // Standard still imaging. 2396 {YUV, S720P, JPEG, S1440P_4_3}, 2397 {PRIV, S720P, JPEG, S1440P_4_3}, 2398 // In-app video / processing with preview. 2399 {YUV, S720P, YUV, S1440P_4_3}, 2400 {YUV, S720P, PRIV, S1440P_4_3}, 2401 {PRIV, S720P, YUV, S1440P_4_3}, 2402 {PRIV, S720P, PRIV, S1440P_4_3} 2403 }; 2404 2405 final int[][] ultraHighResolutionsCombinations = { 2406 // Ultra high res still image capture with preview. 2407 {YUV, MAX_RES, PRIV, PREVIEW}, 2408 {YUV, MAX_RES, YUV, PREVIEW}, 2409 {JPEG, MAX_RES, PRIV, PREVIEW}, 2410 {JPEG, MAX_RES, YUV, PREVIEW}, 2411 {RAW, MAX_RES, PRIV, PREVIEW}, 2412 {RAW, MAX_RES, YUV, PREVIEW}, 2413 // Ultra high res still capture with preview + app based RECORD size analysis. 2414 {YUV, MAX_RES, PRIV, PREVIEW, PRIV, RECORD}, 2415 {YUV, MAX_RES, PRIV, PREVIEW, YUV, RECORD}, 2416 {JPEG, MAX_RES, PRIV, PREVIEW, PRIV, RECORD}, 2417 {JPEG, MAX_RES, PRIV, PREVIEW, YUV, RECORD}, 2418 {RAW, MAX_RES, PRIV, PREVIEW, PRIV, RECORD}, 2419 {RAW, MAX_RES, PRIV, PREVIEW, YUV, RECORD}, 2420 // Ultra high res still image capture with preview + default sensor pixel mode analysis 2421 // stream 2422 {YUV, MAX_RES, PRIV, PREVIEW, JPEG, MAXIMUM}, 2423 {YUV, MAX_RES, PRIV, PREVIEW, YUV, MAXIMUM}, 2424 {YUV, MAX_RES, PRIV, PREVIEW, RAW, MAXIMUM}, 2425 {JPEG, MAX_RES, PRIV, PREVIEW, JPEG, MAXIMUM}, 2426 {JPEG, MAX_RES, PRIV, PREVIEW, YUV, MAXIMUM}, 2427 {JPEG, MAX_RES, PRIV, PREVIEW, RAW, MAXIMUM}, 2428 {RAW, MAX_RES, PRIV, PREVIEW, JPEG, MAXIMUM}, 2429 {RAW, MAX_RES, PRIV, PREVIEW, YUV, MAXIMUM}, 2430 {RAW, MAX_RES, PRIV, PREVIEW, RAW, MAXIMUM}, 2431 }; 2432 2433 final int[][] tenBitOutputCombinations = { 2434 // Simple preview, GPU video processing, or no-preview video recording. 2435 {PRIV, MAXIMUM}, 2436 // In-application video/image processing. 2437 {YUV, MAXIMUM}, 2438 // Standard still imaging. 2439 {PRIV, PREVIEW, JPEG, MAXIMUM}, 2440 // Maximum-resolution in-app processing with preview. 2441 {PRIV, PREVIEW, YUV, MAXIMUM}, 2442 // Maximum-resolution two-input in-app processing. 2443 {YUV, PREVIEW, YUV, MAXIMUM}, 2444 // High-resolution video recording with preview. 2445 {PRIV, PREVIEW, PRIV, RECORD}, 2446 // High-resolution recording with in-app snapshot. 2447 {PRIV, PREVIEW, PRIV, RECORD, YUV, RECORD}, 2448 // High-resolution recording with video snapshot. 2449 {PRIV, PREVIEW, PRIV, RECORD, JPEG, RECORD} 2450 }; 2451 2452 final int[][] streamUseCaseCombinations = { 2453 // Simple preview or in-app image processing. 2454 {YUV, PREVIEW, USE_CASE_PREVIEW}, 2455 {PRIV, PREVIEW, USE_CASE_PREVIEW}, 2456 // Simple video recording or in-app video processing. 2457 {YUV, RECORD, USE_CASE_VIDEO_RECORD}, 2458 {PRIV, RECORD, USE_CASE_VIDEO_RECORD}, 2459 // Simple JPEG or YUV still image capture. 2460 {YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2461 {JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2462 // Multi-purpose stream for preview, video and still image capture. 2463 {YUV, S1440P_4_3, USE_CASE_PREVIEW_VIDEO_STILL}, 2464 {PRIV, S1440P_4_3, USE_CASE_PREVIEW_VIDEO_STILL}, 2465 // Simple video call. 2466 {YUV, S1440P_4_3, USE_CASE_VIDEO_CALL}, 2467 {PRIV, S1440P_4_3, USE_CASE_VIDEO_CALL}, 2468 // Preview with JPEG or YUV still image capture. 2469 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2470 {PRIV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2471 // Preview with video recording or in-app video processing. 2472 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, RECORD, USE_CASE_VIDEO_RECORD}, 2473 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, RECORD, USE_CASE_VIDEO_RECORD}, 2474 // Preview with in-application image processing. 2475 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW}, 2476 // Preview with video call. 2477 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, S1440P_4_3, USE_CASE_VIDEO_CALL}, 2478 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, S1440P_4_3, USE_CASE_VIDEO_CALL}, 2479 // {Multi-purpose stream with JPEG or YUV still capture. 2480 {YUV, S1440P_4_3, USE_CASE_PREVIEW_VIDEO_STILL, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2481 {YUV, S1440P_4_3, USE_CASE_PREVIEW_VIDEO_STILL, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2482 {PRIV, S1440P_4_3, USE_CASE_PREVIEW_VIDEO_STILL, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2483 {PRIV, S1440P_4_3, USE_CASE_PREVIEW_VIDEO_STILL, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2484 // YUV and JPEG concurrent still image capture (for testing). 2485 {YUV, PREVIEW, USE_CASE_STILL_CAPTURE, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2486 // Preview, video record and JPEG video snapshot. 2487 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, RECORD, USE_CASE_VIDEO_RECORD, JPEG, RECORD, 2488 USE_CASE_STILL_CAPTURE}, 2489 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, RECORD, USE_CASE_VIDEO_RECORD, JPEG, RECORD, 2490 USE_CASE_STILL_CAPTURE}, 2491 // Preview, in-application image processing, and JPEG still image capture. 2492 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, 2493 USE_CASE_STILL_CAPTURE}, 2494 }; 2495 2496 final int[][] streamUseCaseCroppedRawCombinations = { 2497 // Cropped RAW still image capture without preview 2498 {RAW, MAXIMUM, USE_CASE_CROPPED_RAW}, 2499 2500 // Preview / In-app processing with cropped RAW still image capture 2501 {PRIV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, USE_CASE_CROPPED_RAW}, 2502 {YUV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, USE_CASE_CROPPED_RAW}, 2503 2504 // Preview / In-app processing with YUV and cropped RAW still image capture 2505 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2506 USE_CASE_CROPPED_RAW}, 2507 {YUV, PREVIEW, USE_CASE_PREVIEW, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2508 USE_CASE_CROPPED_RAW}, 2509 2510 // Preview / In-app processing with JPEG and cropped RAW still image capture 2511 {PRIV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2512 USE_CASE_CROPPED_RAW}, 2513 {YUV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2514 USE_CASE_CROPPED_RAW}, 2515 2516 // Preview with in-app processing / video recording and cropped RAW snapshot 2517 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, PREVIEW, USE_CASE_VIDEO_RECORD, RAW, MAXIMUM, 2518 USE_CASE_CROPPED_RAW}, 2519 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, 2520 USE_CASE_CROPPED_RAW}, 2521 2522 // Two input in-app processing with RAW 2523 {YUV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, 2524 USE_CASE_CROPPED_RAW}, 2525 }; 2526 2527 2528 final int[][] previewStabilizationCombinations = { 2529 // Stabilized preview, GPU video processing, or no-preview stabilized video recording. 2530 {PRIV, S1440P_4_3}, 2531 {YUV, S1440P_4_3}, 2532 // Standard still imaging with stabilized preview. 2533 {PRIV, S1440P_4_3, JPEG, MAXIMUM}, 2534 {PRIV, S1440P_4_3, YUV, MAXIMUM}, 2535 {YUV, S1440P_4_3, JPEG, MAXIMUM}, 2536 {YUV, S1440P_4_3, YUV, MAXIMUM}, 2537 // High-resolution recording with stabilized preview and recording stream. 2538 {PRIV, PREVIEW, PRIV, S1440P_4_3}, 2539 {PRIV, PREVIEW, YUV, S1440P_4_3}, 2540 {YUV, PREVIEW, PRIV, S1440P_4_3}, 2541 {YUV, PREVIEW, YUV, S1440P_4_3}, 2542 }; 2543 2544 final int[][][] tables = 2545 {legacyCombinations, limitedCombinations, burstCombinations, fullCombinations, 2546 rawCombinations, level3Combinations, concurrentStreamCombinations, 2547 ultraHighResolutionsCombinations, tenBitOutputCombinations, 2548 previewStabilizationCombinations}; 2549 2550 final int[][][] useCaseTables = {streamUseCaseCombinations, 2551 streamUseCaseCroppedRawCombinations}; 2552 2553 validityCheckConfigurationTables(tables); 2554 validityCheckConfigurationTables(useCaseTables, /*useCaseSpecified*/ true); 2555 2556 for (String id : getCameraIdsUnderTest()) { 2557 openDevice(id); 2558 MandatoryStreamCombination[] combinations = 2559 mStaticInfo.getCharacteristics().get( 2560 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 2561 if ((combinations == null) || (combinations.length == 0)) { 2562 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 2563 closeDevice(id); 2564 continue; 2565 } 2566 2567 MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, mContext); 2568 try { 2569 if (mStaticInfo.isColorOutputSupported()) { 2570 for (int[] c : legacyCombinations) { 2571 assertTrue(String.format("Expected static stream combination: %s not " 2572 + "found among the available mandatory combinations", 2573 maxSizes.combinationToString(c)), 2574 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2575 } 2576 } 2577 2578 if (!mStaticInfo.isHardwareLevelLegacy()) { 2579 if (mStaticInfo.isColorOutputSupported()) { 2580 for (int[] c : limitedCombinations) { 2581 assertTrue(String.format("Expected static stream combination: %s not " 2582 + "found among the available mandatory combinations", 2583 maxSizes.combinationToString(c)), 2584 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2585 } 2586 } 2587 2588 if (mStaticInfo.isCapabilitySupported( 2589 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 2590 for (int[] c : burstCombinations) { 2591 assertTrue(String.format("Expected static stream combination: %s not " 2592 + "found among the available mandatory combinations", 2593 maxSizes.combinationToString(c)), 2594 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2595 } 2596 } 2597 2598 if (mStaticInfo.isHardwareLevelAtLeastFull()) { 2599 for (int[] c : fullCombinations) { 2600 assertTrue(String.format("Expected static stream combination: %s not " 2601 + "found among the available mandatory combinations", 2602 maxSizes.combinationToString(c)), 2603 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2604 } 2605 } 2606 2607 if (mStaticInfo.isCapabilitySupported( 2608 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2609 for (int[] c : rawCombinations) { 2610 assertTrue(String.format("Expected static stream combination: %s not " 2611 + "found among the available mandatory combinations", 2612 maxSizes.combinationToString(c)), 2613 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2614 } 2615 } 2616 2617 if (mStaticInfo.isHardwareLevelAtLeast( 2618 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) { 2619 for (int[] c: level3Combinations) { 2620 assertTrue(String.format("Expected static stream combination: %s not " 2621 + "found among the available mandatory combinations ", 2622 maxSizes.combinationToString(c)), 2623 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2624 } 2625 } 2626 } 2627 2628 Set<Set<String>> concurrentCameraIdCombinations = 2629 mCameraManager.getConcurrentCameraIds(); 2630 boolean isConcurrentCamera = false; 2631 for (Set<String> concurrentCameraIdCombination : concurrentCameraIdCombinations) { 2632 if (concurrentCameraIdCombination.contains(id)) { 2633 isConcurrentCamera = true; 2634 break; 2635 } 2636 } 2637 2638 if (isConcurrentCamera && mStaticInfo.isCapabilitySupported( 2639 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) { 2640 MandatoryStreamCombination[] mandatoryConcurrentStreamCombinations = 2641 mStaticInfo.getCharacteristics().get( 2642 CameraCharacteristics 2643 .SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS); 2644 for (int[] c : concurrentStreamCombinations) { 2645 assertTrue(String.format("Expected static stream combination: %s not " 2646 + "found among the available mandatory concurrent stream " 2647 + "combinations", 2648 maxSizes.combinationToString(c)), 2649 isMandatoryCombinationAvailable(c, maxSizes, 2650 mandatoryConcurrentStreamCombinations)); 2651 } 2652 } 2653 2654 if (mStaticInfo.isCapabilitySupported( 2655 CameraCharacteristics 2656 .REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR)) { 2657 MandatoryStreamCombination[] maxResolutionStreamCombinations = 2658 mStaticInfo.getCharacteristics().get( 2659 CameraCharacteristics 2660 .SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS); 2661 for (int[] c : ultraHighResolutionsCombinations) { 2662 assertTrue(String.format("Expected static stream combination: %s not " 2663 + "found among the available mandatory max resolution stream " 2664 + "combinations", 2665 maxSizes.combinationToString(c)), 2666 isMandatoryCombinationAvailable(c, maxSizes, 2667 maxResolutionStreamCombinations)); 2668 } 2669 } 2670 2671 if (mStaticInfo.isCapabilitySupported( 2672 CameraCharacteristics 2673 .REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) { 2674 MandatoryStreamCombination[] mandatoryTenBitOutputCombinations = 2675 mStaticInfo.getCharacteristics().get( 2676 CameraCharacteristics 2677 .SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS); 2678 for (int[] c : tenBitOutputCombinations) { 2679 assertTrue(String.format("Expected static stream combination: %s not " 2680 + "found among the available mandatory 10 bit output " 2681 + "combinations", 2682 maxSizes.combinationToString(c)), 2683 isMandatoryCombinationAvailable(c, maxSizes, 2684 mandatoryTenBitOutputCombinations)); 2685 } 2686 } 2687 2688 if (mStaticInfo.isCapabilitySupported( 2689 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) { 2690 MandatoryStreamCombination[] mandatoryStreamUseCaseCombinations = 2691 mStaticInfo.getCharacteristics().get( 2692 CameraCharacteristics 2693 .SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS); 2694 for (int[] c : streamUseCaseCombinations) { 2695 assertTrue(String.format("Expected static stream combination: %s not " 2696 + "found among the available mandatory stream use case " 2697 + "combinations", 2698 maxSizes.combinationToString(c, /*useCaseSpecified*/ true)), 2699 isMandatoryCombinationAvailable(c, maxSizes, 2700 /*isInput*/ false, mandatoryStreamUseCaseCombinations, 2701 /*useCaseSpecified*/ true)); 2702 } 2703 2704 if (mStaticInfo.isCroppedRawStreamUseCaseSupported()) { 2705 for (int[] c : streamUseCaseCroppedRawCombinations) { 2706 assertTrue(String.format("Expected static stream combination: %s not " 2707 + "found among the available mandatory cropped RAW stream" 2708 + " use case combinations", 2709 maxSizes.combinationToString(c, /*useCaseSpecified*/ true)), 2710 isMandatoryCombinationAvailable(c, maxSizes, 2711 /*isInput*/ false, mandatoryStreamUseCaseCombinations, 2712 /*useCaseSpecified*/ true)); 2713 } 2714 } 2715 } 2716 2717 if (mStaticInfo.isPreviewStabilizationSupported()) { 2718 MandatoryStreamCombination[] mandatoryPreviewStabilizationCombinations = 2719 mStaticInfo.getCharacteristics().get( 2720 CameraCharacteristics 2721 .SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS); 2722 for (int[] c : previewStabilizationCombinations) { 2723 assertTrue(String.format("Expected static stream combination: %s not " 2724 + "found among the available mandatory preview stabilization" 2725 + "combinations", 2726 maxSizes.combinationToString(c)), 2727 isMandatoryCombinationAvailable(c, maxSizes, 2728 mandatoryPreviewStabilizationCombinations)); 2729 } 2730 } 2731 } finally { 2732 closeDevice(id); 2733 } 2734 } 2735 } 2736 2737 /** 2738 * Test for making sure that all expected reprocessable mandatory stream combinations are 2739 * present and advertised accordingly. 2740 */ 2741 @Test testVerifyReprocessMandatoryOutputCombinationTables()2742 public void testVerifyReprocessMandatoryOutputCombinationTables() throws Exception { 2743 final int[][] limitedCombinations = { 2744 // Input Outputs 2745 {PRIV, MAXIMUM, JPEG, MAXIMUM}, 2746 {YUV , MAXIMUM, JPEG, MAXIMUM}, 2747 {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM}, 2748 {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM}, 2749 {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM}, 2750 {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM}, 2751 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2752 {YUV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2753 }; 2754 2755 final int[][] fullCombinations = { 2756 // Input Outputs 2757 {YUV , MAXIMUM, PRIV, PREVIEW}, 2758 {YUV , MAXIMUM, YUV , PREVIEW}, 2759 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , RECORD}, 2760 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , RECORD}, 2761 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , MAXIMUM}, 2762 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , MAXIMUM}, 2763 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2764 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2765 }; 2766 2767 final int[][] rawCombinations = { 2768 // Input Outputs 2769 {PRIV, MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM}, 2770 {YUV , MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM}, 2771 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2772 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2773 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2774 {YUV , MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2775 {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2776 {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2777 {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2778 {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2779 }; 2780 2781 final int[][] level3Combinations = { 2782 // Input Outputs 2783 // In-app viewfinder analysis with YUV->YUV ZSL and RAW 2784 {YUV , MAXIMUM, PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM}, 2785 // In-app viewfinder analysis with PRIV->JPEG ZSL and RAW 2786 {PRIV, MAXIMUM, PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM}, 2787 // In-app viewfinder analysis with YUV->JPEG ZSL and RAW 2788 {YUV , MAXIMUM, PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM}, 2789 }; 2790 2791 final int[][] ultraHighResolutionCombinations = { 2792 // Input Outputs 2793 // RAW remosaic reprocessing with separate preview 2794 {RAW, MAX_RES, PRIV, PREVIEW}, 2795 {RAW, MAX_RES, YUV, PREVIEW}, 2796 // Ultra high res RAW -> JPEG / YUV with separate preview 2797 {RAW, MAX_RES, PRIV, PREVIEW, JPEG, MAX_RES}, 2798 {RAW, MAX_RES, PRIV, PREVIEW, YUV, MAX_RES}, 2799 {RAW, MAX_RES, YUV, PREVIEW, JPEG, MAX_RES}, 2800 {RAW, MAX_RES, YUV, PREVIEW, YUV, MAX_RES}, 2801 // Ultra high res PRIV / YUV -> YUV / JPEG reprocessing with separate preview 2802 {YUV, MAX_RES, YUV, PREVIEW, JPEG, MAX_RES}, 2803 {YUV, MAX_RES, PRIV, PREVIEW, JPEG, MAX_RES}, 2804 {PRIV, MAX_RES, YUV, PREVIEW, JPEG, MAX_RES}, 2805 {PRIV, MAX_RES, PRIV, PREVIEW, JPEG, MAX_RES}, 2806 }; 2807 2808 final int[][][] TABLES = 2809 {limitedCombinations, fullCombinations, rawCombinations, level3Combinations, 2810 ultraHighResolutionCombinations}; 2811 2812 validityCheckConfigurationTables(TABLES); 2813 2814 for (String id : getCameraIdsUnderTest()) { 2815 openDevice(id); 2816 MandatoryStreamCombination[] cs = mStaticInfo.getCharacteristics().get( 2817 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 2818 if ((cs == null) || (cs.length == 0)) { 2819 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 2820 closeDevice(id); 2821 continue; 2822 } 2823 2824 boolean supportYuvReprocess = mStaticInfo.isCapabilitySupported( 2825 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 2826 boolean supportOpaqueReprocess = mStaticInfo.isCapabilitySupported( 2827 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 2828 if (!supportYuvReprocess && !supportOpaqueReprocess) { 2829 Log.i(TAG, "No reprocess support for camera: " + id + " skip test"); 2830 closeDevice(id); 2831 continue; 2832 } 2833 2834 MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, mContext); 2835 try { 2836 for (int[] c : limitedCombinations) { 2837 assertTrue(String.format("Expected static reprocessable stream combination:" + 2838 "%s not found among the available mandatory combinations", 2839 maxSizes.reprocessCombinationToString(c)), 2840 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2841 } 2842 2843 if (mStaticInfo.isHardwareLevelAtLeastFull()) { 2844 for (int[] c : fullCombinations) { 2845 assertTrue(String.format( 2846 "Expected static reprocessable stream combination:" + 2847 "%s not found among the available mandatory combinations", 2848 maxSizes.reprocessCombinationToString(c)), 2849 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2850 } 2851 } 2852 2853 if (mStaticInfo.isCapabilitySupported( 2854 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2855 for (int[] c : rawCombinations) { 2856 assertTrue(String.format( 2857 "Expected static reprocessable stream combination:" + 2858 "%s not found among the available mandatory combinations", 2859 maxSizes.reprocessCombinationToString(c)), 2860 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2861 } 2862 } 2863 2864 if (mStaticInfo.isHardwareLevelAtLeast( 2865 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) { 2866 for (int[] c : level3Combinations) { 2867 assertTrue(String.format( 2868 "Expected static reprocessable stream combination:" + 2869 "%s not found among the available mandatory combinations", 2870 maxSizes.reprocessCombinationToString(c)), 2871 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2872 } 2873 } 2874 2875 if (mStaticInfo.isCapabilitySupported( 2876 CameraCharacteristics 2877 .REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR)) { 2878 MandatoryStreamCombination[] maxResolutionCombinations = 2879 mStaticInfo.getCharacteristics().get( 2880 CameraCharacteristics 2881 .SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS); 2882 for (int[] c : ultraHighResolutionCombinations) { 2883 assertTrue(String.format( 2884 "Expected static reprocessable stream combination:" 2885 + "%s not found among the available mandatory max resolution" 2886 + "combinations", 2887 maxSizes.reprocessCombinationToString(c)), 2888 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, 2889 maxResolutionCombinations)); 2890 } 2891 } 2892 } finally { 2893 closeDevice(id); 2894 } 2895 } 2896 } 2897 isMandatoryCombinationAvailable(final int[] combination, final MaxStreamSizes maxSizes, final MandatoryStreamCombination[] availableCombinations)2898 private boolean isMandatoryCombinationAvailable(final int[] combination, 2899 final MaxStreamSizes maxSizes, 2900 final MandatoryStreamCombination[] availableCombinations) { 2901 return isMandatoryCombinationAvailable(combination, maxSizes, /*isInput*/ false, 2902 availableCombinations, /*useCaseSpecified*/ false); 2903 } 2904 isMandatoryCombinationAvailable(final int[] combination, final MaxStreamSizes maxSizes, boolean isInput, final MandatoryStreamCombination[] availableCombinations)2905 private boolean isMandatoryCombinationAvailable(final int[] combination, 2906 final MaxStreamSizes maxSizes, boolean isInput, 2907 final MandatoryStreamCombination[] availableCombinations) { 2908 return isMandatoryCombinationAvailable(combination, maxSizes, isInput, 2909 availableCombinations, /*useCaseSpecified*/ false); 2910 } 2911 isMandatoryCombinationAvailable(final int[] combination, final MaxStreamSizes maxSizes, boolean isInput, final MandatoryStreamCombination[] availableCombinations, boolean useCaseSpecified)2912 private boolean isMandatoryCombinationAvailable(final int[] combination, 2913 final MaxStreamSizes maxSizes, boolean isInput, 2914 final MandatoryStreamCombination[] availableCombinations, boolean useCaseSpecified) { 2915 boolean supportYuvReprocess = mStaticInfo.isCapabilitySupported( 2916 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 2917 boolean supportOpaqueReprocess = mStaticInfo.isCapabilitySupported( 2918 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 2919 // Static combinations to be verified can be composed of multiple entries 2920 // that have the following layout (format, size). In case "isInput" is set, 2921 // the first stream configuration entry will contain the input format and size 2922 // as well as the first matching output. 2923 // For combinations that contain streamUseCase, the layout will be (format, size, useCase). 2924 int streamCount = useCaseSpecified ? combination.length / 3 : combination.length / 2; 2925 2926 List<Pair<Pair<Integer, Boolean>, Size>> currentCombination = 2927 new ArrayList<Pair<Pair<Integer, Boolean>, Size>>(streamCount); 2928 List<Integer> streamUseCases = new ArrayList<Integer>(streamCount); 2929 int i = 0; 2930 while (i < combination.length) { 2931 if (isInput && (i == 0)) { 2932 // Skip the combination if the format is not supported for reprocessing. 2933 if ((combination[i] == YUV && !supportYuvReprocess) || 2934 (combination[i] == PRIV && !supportOpaqueReprocess)) { 2935 return true; 2936 } 2937 // Skip the combination if for MAX_RES size, the maximum resolution stream config 2938 // map doesn't have the given format in getInputFormats(). 2939 if (combination[i + 1] == MAX_RES) { 2940 StreamConfigurationMap maxResolutionStreamConfigMap = 2941 mStaticInfo.getCharacteristics().get( 2942 CameraCharacteristics 2943 .SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 2944 int[] inputFormats = maxResolutionStreamConfigMap.getInputFormats(); 2945 int type = combination[i]; 2946 if (!Arrays.stream(inputFormats).anyMatch(index -> index == type)) { 2947 return true; 2948 } 2949 } 2950 Size sz = maxSizes.getMaxInputSizeForFormat(combination[i], combination[i + 1]); 2951 currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]), 2952 new Boolean(true)), sz)); 2953 currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]), 2954 new Boolean(false)), sz)); 2955 } else { 2956 Size sz = maxSizes.getOutputSizeForFormat(combination[i], combination[i+1]); 2957 currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]), 2958 new Boolean(false)), sz)); 2959 if (useCaseSpecified) { 2960 streamUseCases.add(combination[i + 2]); 2961 } 2962 } 2963 i += 2; 2964 if (useCaseSpecified) { 2965 i += 1; 2966 } 2967 } 2968 2969 for (MandatoryStreamCombination c : availableCombinations) { 2970 List<MandatoryStreamInformation> streamInfoList = c.getStreamsInformation(); 2971 if ((streamInfoList.size() == currentCombination.size()) && 2972 (isInput == c.isReprocessable())) { 2973 ArrayList<Pair<Pair<Integer, Boolean>, Size>> expected = 2974 new ArrayList<Pair<Pair<Integer, Boolean>, Size>>(currentCombination); 2975 ArrayList<Integer> expectedStreamUseCases = new ArrayList<Integer>(streamUseCases); 2976 2977 for (MandatoryStreamInformation streamInfo : streamInfoList) { 2978 Size maxSize = CameraTestUtils.getMaxSize( 2979 streamInfo.getAvailableSizes().toArray(new Size[0])); 2980 Pair p = Pair.create(Pair.create(new Integer(streamInfo.getFormat()), 2981 new Boolean(streamInfo.isInput())), maxSize); 2982 if (expected.contains(p)) { 2983 expected.remove(p); 2984 } 2985 if (useCaseSpecified) { 2986 int streamUseCase = (int) streamInfo.getStreamUseCase(); 2987 if (expectedStreamUseCases.contains(streamUseCase)) { 2988 expectedStreamUseCases.remove(Integer.valueOf(streamUseCase)); 2989 } 2990 } 2991 } 2992 2993 if (expected.isEmpty() && (!useCaseSpecified || expectedStreamUseCases.isEmpty())) { 2994 return true; 2995 } 2996 } 2997 } 2998 2999 return false; 3000 } 3001 3002 /** 3003 * Verify correctness of the configuration tables. 3004 */ validityCheckConfigurationTables(final int[][][] tables)3005 private void validityCheckConfigurationTables(final int[][][] tables) throws Exception { 3006 validityCheckConfigurationTables(tables, false); 3007 } 3008 validityCheckConfigurationTables(final int[][][] tables, boolean useCaseSpecified)3009 private void validityCheckConfigurationTables(final int[][][] tables, boolean useCaseSpecified) 3010 throws Exception { 3011 int tableIdx = 0; 3012 for (int[][] table : tables) { 3013 int rowIdx = 0; 3014 for (int[] row : table) { 3015 if (!useCaseSpecified) { 3016 assertTrue(String.format("Odd number of entries for table %d row %d: %s ", 3017 tableIdx, rowIdx, Arrays.toString(row)), 3018 (row.length % 2) == 0); 3019 } else { 3020 assertTrue(String.format("Incorrect number entries for table with use case " 3021 + "specified %d row %d: %s ", 3022 tableIdx, rowIdx, Arrays.toString(row)), 3023 (row.length % 3) == 0); 3024 } 3025 3026 int i = 0; 3027 while (i < row.length) { 3028 int format = row[i]; 3029 int maxSize = row[i + 1]; 3030 assertTrue(String.format("table %d row %d index %d format not valid: %d", 3031 tableIdx, rowIdx, i, format), 3032 format == PRIV || format == JPEG || format == YUV 3033 || format == RAW); 3034 assertTrue(String.format("table %d row %d index %d max size not valid: %d", 3035 tableIdx, rowIdx, i + 1, maxSize), 3036 maxSize == PREVIEW || maxSize == RECORD 3037 || maxSize == MAXIMUM || maxSize == VGA || maxSize == S720P 3038 || maxSize == S1440P_4_3 || maxSize == MAX_RES); 3039 if (useCaseSpecified) { 3040 int useCase = row[i + 2]; 3041 assertTrue(String.format("table %d row %d index %d use case not valid: %d", 3042 tableIdx, rowIdx, i + 2, useCase), 3043 useCase == USE_CASE_PREVIEW 3044 || useCase == USE_CASE_PREVIEW_VIDEO_STILL 3045 || useCase == USE_CASE_STILL_CAPTURE 3046 || useCase == USE_CASE_VIDEO_CALL 3047 || useCase == USE_CASE_VIDEO_RECORD 3048 || useCase == USE_CASE_CROPPED_RAW); 3049 i += 3; 3050 } else { 3051 i += 2; 3052 } 3053 } 3054 rowIdx++; 3055 } 3056 tableIdx++; 3057 } 3058 } 3059 } 3060