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