1 /* 2 * Copyright 2013 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 com.android.ex.camera2.blocking.BlockingStateCallback.*; 21 import static com.android.ex.camera2.blocking.BlockingSessionCallback.*; 22 import static org.mockito.Mockito.*; 23 import static android.hardware.camera2.CaptureRequest.*; 24 25 import android.content.Context; 26 import android.graphics.SurfaceTexture; 27 import android.graphics.ImageFormat; 28 import android.hardware.camera2.CameraAccessException; 29 import android.hardware.camera2.CameraCaptureSession; 30 import android.hardware.camera2.CameraCharacteristics; 31 import android.hardware.camera2.CameraDevice; 32 import android.hardware.camera2.CameraMetadata; 33 import android.hardware.camera2.CaptureFailure; 34 import android.hardware.camera2.CaptureRequest; 35 import android.hardware.camera2.CaptureResult; 36 import android.hardware.camera2.TotalCaptureResult; 37 import android.hardware.camera2.cts.helpers.StaticMetadata; 38 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel; 39 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 40 import android.hardware.camera2.params.MeteringRectangle; 41 import android.hardware.camera2.params.InputConfiguration; 42 import android.hardware.camera2.params.OutputConfiguration; 43 import android.hardware.camera2.params.SessionConfiguration; 44 import android.hardware.camera2.params.StreamConfigurationMap; 45 import android.media.ImageReader; 46 import android.os.ConditionVariable; 47 import android.os.Handler; 48 import android.os.SystemClock; 49 import android.util.Log; 50 import android.util.Range; 51 import android.view.Surface; 52 53 import com.android.ex.camera2.blocking.BlockingSessionCallback; 54 import com.android.ex.camera2.blocking.BlockingStateCallback; 55 import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 56 import com.android.ex.camera2.utils.StateWaiter; 57 58 import java.util.ArrayList; 59 import java.util.Arrays; 60 import java.util.concurrent.locks.Condition; 61 import java.util.concurrent.locks.Lock; 62 import java.util.concurrent.locks.ReentrantLock; 63 import java.util.HashSet; 64 import java.util.List; 65 import java.util.Map; 66 import java.util.HashMap; 67 import java.util.Set; 68 import android.util.Size; 69 70 import org.mockito.ArgumentMatcher; 71 72 import java.util.concurrent.Executor; 73 import java.util.concurrent.LinkedBlockingQueue; 74 import java.util.concurrent.TimeUnit; 75 76 /** 77 * <p>Basic test for CameraDevice APIs.</p> 78 */ 79 public class CameraDeviceTest extends Camera2AndroidTestCase { 80 private static final String TAG = "CameraDeviceTest"; 81 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 82 private static final int ERROR_LISTENER_WAIT_TIMEOUT_MS = 1000; 83 private static final int REPEATING_CAPTURE_EXPECTED_RESULT_COUNT = 5; 84 private static final int MAX_NUM_IMAGES = 5; 85 private static final int MIN_FPS_REQUIRED_FOR_STREAMING = 20; 86 private static final int DEFAULT_POST_RAW_SENSITIVITY_BOOST = 100; 87 88 private CameraCaptureSession mSession; 89 90 private BlockingStateCallback mCameraMockListener; 91 private int mLatestDeviceState = STATE_UNINITIALIZED; 92 private BlockingSessionCallback mSessionMockListener; 93 private StateWaiter mSessionWaiter; 94 private int mLatestSessionState = -1; // uninitialized 95 96 private static int[] sTemplates = new int[] { 97 CameraDevice.TEMPLATE_PREVIEW, 98 CameraDevice.TEMPLATE_RECORD, 99 CameraDevice.TEMPLATE_STILL_CAPTURE, 100 CameraDevice.TEMPLATE_VIDEO_SNAPSHOT, 101 }; 102 103 private static int[] sInvalidTemplates = new int[] { 104 CameraDevice.TEMPLATE_PREVIEW - 1, 105 CameraDevice.TEMPLATE_MANUAL + 1, 106 }; 107 108 // Request templates that are unsupported by LEGACY mode. 109 private static Set<Integer> sLegacySkipTemplates = new HashSet<>(); 110 static { 111 sLegacySkipTemplates.add(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT); 112 sLegacySkipTemplates.add(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 113 sLegacySkipTemplates.add(CameraDevice.TEMPLATE_MANUAL); 114 } 115 116 @Override setContext(Context context)117 public void setContext(Context context) { 118 super.setContext(context); 119 120 /** 121 * Workaround for mockito and JB-MR2 incompatibility 122 * 123 * Avoid java.lang.IllegalArgumentException: dexcache == null 124 * https://code.google.com/p/dexmaker/issues/detail?id=2 125 */ 126 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 127 128 /** 129 * Create error listener in context scope, to catch asynchronous device error. 130 * Use spy object here since we want to use the SimpleDeviceListener callback 131 * implementation (spy doesn't stub the functions unless we ask it to do so). 132 */ 133 mCameraMockListener = spy(new BlockingStateCallback()); 134 } 135 136 @Override setUp()137 protected void setUp() throws Exception { 138 super.setUp(); 139 /** 140 * Due to the asynchronous nature of camera device error callback, we 141 * have to make sure device doesn't run into error state before. If so, 142 * fail the rest of the tests. This is especially needed when error 143 * callback is fired too late. 144 */ 145 verify(mCameraMockListener, never()) 146 .onError( 147 any(CameraDevice.class), 148 anyInt()); 149 verify(mCameraMockListener, never()) 150 .onDisconnected( 151 any(CameraDevice.class)); 152 153 mCameraListener = mCameraMockListener; 154 } 155 156 @Override tearDown()157 protected void tearDown() throws Exception { 158 super.tearDown(); 159 } 160 161 /** 162 * <p> 163 * Test camera capture request preview capture template. 164 * </p> 165 * 166 * <p> 167 * The request template returned by the camera device must include a 168 * necessary set of metadata keys, and their values must be set correctly. 169 * It mainly requires below settings: 170 * </p> 171 * <ul> 172 * <li>All 3A settings are auto.</li> 173 * <li>All sensor settings are not null.</li> 174 * <li>All ISP processing settings should be non-manual, and the camera 175 * device should make sure the stable frame rate is guaranteed for the given 176 * settings.</li> 177 * </ul> 178 */ testCameraDevicePreviewTemplate()179 public void testCameraDevicePreviewTemplate() throws Exception { 180 for (int i = 0; i < mCameraIds.length; i++) { 181 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_PREVIEW); 182 } 183 184 // TODO: test the frame rate sustainability in preview use case test. 185 } 186 187 /** 188 * <p> 189 * Test camera capture request still capture template. 190 * </p> 191 * 192 * <p> 193 * The request template returned by the camera device must include a 194 * necessary set of metadata keys, and their values must be set correctly. 195 * It mainly requires below settings: 196 * </p> 197 * <ul> 198 * <li>All 3A settings are auto.</li> 199 * <li>All sensor settings are not null.</li> 200 * <li>All ISP processing settings should be non-manual, and the camera 201 * device should make sure the high quality takes priority to the stable 202 * frame rate for the given settings.</li> 203 * </ul> 204 */ testCameraDeviceStillTemplate()205 public void testCameraDeviceStillTemplate() throws Exception { 206 for (int i = 0; i < mCameraIds.length; i++) { 207 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_STILL_CAPTURE); 208 } 209 } 210 211 /** 212 * <p> 213 * Test camera capture video recording template. 214 * </p> 215 * 216 * <p> 217 * The request template returned by the camera device must include a 218 * necessary set of metadata keys, and their values must be set correctly. 219 * It has the similar requirement as preview, with one difference: 220 * </p> 221 * <ul> 222 * <li>Frame rate should be stable, for example, wide fps range like [7, 30] 223 * is a bad setting.</li> 224 */ testCameraDeviceRecordingTemplate()225 public void testCameraDeviceRecordingTemplate() throws Exception { 226 for (int i = 0; i < mCameraIds.length; i++) { 227 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_RECORD); 228 } 229 230 // TODO: test the frame rate sustainability in recording use case test. 231 } 232 233 /** 234 *<p>Test camera capture video snapshot template.</p> 235 * 236 * <p>The request template returned by the camera device must include a necessary set of 237 * metadata keys, and their values must be set correctly. It has the similar requirement 238 * as recording, with an additional requirement: the settings should maximize image quality 239 * without compromising stable frame rate.</p> 240 */ testCameraDeviceVideoSnapShotTemplate()241 public void testCameraDeviceVideoSnapShotTemplate() throws Exception { 242 for (int i = 0; i < mCameraIds.length; i++) { 243 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_VIDEO_SNAPSHOT); 244 } 245 246 // TODO: test the frame rate sustainability in video snapshot use case test. 247 } 248 249 /** 250 *<p>Test camera capture request zero shutter lag template.</p> 251 * 252 * <p>The request template returned by the camera device must include a necessary set of 253 * metadata keys, and their values must be set correctly. It has the similar requirement 254 * as preview, with an additional requirement: </p> 255 */ testCameraDeviceZSLTemplate()256 public void testCameraDeviceZSLTemplate() throws Exception { 257 for (int i = 0; i < mCameraIds.length; i++) { 258 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 259 } 260 } 261 262 /** 263 * <p> 264 * Test camera capture request manual template. 265 * </p> 266 * 267 * <p> 268 * The request template returned by the camera device must include a 269 * necessary set of metadata keys, and their values must be set correctly. It 270 * mainly requires below settings: 271 * </p> 272 * <ul> 273 * <li>All 3A settings are manual.</li> 274 * <li>ISP processing parameters are set to preview quality.</li> 275 * <li>The manual capture parameters (exposure, sensitivity, and so on) are 276 * set to reasonable defaults.</li> 277 * </ul> 278 */ testCameraDeviceManualTemplate()279 public void testCameraDeviceManualTemplate() throws Exception { 280 for (int i = 0; i < mCameraIds.length; i++) { 281 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_MANUAL); 282 } 283 } 284 testCameraDeviceCreateCaptureBuilder()285 public void testCameraDeviceCreateCaptureBuilder() throws Exception { 286 for (int i = 0; i < mCameraIds.length; i++) { 287 try { 288 openDevice(mCameraIds[i], mCameraMockListener); 289 /** 290 * Test: that each template type is supported, and that its required fields are 291 * present. 292 */ 293 for (int j = 0; j < sTemplates.length; j++) { 294 // Skip video snapshots for LEGACY mode 295 if (mStaticInfo.isHardwareLevelLegacy() && 296 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 297 continue; 298 } 299 // Skip non-PREVIEW templates for non-color output 300 if (!mStaticInfo.isColorOutputSupported() && 301 sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) { 302 continue; 303 } 304 CaptureRequest.Builder capReq = mCamera.createCaptureRequest(sTemplates[j]); 305 assertNotNull("Failed to create capture request", capReq); 306 if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_EXPOSURE_TIME)) { 307 assertNotNull("Missing field: SENSOR_EXPOSURE_TIME", 308 capReq.get(CaptureRequest.SENSOR_EXPOSURE_TIME)); 309 } 310 if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_SENSITIVITY)) { 311 assertNotNull("Missing field: SENSOR_SENSITIVITY", 312 capReq.get(CaptureRequest.SENSOR_SENSITIVITY)); 313 } 314 } 315 316 /** 317 * Test: creating capture requests with an invalid template ID should throw 318 * IllegalArgumentException. 319 */ 320 for (int j = 0; j < sInvalidTemplates.length; j++) { 321 try { 322 CaptureRequest.Builder capReq = 323 mCamera.createCaptureRequest(sInvalidTemplates[j]); 324 fail("Should get IllegalArgumentException due to an invalid template ID."); 325 } catch (IllegalArgumentException e) { 326 // Expected exception. 327 } 328 } 329 } 330 finally { 331 try { 332 closeSession(); 333 } finally { 334 closeDevice(mCameraIds[i], mCameraMockListener); 335 } 336 } 337 } 338 } 339 testCameraDeviceSetErrorListener()340 public void testCameraDeviceSetErrorListener() throws Exception { 341 for (int i = 0; i < mCameraIds.length; i++) { 342 try { 343 openDevice(mCameraIds[i], mCameraMockListener); 344 /** 345 * Test: that the error listener can be set without problems. 346 * Also, wait some time to check if device doesn't run into error. 347 */ 348 SystemClock.sleep(ERROR_LISTENER_WAIT_TIMEOUT_MS); 349 verify(mCameraMockListener, never()) 350 .onError( 351 any(CameraDevice.class), 352 anyInt()); 353 } 354 finally { 355 try { 356 closeSession(); 357 } finally { 358 closeDevice(mCameraIds[i], mCameraMockListener); 359 } 360 } 361 } 362 } 363 testCameraDeviceCapture()364 public void testCameraDeviceCapture() throws Exception { 365 runCaptureTest(/*burst*/false, /*repeating*/false, /*abort*/false, /*useExecutor*/false); 366 runCaptureTest(/*burst*/false, /*repeating*/false, /*abort*/false, /*useExecutor*/true); 367 } 368 testCameraDeviceCaptureBurst()369 public void testCameraDeviceCaptureBurst() throws Exception { 370 runCaptureTest(/*burst*/true, /*repeating*/false, /*abort*/false, /*useExecutor*/false); 371 runCaptureTest(/*burst*/true, /*repeating*/false, /*abort*/false, /*useExecutor*/true); 372 } 373 testCameraDeviceRepeatingRequest()374 public void testCameraDeviceRepeatingRequest() throws Exception { 375 runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/false, /*useExecutor*/false); 376 runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/false, /*useExecutor*/true); 377 } 378 testCameraDeviceRepeatingBurst()379 public void testCameraDeviceRepeatingBurst() throws Exception { 380 runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/false, /*useExecutor*/ false); 381 runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/false, /*useExecutor*/ true); 382 } 383 384 /** 385 * Test {@link android.hardware.camera2.CameraCaptureSession#abortCaptures} API. 386 * 387 * <p>Abort is the fastest way to idle the camera device for reconfiguration with 388 * {@link android.hardware.camera2.CameraCaptureSession#abortCaptures}, at the cost of 389 * discarding in-progress work. Once the abort is complete, the idle callback will be called. 390 * </p> 391 */ testCameraDeviceAbort()392 public void testCameraDeviceAbort() throws Exception { 393 runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/true, /*useExecutor*/false); 394 runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/true, /*useExecutor*/true); 395 runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/true, /*useExecutor*/false); 396 runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/true, /*useExecutor*/true); 397 /** 398 * TODO: this is only basic test of abort. we probably should also test below cases: 399 * 400 * 1. Performance. Make sure abort is faster than stopRepeating, we can test each one a 401 * couple of times, then compare the average. Also, for abortCaptures() alone, we should 402 * make sure it doesn't take too long time (e.g. <100ms for full devices, <500ms for limited 403 * devices), after the abort, we should be able to get all results back very quickly. This 404 * can be done in performance test. 405 * 406 * 2. Make sure all in-flight request comes back after abort, e.g. submit a couple of 407 * long exposure single captures, then abort, then check if we can get the pending 408 * request back quickly. 409 * 410 * 3. Also need check onCaptureSequenceCompleted for repeating burst after abortCaptures(). 411 */ 412 } 413 414 /** 415 * Test invalid capture (e.g. null or empty capture request). 416 */ testInvalidCapture()417 public void testInvalidCapture() throws Exception { 418 for (int i = 0; i < mCameraIds.length; i++) { 419 try { 420 openDevice(mCameraIds[i], mCameraMockListener); 421 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 422 423 prepareCapture(); 424 425 invalidRequestCaptureTestByCamera(); 426 427 closeSession(); 428 } 429 finally { 430 closeDevice(mCameraIds[i], mCameraMockListener); 431 } 432 } 433 } 434 435 /** 436 * Test to ensure that we can call camera2 API methods inside callbacks. 437 * 438 * Tests: 439 * onOpened -> createCaptureSession, createCaptureRequest 440 * onConfigured -> getDevice, abortCaptures, 441 * createCaptureRequest, capture, setRepeatingRequest, stopRepeating 442 * onCaptureCompleted -> createCaptureRequest, getDevice, abortCaptures, 443 * capture, setRepeatingRequest, stopRepeating, session+device.close 444 */ testChainedOperation()445 public void testChainedOperation() throws Throwable { 446 447 final ArrayList<Surface> outputs = new ArrayList<>(); 448 449 // A queue for the chained listeners to push results to 450 // A success Throwable indicates no errors; other Throwables detail a test failure; 451 // nulls indicate timeouts. 452 final Throwable success = new Throwable("Success"); 453 final LinkedBlockingQueue<Throwable> results = new LinkedBlockingQueue<>(); 454 455 // Define listeners 456 // A cascade of Device->Session->Capture listeners, each of which invokes at least one 457 // method on the camera device or session. 458 459 class ChainedCaptureCallback extends CameraCaptureSession.CaptureCallback { 460 @Override 461 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 462 TotalCaptureResult result) { 463 try { 464 CaptureRequest.Builder request2 = 465 session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 466 request2.addTarget(mReaderSurface); 467 468 // Some calls to the camera for coverage 469 session.abortCaptures(); 470 session.capture(request2.build(), 471 /*listener*/ null, /*handler*/ null); 472 session.setRepeatingRequest(request2.build(), 473 /*listener*/ null, /*handler*/ null); 474 session.stopRepeating(); 475 476 CameraDevice camera = session.getDevice(); 477 session.close(); 478 camera.close(); 479 480 results.offer(success); 481 } catch (Throwable t) { 482 results.offer(t); 483 } 484 } 485 486 @Override 487 public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, 488 CaptureFailure failure) { 489 try { 490 CameraDevice camera = session.getDevice(); 491 session.close(); 492 camera.close(); 493 fail("onCaptureFailed invoked with failure reason: " + failure.getReason()); 494 } catch (Throwable t) { 495 results.offer(t); 496 } 497 } 498 } 499 500 class ChainedSessionListener extends CameraCaptureSession.StateCallback { 501 private final ChainedCaptureCallback mCaptureCallback = new ChainedCaptureCallback(); 502 503 @Override 504 public void onConfigured(CameraCaptureSession session) { 505 try { 506 CaptureRequest.Builder request = 507 session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 508 request.addTarget(mReaderSurface); 509 // Some calls to the camera for coverage 510 session.getDevice(); 511 session.abortCaptures(); 512 // The important call for the next level of chaining 513 session.capture(request.build(), mCaptureCallback, mHandler); 514 // Some more calls 515 session.setRepeatingRequest(request.build(), 516 /*listener*/ null, /*handler*/ null); 517 session.stopRepeating(); 518 results.offer(success); 519 } catch (Throwable t) { 520 results.offer(t); 521 } 522 } 523 524 @Override 525 public void onConfigureFailed(CameraCaptureSession session) { 526 try { 527 CameraDevice camera = session.getDevice(); 528 session.close(); 529 camera.close(); 530 fail("onConfigureFailed was invoked"); 531 } catch (Throwable t) { 532 results.offer(t); 533 } 534 } 535 } 536 537 class ChainedCameraListener extends CameraDevice.StateCallback { 538 private final ChainedSessionListener mSessionListener = new ChainedSessionListener(); 539 540 public CameraDevice cameraDevice; 541 542 @Override 543 public void onOpened(CameraDevice camera) { 544 545 cameraDevice = camera; 546 try { 547 // Some calls for coverage 548 camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 549 // The important call for next level of chaining 550 camera.createCaptureSession(outputs, mSessionListener, mHandler); 551 results.offer(success); 552 } catch (Throwable t) { 553 try { 554 camera.close(); 555 results.offer(t); 556 } catch (Throwable t2) { 557 Log.e(TAG, 558 "Second failure reached; discarding first exception with trace " + 559 Log.getStackTraceString(t)); 560 results.offer(t2); 561 } 562 } 563 } 564 565 @Override 566 public void onDisconnected(CameraDevice camera) { 567 try { 568 camera.close(); 569 fail("onDisconnected invoked"); 570 } catch (Throwable t) { 571 results.offer(t); 572 } 573 } 574 575 @Override 576 public void onError(CameraDevice camera, int error) { 577 try { 578 camera.close(); 579 fail("onError invoked with error code: " + error); 580 } catch (Throwable t) { 581 results.offer(t); 582 } 583 } 584 } 585 586 // Actual test code 587 588 for (int i = 0; i < mCameraIds.length; i++) { 589 try { 590 Throwable result; 591 592 if (!(new StaticMetadata(mCameraManager.getCameraCharacteristics(mCameraIds[i]))). 593 isColorOutputSupported()) { 594 Log.i(TAG, "Camera " + mCameraIds[i] + 595 " does not support color outputs, skipping"); 596 continue; 597 } 598 599 createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888, 600 MAX_NUM_IMAGES, new ImageDropperListener()); 601 outputs.add(mReaderSurface); 602 603 // Start chained cascade 604 ChainedCameraListener cameraListener = new ChainedCameraListener(); 605 mCameraManager.openCamera(mCameraIds[i], cameraListener, mHandler); 606 607 // Check if open succeeded 608 result = results.poll(CAMERA_OPEN_TIMEOUT_MS, TimeUnit.MILLISECONDS); 609 if (result != success) { 610 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close(); 611 if (result == null) { 612 fail("Timeout waiting for camera open"); 613 } else { 614 throw result; 615 } 616 } 617 618 // Check if configure succeeded 619 result = results.poll(SESSION_CONFIGURE_TIMEOUT_MS, TimeUnit.MILLISECONDS); 620 if (result != success) { 621 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close(); 622 if (result == null) { 623 fail("Timeout waiting for session configure"); 624 } else { 625 throw result; 626 } 627 } 628 629 // Check if capture succeeded 630 result = results.poll(CAPTURE_RESULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); 631 if (result != success) { 632 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close(); 633 if (result == null) { 634 fail("Timeout waiting for capture completion"); 635 } else { 636 throw result; 637 } 638 } 639 640 } finally { 641 closeDefaultImageReader(); 642 outputs.clear(); 643 } 644 } 645 } 646 647 /** 648 * Verify basic semantics and error conditions of the prepare call. 649 * 650 */ testPrepare()651 public void testPrepare() throws Exception { 652 for (int i = 0; i < mCameraIds.length; i++) { 653 try { 654 if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) { 655 Log.i(TAG, "Camera " + mCameraIds[i] + 656 " does not support color outputs, skipping"); 657 continue; 658 } 659 openDevice(mCameraIds[i], mCameraMockListener); 660 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 661 662 prepareTestByCamera(); 663 } 664 finally { 665 closeDevice(mCameraIds[i], mCameraMockListener); 666 } 667 } 668 } 669 670 /** 671 * Verify prepare call behaves properly when sharing surfaces. 672 * 673 */ testPrepareForSharedSurfaces()674 public void testPrepareForSharedSurfaces() throws Exception { 675 for (int i = 0; i < mCameraIds.length; i++) { 676 try { 677 StaticMetadata staticInfo = mAllStaticInfo.get(mCameraIds[i]); 678 if (staticInfo.isHardwareLevelLegacy()) { 679 Log.i(TAG, "Camera " + mCameraIds[i] + " is legacy, skipping"); 680 continue; 681 } 682 if (!staticInfo.isColorOutputSupported()) { 683 Log.i(TAG, "Camera " + mCameraIds[i] + 684 " does not support color outputs, skipping"); 685 continue; 686 } 687 openDevice(mCameraIds[i], mCameraMockListener); 688 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 689 690 prepareTestForSharedSurfacesByCamera(); 691 } 692 finally { 693 closeDevice(mCameraIds[i], mCameraMockListener); 694 } 695 } 696 } 697 698 /** 699 * Verify creating sessions back to back. 700 */ testCreateSessions()701 public void testCreateSessions() throws Exception { 702 for (int i = 0; i < mCameraIds.length; i++) { 703 try { 704 if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) { 705 Log.i(TAG, "Camera " + mCameraIds[i] + 706 " does not support color outputs, skipping"); 707 continue; 708 } 709 openDevice(mCameraIds[i], mCameraMockListener); 710 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 711 712 testCreateSessionsByCamera(mCameraIds[i]); 713 } 714 finally { 715 closeDevice(mCameraIds[i], mCameraMockListener); 716 } 717 } 718 } 719 720 /** 721 * Verify creating a custom session 722 */ testCreateCustomSession()723 public void testCreateCustomSession() throws Exception { 724 for (int i = 0; i < mCameraIds.length; i++) { 725 try { 726 if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) { 727 Log.i(TAG, "Camera " + mCameraIds[i] + 728 " does not support color outputs, skipping"); 729 continue; 730 } 731 openDevice(mCameraIds[i], mCameraMockListener); 732 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 733 734 testCreateCustomSessionByCamera(mCameraIds[i]); 735 } 736 finally { 737 closeDevice(mCameraIds[i], mCameraMockListener); 738 } 739 } 740 } 741 742 /** 743 * Verify creating a custom mode session works 744 */ testCreateCustomSessionByCamera(String cameraId)745 private void testCreateCustomSessionByCamera(String cameraId) throws Exception { 746 final int SESSION_TIMEOUT_MS = 1000; 747 final int CAPTURE_TIMEOUT_MS = 3000; 748 749 if (VERBOSE) { 750 Log.v(TAG, "Testing creating custom session for camera " + cameraId); 751 } 752 753 Size yuvSize = mOrderedPreviewSizes.get(0); 754 755 // Create a list of image readers. JPEG for last one and YUV for the rest. 756 ImageReader imageReader = ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(), 757 ImageFormat.YUV_420_888, /*maxImages*/1); 758 759 try { 760 // Create a normal-mode session via createCustomCaptureSession 761 mSessionMockListener = spy(new BlockingSessionCallback()); 762 mSessionWaiter = mSessionMockListener.getStateWaiter(); 763 List<OutputConfiguration> outputs = new ArrayList<>(); 764 outputs.add(new OutputConfiguration(imageReader.getSurface())); 765 mCamera.createCustomCaptureSession(/*inputConfig*/null, outputs, 766 CameraDevice.SESSION_OPERATION_MODE_NORMAL, mSessionMockListener, mHandler); 767 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 768 769 // Verify we can capture a frame with the session. 770 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 771 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 772 imageReader.setOnImageAvailableListener(imageListener, mHandler); 773 774 CaptureRequest.Builder builder = 775 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 776 builder.addTarget(imageReader.getSurface()); 777 CaptureRequest request = builder.build(); 778 779 mSession.capture(request, captureListener, mHandler); 780 captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS); 781 imageListener.getImage(CAPTURE_TIMEOUT_MS).close(); 782 783 // Create a few invalid custom sessions by using undefined non-vendor mode indices, and 784 // check that they fail to configure 785 mSessionMockListener = spy(new BlockingSessionCallback()); 786 mSessionWaiter = mSessionMockListener.getStateWaiter(); 787 mCamera.createCustomCaptureSession(/*inputConfig*/null, outputs, 788 CameraDevice.SESSION_OPERATION_MODE_VENDOR_START - 1, mSessionMockListener, mHandler); 789 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 790 waitForSessionState(BlockingSessionCallback.SESSION_CONFIGURE_FAILED, 791 SESSION_CONFIGURE_TIMEOUT_MS); 792 793 mSessionMockListener = spy(new BlockingSessionCallback()); 794 mCamera.createCustomCaptureSession(/*inputConfig*/null, outputs, 795 CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED + 1, mSessionMockListener, 796 mHandler); 797 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 798 mSessionWaiter = mSessionMockListener.getStateWaiter(); 799 waitForSessionState(BlockingSessionCallback.SESSION_CONFIGURE_FAILED, 800 SESSION_CONFIGURE_TIMEOUT_MS); 801 802 } finally { 803 imageReader.close(); 804 mSession.close(); 805 } 806 } 807 808 /** 809 * Test session configuration. 810 */ testSessionConfiguration()811 public void testSessionConfiguration() throws Exception { 812 ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration> (); 813 outConfigs.add(new OutputConfiguration(new Size(1, 1), SurfaceTexture.class)); 814 outConfigs.add(new OutputConfiguration(new Size(2, 2), SurfaceTexture.class)); 815 mSessionMockListener = spy(new BlockingSessionCallback()); 816 HandlerExecutor executor = new HandlerExecutor(mHandler); 817 InputConfiguration inputConfig = new InputConfiguration(1, 1, ImageFormat.PRIVATE); 818 819 SessionConfiguration regularSessionConfig = new SessionConfiguration( 820 SessionConfiguration.SESSION_REGULAR, outConfigs, executor, mSessionMockListener); 821 822 SessionConfiguration highspeedSessionConfig = new SessionConfiguration( 823 SessionConfiguration.SESSION_HIGH_SPEED, outConfigs, executor, mSessionMockListener); 824 825 assertEquals("Session configuration output doesn't match", 826 regularSessionConfig.getOutputConfigurations(), outConfigs); 827 828 assertEquals("Session configuration output doesn't match", 829 regularSessionConfig.getOutputConfigurations(), 830 highspeedSessionConfig.getOutputConfigurations()); 831 832 assertEquals("Session configuration callback doesn't match", 833 regularSessionConfig.getStateCallback(), mSessionMockListener); 834 835 assertEquals("Session configuration callback doesn't match", 836 regularSessionConfig.getStateCallback(), 837 highspeedSessionConfig.getStateCallback()); 838 839 assertEquals("Session configuration executor doesn't match", 840 regularSessionConfig.getExecutor(), executor); 841 842 assertEquals("Session configuration handler doesn't match", 843 regularSessionConfig.getExecutor(), highspeedSessionConfig.getExecutor()); 844 845 regularSessionConfig.setInputConfiguration(inputConfig); 846 assertEquals("Session configuration input doesn't match", 847 regularSessionConfig.getInputConfiguration(), inputConfig); 848 849 try { 850 highspeedSessionConfig.setInputConfiguration(inputConfig); 851 fail("No exception for valid input configuration in hight speed session configuration"); 852 } catch (UnsupportedOperationException e) { 853 //expected 854 } 855 856 assertEquals("Session configuration input doesn't match", 857 highspeedSessionConfig.getInputConfiguration(), null); 858 859 for (int i = 0; i < mCameraIds.length; i++) { 860 try { 861 if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) { 862 Log.i(TAG, "Camera " + mCameraIds[i] + 863 " does not support color outputs, skipping"); 864 continue; 865 } 866 openDevice(mCameraIds[i], mCameraMockListener); 867 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 868 869 CaptureRequest.Builder builder = 870 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 871 CaptureRequest request = builder.build(); 872 873 regularSessionConfig.setSessionParameters(request); 874 highspeedSessionConfig.setSessionParameters(request); 875 876 assertEquals("Session configuration parameters doesn't match", 877 regularSessionConfig.getSessionParameters(), request); 878 879 assertEquals("Session configuration parameters doesn't match", 880 regularSessionConfig.getSessionParameters(), 881 highspeedSessionConfig.getSessionParameters()); 882 } 883 finally { 884 closeDevice(mCameraIds[i], mCameraMockListener); 885 } 886 } 887 } 888 889 /** 890 * Check for any state leakage in case of internal re-configure 891 */ testSessionParametersStateLeak()892 public void testSessionParametersStateLeak() throws Exception { 893 for (int i = 0; i < mCameraIds.length; i++) { 894 try { 895 if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) { 896 Log.i(TAG, "Camera " + mCameraIds[i] + 897 " does not support color outputs, skipping"); 898 continue; 899 } 900 openDevice(mCameraIds[i], mCameraMockListener); 901 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 902 903 testSessionParametersStateLeakByCamera(mCameraIds[i]); 904 } 905 finally { 906 closeDevice(mCameraIds[i], mCameraMockListener); 907 } 908 } 909 } 910 911 /** 912 * Check for any state leakage in case of internal re-configure 913 */ testSessionParametersStateLeakByCamera(String cameraId)914 private void testSessionParametersStateLeakByCamera(String cameraId) 915 throws Exception { 916 int outputFormat = ImageFormat.YUV_420_888; 917 Size outputSize = mOrderedPreviewSizes.get(0); 918 919 CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); 920 StreamConfigurationMap config = characteristics.get( 921 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 922 List <CaptureRequest.Key<?>> sessionKeys = characteristics.getAvailableSessionKeys(); 923 if (sessionKeys == null) { 924 return; 925 } 926 927 if (config.isOutputSupportedFor(outputFormat)) { 928 outputSize = config.getOutputSizes(outputFormat)[0]; 929 } else { 930 return; 931 } 932 933 ImageReader imageReader = ImageReader.newInstance(outputSize.getWidth(), 934 outputSize.getHeight(), outputFormat, /*maxImages*/3); 935 936 class OnReadyCaptureStateCallback extends CameraCaptureSession.StateCallback { 937 private ConditionVariable onReadyTriggeredCond = new ConditionVariable(); 938 private boolean onReadyTriggered = false; 939 940 @Override 941 public void onConfigured(CameraCaptureSession session) { 942 } 943 944 @Override 945 public void onConfigureFailed(CameraCaptureSession session) { 946 } 947 948 @Override 949 public synchronized void onReady(CameraCaptureSession session) { 950 onReadyTriggered = true; 951 onReadyTriggeredCond.open(); 952 } 953 954 public void waitForOnReady(long timeout) { 955 synchronized (this) { 956 if (onReadyTriggered) { 957 onReadyTriggered = false; 958 onReadyTriggeredCond.close(); 959 return; 960 } 961 } 962 963 if (onReadyTriggeredCond.block(timeout)) { 964 synchronized (this) { 965 onReadyTriggered = false; 966 onReadyTriggeredCond.close(); 967 } 968 } else { 969 throw new TimeoutRuntimeException("Unable to receive onReady after " 970 + timeout + "ms"); 971 } 972 } 973 } 974 975 OnReadyCaptureStateCallback sessionListener = new OnReadyCaptureStateCallback(); 976 977 try { 978 mSessionMockListener = spy(new BlockingSessionCallback(sessionListener)); 979 mSessionWaiter = mSessionMockListener.getStateWaiter(); 980 List<OutputConfiguration> outputs = new ArrayList<>(); 981 outputs.add(new OutputConfiguration(imageReader.getSurface())); 982 SessionConfiguration sessionConfig = new SessionConfiguration( 983 SessionConfiguration.SESSION_REGULAR, outputs, 984 new HandlerExecutor(mHandler), mSessionMockListener); 985 986 CaptureRequest.Builder builder = 987 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 988 builder.addTarget(imageReader.getSurface()); 989 CaptureRequest request = builder.build(); 990 991 sessionConfig.setSessionParameters(request); 992 mCamera.createCaptureSession(sessionConfig); 993 994 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 995 sessionListener.waitForOnReady(SESSION_CONFIGURE_TIMEOUT_MS); 996 997 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 998 ImageDropperListener imageListener = new ImageDropperListener(); 999 imageReader.setOnImageAvailableListener(imageListener, mHandler); 1000 1001 // To check the state leak condition, we need a capture request that has 1002 // at least one session pararameter value difference from the initial session 1003 // parameters configured above. Scan all available template types for the 1004 // required delta. 1005 CaptureRequest.Builder requestBuilder = null; 1006 ArrayList<CaptureRequest.Builder> builders = new ArrayList<CaptureRequest.Builder> (); 1007 if (mStaticInfo.isCapabilitySupported( 1008 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1009 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL)); 1010 } 1011 if (mStaticInfo.isCapabilitySupported( 1012 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING) 1013 || mStaticInfo.isCapabilitySupported( 1014 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING)) { 1015 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG)); 1016 } 1017 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT)); 1018 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)); 1019 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)); 1020 for (CaptureRequest.Key<?> key : sessionKeys) { 1021 Object sessionValue = builder.get(key); 1022 for (CaptureRequest.Builder newBuilder : builders) { 1023 Object currentValue = newBuilder.get(key); 1024 if ((sessionValue == null) && (currentValue == null)) { 1025 continue; 1026 } 1027 1028 if (((sessionValue == null) && (currentValue != null)) || 1029 ((sessionValue != null) && (currentValue == null)) || 1030 (!sessionValue.equals(currentValue))) { 1031 requestBuilder = newBuilder; 1032 break; 1033 } 1034 } 1035 1036 if (requestBuilder != null) { 1037 break; 1038 } 1039 } 1040 1041 if (requestBuilder != null) { 1042 requestBuilder.addTarget(imageReader.getSurface()); 1043 request = requestBuilder.build(); 1044 mSession.setRepeatingRequest(request, captureListener, mHandler); 1045 try { 1046 sessionListener.waitForOnReady(SESSION_CONFIGURE_TIMEOUT_MS); 1047 fail("Camera shouldn't switch to ready state when session parameters are " + 1048 "modified"); 1049 } catch (TimeoutRuntimeException e) { 1050 //expected 1051 } 1052 } 1053 } finally { 1054 imageReader.close(); 1055 mSession.close(); 1056 } 1057 } 1058 1059 /** 1060 * Verify creating a session with additional parameters. 1061 */ testCreateSessionWithParameters()1062 public void testCreateSessionWithParameters() throws Exception { 1063 for (int i = 0; i < mCameraIds.length; i++) { 1064 try { 1065 if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) { 1066 Log.i(TAG, "Camera " + mCameraIds[i] + 1067 " does not support color outputs, skipping"); 1068 continue; 1069 } 1070 openDevice(mCameraIds[i], mCameraMockListener); 1071 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 1072 1073 testCreateSessionWithParametersByCamera(mCameraIds[i], /*reprocessable*/false); 1074 testCreateSessionWithParametersByCamera(mCameraIds[i], /*reprocessable*/true); 1075 } 1076 finally { 1077 closeDevice(mCameraIds[i], mCameraMockListener); 1078 } 1079 } 1080 } 1081 1082 /** 1083 * Verify creating a session with additional parameters works 1084 */ testCreateSessionWithParametersByCamera(String cameraId, boolean reprocessable)1085 private void testCreateSessionWithParametersByCamera(String cameraId, boolean reprocessable) 1086 throws Exception { 1087 final int SESSION_TIMEOUT_MS = 1000; 1088 final int CAPTURE_TIMEOUT_MS = 3000; 1089 int inputFormat = ImageFormat.YUV_420_888; 1090 int outputFormat = inputFormat; 1091 Size outputSize = mOrderedPreviewSizes.get(0); 1092 Size inputSize = outputSize; 1093 InputConfiguration inputConfig = null; 1094 1095 if (VERBOSE) { 1096 Log.v(TAG, "Testing creating session with parameters for camera " + cameraId); 1097 } 1098 1099 CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); 1100 StreamConfigurationMap config = characteristics.get( 1101 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1102 1103 if (reprocessable) { 1104 //Pick a supported i/o format and size combination. 1105 //Ideally the input format should match the output. 1106 boolean found = false; 1107 int inputFormats [] = config.getInputFormats(); 1108 if (inputFormats.length == 0) { 1109 return; 1110 } 1111 1112 for (int inFormat : inputFormats) { 1113 int outputFormats [] = config.getValidOutputFormatsForInput(inFormat); 1114 for (int outFormat : outputFormats) { 1115 if (inFormat == outFormat) { 1116 inputFormat = inFormat; 1117 outputFormat = outFormat; 1118 found = true; 1119 break; 1120 } 1121 } 1122 if (found) { 1123 break; 1124 } 1125 } 1126 1127 //In case the above combination doesn't exist, pick the first first supported 1128 //pair. 1129 if (!found) { 1130 inputFormat = inputFormats[0]; 1131 int outputFormats [] = config.getValidOutputFormatsForInput(inputFormat); 1132 assertTrue("No output formats supported for input format: " + inputFormat, 1133 (outputFormats.length > 0)); 1134 outputFormat = outputFormats[0]; 1135 } 1136 1137 Size inputSizes[] = config.getInputSizes(inputFormat); 1138 Size outputSizes[] = config.getOutputSizes(outputFormat); 1139 assertTrue("No valid sizes supported for input format: " + inputFormat, 1140 (inputSizes.length > 0)); 1141 assertTrue("No valid sizes supported for output format: " + outputFormat, 1142 (outputSizes.length > 0)); 1143 1144 inputSize = inputSizes[0]; 1145 outputSize = outputSizes[0]; 1146 inputConfig = new InputConfiguration(inputSize.getWidth(), 1147 inputSize.getHeight(), inputFormat); 1148 } else { 1149 if (config.isOutputSupportedFor(outputFormat)) { 1150 outputSize = config.getOutputSizes(outputFormat)[0]; 1151 } else { 1152 return; 1153 } 1154 } 1155 1156 ImageReader imageReader = ImageReader.newInstance(outputSize.getWidth(), 1157 outputSize.getHeight(), outputFormat, /*maxImages*/1); 1158 1159 try { 1160 mSessionMockListener = spy(new BlockingSessionCallback()); 1161 mSessionWaiter = mSessionMockListener.getStateWaiter(); 1162 List<OutputConfiguration> outputs = new ArrayList<>(); 1163 outputs.add(new OutputConfiguration(imageReader.getSurface())); 1164 SessionConfiguration sessionConfig = new SessionConfiguration( 1165 SessionConfiguration.SESSION_REGULAR, outputs, 1166 new HandlerExecutor(mHandler), mSessionMockListener); 1167 1168 CaptureRequest.Builder builder = 1169 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1170 builder.addTarget(imageReader.getSurface()); 1171 CaptureRequest request = builder.build(); 1172 1173 sessionConfig.setInputConfiguration(inputConfig); 1174 sessionConfig.setSessionParameters(request); 1175 mCamera.createCaptureSession(sessionConfig); 1176 1177 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1178 1179 // Verify we can capture a frame with the session. 1180 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 1181 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1182 imageReader.setOnImageAvailableListener(imageListener, mHandler); 1183 1184 mSession.capture(request, captureListener, mHandler); 1185 captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS); 1186 imageListener.getImage(CAPTURE_TIMEOUT_MS).close(); 1187 } finally { 1188 imageReader.close(); 1189 mSession.close(); 1190 } 1191 } 1192 1193 /** 1194 * Verify creating sessions back to back and only the last one is valid for 1195 * submitting requests. 1196 */ testCreateSessionsByCamera(String cameraId)1197 private void testCreateSessionsByCamera(String cameraId) throws Exception { 1198 final int NUM_SESSIONS = 3; 1199 final int SESSION_TIMEOUT_MS = 1000; 1200 final int CAPTURE_TIMEOUT_MS = 3000; 1201 1202 if (VERBOSE) { 1203 Log.v(TAG, "Testing creating sessions for camera " + cameraId); 1204 } 1205 1206 Size yuvSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.YUV_420_888, 1207 /*bound*/null).get(0); 1208 Size jpegSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.JPEG, 1209 /*bound*/null).get(0); 1210 1211 // Create a list of image readers. JPEG for last one and YUV for the rest. 1212 List<ImageReader> imageReaders = new ArrayList<>(); 1213 List<CameraCaptureSession> allSessions = new ArrayList<>(); 1214 1215 try { 1216 for (int i = 0; i < NUM_SESSIONS - 1; i++) { 1217 imageReaders.add(ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(), 1218 ImageFormat.YUV_420_888, /*maxImages*/1)); 1219 } 1220 imageReaders.add(ImageReader.newInstance(jpegSize.getWidth(), jpegSize.getHeight(), 1221 ImageFormat.JPEG, /*maxImages*/1)); 1222 1223 // Create multiple sessions back to back. 1224 MultipleSessionCallback sessionListener = 1225 new MultipleSessionCallback(/*failOnConfigureFailed*/true); 1226 for (int i = 0; i < NUM_SESSIONS; i++) { 1227 List<Surface> outputs = new ArrayList<>(); 1228 outputs.add(imageReaders.get(i).getSurface()); 1229 mCamera.createCaptureSession(outputs, sessionListener, mHandler); 1230 } 1231 1232 // Verify we get onConfigured() for all sessions. 1233 allSessions = sessionListener.getAllSessions(NUM_SESSIONS, 1234 SESSION_TIMEOUT_MS * NUM_SESSIONS); 1235 assertEquals(String.format("Got %d sessions but configured %d sessions", 1236 allSessions.size(), NUM_SESSIONS), allSessions.size(), NUM_SESSIONS); 1237 1238 // Verify all sessions except the last one are closed. 1239 for (int i = 0; i < NUM_SESSIONS - 1; i++) { 1240 sessionListener.waitForSessionClose(allSessions.get(i), SESSION_TIMEOUT_MS); 1241 } 1242 1243 // Verify we can capture a frame with the last session. 1244 CameraCaptureSession session = allSessions.get(allSessions.size() - 1); 1245 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 1246 ImageReader reader = imageReaders.get(imageReaders.size() - 1); 1247 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 1248 reader.setOnImageAvailableListener(imageListener, mHandler); 1249 1250 CaptureRequest.Builder builder = 1251 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 1252 builder.addTarget(reader.getSurface()); 1253 CaptureRequest request = builder.build(); 1254 1255 session.capture(request, captureListener, mHandler); 1256 captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS); 1257 imageListener.getImage(CAPTURE_TIMEOUT_MS).close(); 1258 } finally { 1259 for (ImageReader reader : imageReaders) { 1260 reader.close(); 1261 } 1262 for (CameraCaptureSession session : allSessions) { 1263 session.close(); 1264 } 1265 } 1266 } 1267 prepareTestByCamera()1268 private void prepareTestByCamera() throws Exception { 1269 final int PREPARE_TIMEOUT_MS = 10000; 1270 1271 mSessionMockListener = spy(new BlockingSessionCallback()); 1272 1273 SurfaceTexture output1 = new SurfaceTexture(1); 1274 Surface output1Surface = new Surface(output1); 1275 SurfaceTexture output2 = new SurfaceTexture(2); 1276 Surface output2Surface = new Surface(output2); 1277 1278 ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration> (); 1279 outConfigs.add(new OutputConfiguration(output1Surface)); 1280 outConfigs.add(new OutputConfiguration(output2Surface)); 1281 SessionConfiguration sessionConfig = new SessionConfiguration( 1282 SessionConfiguration.SESSION_REGULAR, outConfigs, 1283 new HandlerExecutor(mHandler), mSessionMockListener); 1284 CaptureRequest.Builder r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1285 sessionConfig.setSessionParameters(r.build()); 1286 mCamera.createCaptureSession(sessionConfig); 1287 1288 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1289 1290 // Try basic prepare 1291 1292 mSession.prepare(output1Surface); 1293 1294 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 1295 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 1296 1297 // Should not complain if preparing already prepared stream 1298 1299 mSession.prepare(output1Surface); 1300 1301 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2)) 1302 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 1303 1304 // Check surface not included in session 1305 1306 SurfaceTexture output3 = new SurfaceTexture(3); 1307 Surface output3Surface = new Surface(output3); 1308 try { 1309 mSession.prepare(output3Surface); 1310 // Legacy camera prepare always succeed 1311 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1312 fail("Preparing surface not part of session must throw IllegalArgumentException"); 1313 } 1314 } catch (IllegalArgumentException e) { 1315 // expected 1316 } 1317 1318 // Ensure second prepare also works 1319 1320 mSession.prepare(output2Surface); 1321 1322 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 1323 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 1324 1325 // Use output1 1326 1327 r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1328 r.addTarget(output1Surface); 1329 1330 mSession.capture(r.build(), null, null); 1331 1332 try { 1333 mSession.prepare(output1Surface); 1334 // Legacy camera prepare always succeed 1335 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1336 fail("Preparing already-used surface must throw IllegalArgumentException"); 1337 } 1338 } catch (IllegalArgumentException e) { 1339 // expected 1340 } 1341 1342 // Create new session with outputs 1 and 3, ensure output1Surface still can't be prepared 1343 // again 1344 1345 mSessionMockListener = spy(new BlockingSessionCallback()); 1346 1347 ArrayList<Surface> outputSurfaces = new ArrayList<Surface>( 1348 Arrays.asList(output1Surface, output3Surface)); 1349 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 1350 1351 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1352 1353 try { 1354 mSession.prepare(output1Surface); 1355 // Legacy camera prepare always succeed 1356 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1357 fail("Preparing surface used in previous session must throw " + 1358 "IllegalArgumentException"); 1359 } 1360 } catch (IllegalArgumentException e) { 1361 // expected 1362 } 1363 1364 // Use output3, wait for result, then make sure prepare still doesn't work 1365 1366 r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1367 r.addTarget(output3Surface); 1368 1369 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1370 mSession.capture(r.build(), resultListener, mHandler); 1371 1372 resultListener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS); 1373 1374 try { 1375 mSession.prepare(output3Surface); 1376 // Legacy camera prepare always succeed 1377 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1378 fail("Preparing already-used surface must throw IllegalArgumentException"); 1379 } 1380 } catch (IllegalArgumentException e) { 1381 // expected 1382 } 1383 1384 // Create new session with outputs 1 and 2, ensure output2Surface can be prepared again 1385 1386 mSessionMockListener = spy(new BlockingSessionCallback()); 1387 1388 outputSurfaces = new ArrayList<>( 1389 Arrays.asList(output1Surface, output2Surface)); 1390 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 1391 1392 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1393 1394 mSession.prepare(output2Surface); 1395 1396 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 1397 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 1398 1399 try { 1400 mSession.prepare(output1Surface); 1401 // Legacy camera prepare always succeed 1402 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1403 fail("Preparing surface used in previous session must throw " + 1404 "IllegalArgumentException"); 1405 } 1406 } catch (IllegalArgumentException e) { 1407 // expected 1408 } 1409 1410 output1.release(); 1411 output2.release(); 1412 output3.release(); 1413 } 1414 prepareTestForSharedSurfacesByCamera()1415 private void prepareTestForSharedSurfacesByCamera() throws Exception { 1416 final int PREPARE_TIMEOUT_MS = 10000; 1417 1418 mSessionMockListener = spy(new BlockingSessionCallback()); 1419 1420 SurfaceTexture output1 = new SurfaceTexture(1); 1421 Surface output1Surface = new Surface(output1); 1422 SurfaceTexture output2 = new SurfaceTexture(2); 1423 Surface output2Surface = new Surface(output2); 1424 1425 List<Surface> outputSurfaces = new ArrayList<>( 1426 Arrays.asList(output1Surface, output2Surface)); 1427 OutputConfiguration surfaceSharedConfig = new OutputConfiguration( 1428 OutputConfiguration.SURFACE_GROUP_ID_NONE, output1Surface); 1429 surfaceSharedConfig.enableSurfaceSharing(); 1430 surfaceSharedConfig.addSurface(output2Surface); 1431 1432 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 1433 outputConfigurations.add(surfaceSharedConfig); 1434 mCamera.createCaptureSessionByOutputConfigurations( 1435 outputConfigurations, mSessionMockListener, mHandler); 1436 1437 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1438 1439 // Try prepare on output1Surface 1440 mSession.prepare(output1Surface); 1441 1442 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 1443 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 1444 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 1445 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 1446 1447 // Try prepare on output2Surface 1448 mSession.prepare(output2Surface); 1449 1450 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2)) 1451 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 1452 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2)) 1453 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 1454 1455 // Try prepare on output1Surface again 1456 mSession.prepare(output1Surface); 1457 1458 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(3)) 1459 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 1460 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(3)) 1461 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 1462 } 1463 invalidRequestCaptureTestByCamera()1464 private void invalidRequestCaptureTestByCamera() throws Exception { 1465 if (VERBOSE) Log.v(TAG, "invalidRequestCaptureTestByCamera"); 1466 1467 List<CaptureRequest> emptyRequests = new ArrayList<CaptureRequest>(); 1468 CaptureRequest.Builder requestBuilder = 1469 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1470 CaptureRequest unConfiguredRequest = requestBuilder.build(); 1471 List<CaptureRequest> unConfiguredRequests = new ArrayList<CaptureRequest>(); 1472 unConfiguredRequests.add(unConfiguredRequest); 1473 1474 try { 1475 // Test: CameraCaptureSession capture should throw IAE for null request. 1476 mSession.capture(/*request*/null, /*listener*/null, mHandler); 1477 mCollector.addMessage( 1478 "Session capture should throw IllegalArgumentException for null request"); 1479 } catch (IllegalArgumentException e) { 1480 // Pass. 1481 } 1482 1483 try { 1484 // Test: CameraCaptureSession capture should throw IAE for request 1485 // without surface configured. 1486 mSession.capture(unConfiguredRequest, /*listener*/null, mHandler); 1487 mCollector.addMessage("Session capture should throw " + 1488 "IllegalArgumentException for request without surface configured"); 1489 } catch (IllegalArgumentException e) { 1490 // Pass. 1491 } 1492 1493 try { 1494 // Test: CameraCaptureSession setRepeatingRequest should throw IAE for null request. 1495 mSession.setRepeatingRequest(/*request*/null, /*listener*/null, mHandler); 1496 mCollector.addMessage("Session setRepeatingRequest should throw " + 1497 "IllegalArgumentException for null request"); 1498 } catch (IllegalArgumentException e) { 1499 // Pass. 1500 } 1501 1502 try { 1503 // Test: CameraCaptureSession setRepeatingRequest should throw IAE for for request 1504 // without surface configured. 1505 mSession.setRepeatingRequest(unConfiguredRequest, /*listener*/null, mHandler); 1506 mCollector.addMessage("Capture zero burst should throw IllegalArgumentException " + 1507 "for request without surface configured"); 1508 } catch (IllegalArgumentException e) { 1509 // Pass. 1510 } 1511 1512 try { 1513 // Test: CameraCaptureSession captureBurst should throw IAE for null request list. 1514 mSession.captureBurst(/*requests*/null, /*listener*/null, mHandler); 1515 mCollector.addMessage("Session captureBurst should throw " + 1516 "IllegalArgumentException for null request list"); 1517 } catch (IllegalArgumentException e) { 1518 // Pass. 1519 } 1520 1521 try { 1522 // Test: CameraCaptureSession captureBurst should throw IAE for empty request list. 1523 mSession.captureBurst(emptyRequests, /*listener*/null, mHandler); 1524 mCollector.addMessage("Session captureBurst should throw " + 1525 " IllegalArgumentException for empty request list"); 1526 } catch (IllegalArgumentException e) { 1527 // Pass. 1528 } 1529 1530 try { 1531 // Test: CameraCaptureSession captureBurst should throw IAE for request 1532 // without surface configured. 1533 mSession.captureBurst(unConfiguredRequests, /*listener*/null, mHandler); 1534 fail("Session captureBurst should throw IllegalArgumentException " + 1535 "for null request list"); 1536 } catch (IllegalArgumentException e) { 1537 // Pass. 1538 } 1539 1540 try { 1541 // Test: CameraCaptureSession setRepeatingBurst should throw IAE for null request list. 1542 mSession.setRepeatingBurst(/*requests*/null, /*listener*/null, mHandler); 1543 mCollector.addMessage("Session setRepeatingBurst should throw " + 1544 "IllegalArgumentException for null request list"); 1545 } catch (IllegalArgumentException e) { 1546 // Pass. 1547 } 1548 1549 try { 1550 // Test: CameraCaptureSession setRepeatingBurst should throw IAE for empty request list. 1551 mSession.setRepeatingBurst(emptyRequests, /*listener*/null, mHandler); 1552 mCollector.addMessage("Session setRepeatingBurst should throw " + 1553 "IllegalArgumentException for empty request list"); 1554 } catch (IllegalArgumentException e) { 1555 // Pass. 1556 } 1557 1558 try { 1559 // Test: CameraCaptureSession setRepeatingBurst should throw IAE for request 1560 // without surface configured. 1561 mSession.setRepeatingBurst(unConfiguredRequests, /*listener*/null, mHandler); 1562 mCollector.addMessage("Session setRepeatingBurst should throw " + 1563 "IllegalArgumentException for request without surface configured"); 1564 } catch (IllegalArgumentException e) { 1565 // Pass. 1566 } 1567 } 1568 1569 private class IsCaptureResultNotEmpty 1570 implements ArgumentMatcher<TotalCaptureResult> { 1571 @Override matches(TotalCaptureResult result)1572 public boolean matches(TotalCaptureResult result) { 1573 /** 1574 * Do the simple verification here. Only verify the timestamp for now. 1575 * TODO: verify more required capture result metadata fields. 1576 */ 1577 Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP); 1578 if (timeStamp != null && timeStamp.longValue() > 0L) { 1579 return true; 1580 } 1581 return false; 1582 } 1583 } 1584 1585 /** 1586 * Run capture test with different test configurations. 1587 * 1588 * @param burst If the test uses {@link CameraCaptureSession#captureBurst} or 1589 * {@link CameraCaptureSession#setRepeatingBurst} to capture the burst. 1590 * @param repeating If the test uses {@link CameraCaptureSession#setRepeatingBurst} or 1591 * {@link CameraCaptureSession#setRepeatingRequest} for repeating capture. 1592 * @param abort If the test uses {@link CameraCaptureSession#abortCaptures} to stop the 1593 * repeating capture. It has no effect if repeating is false. 1594 * @param useExecutor If the test uses {@link java.util.concurrent.Executor} instead of 1595 * {@link android.os.Handler} for callback invocation. 1596 */ runCaptureTest(boolean burst, boolean repeating, boolean abort, boolean useExecutor)1597 private void runCaptureTest(boolean burst, boolean repeating, boolean abort, 1598 boolean useExecutor) throws Exception { 1599 for (int i = 0; i < mCameraIds.length; i++) { 1600 try { 1601 openDevice(mCameraIds[i], mCameraMockListener); 1602 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 1603 1604 prepareCapture(); 1605 1606 if (!burst) { 1607 // Test: that a single capture of each template type succeeds. 1608 for (int j = 0; j < sTemplates.length; j++) { 1609 // Skip video snapshots for LEGACY mode 1610 if (mStaticInfo.isHardwareLevelLegacy() && 1611 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 1612 continue; 1613 } 1614 // Skip non-PREVIEW templates for non-color output 1615 if (!mStaticInfo.isColorOutputSupported() && 1616 sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) { 1617 continue; 1618 } 1619 1620 captureSingleShot(mCameraIds[i], sTemplates[j], repeating, abort, 1621 useExecutor); 1622 } 1623 } 1624 else { 1625 // Test: burst of one shot 1626 captureBurstShot(mCameraIds[i], sTemplates, 1, repeating, abort, useExecutor); 1627 1628 int template = mStaticInfo.isColorOutputSupported() ? 1629 CameraDevice.TEMPLATE_STILL_CAPTURE : 1630 CameraDevice.TEMPLATE_PREVIEW; 1631 int[] templates = new int[] { 1632 template, 1633 template, 1634 template, 1635 template, 1636 template 1637 }; 1638 1639 // Test: burst of 5 shots of the same template type 1640 captureBurstShot(mCameraIds[i], templates, templates.length, repeating, abort, 1641 useExecutor); 1642 1643 if (mStaticInfo.isColorOutputSupported()) { 1644 // Test: burst of 6 shots of different template types 1645 captureBurstShot(mCameraIds[i], sTemplates, sTemplates.length, repeating, 1646 abort, useExecutor); 1647 } 1648 } 1649 verify(mCameraMockListener, never()) 1650 .onError( 1651 any(CameraDevice.class), 1652 anyInt()); 1653 } catch (Exception e) { 1654 mCollector.addError(e); 1655 } finally { 1656 try { 1657 closeSession(); 1658 } catch (Exception e) { 1659 mCollector.addError(e); 1660 }finally { 1661 closeDevice(mCameraIds[i], mCameraMockListener); 1662 } 1663 } 1664 } 1665 } 1666 captureSingleShot( String id, int template, boolean repeating, boolean abort, boolean useExecutor)1667 private void captureSingleShot( 1668 String id, 1669 int template, 1670 boolean repeating, boolean abort, boolean useExecutor) throws Exception { 1671 1672 assertEquals("Bad initial state for preparing to capture", 1673 mLatestSessionState, SESSION_READY); 1674 1675 final Executor executor = useExecutor ? new HandlerExecutor(mHandler) : null; 1676 CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(template); 1677 assertNotNull("Failed to create capture request", requestBuilder); 1678 requestBuilder.addTarget(mReaderSurface); 1679 CameraCaptureSession.CaptureCallback mockCaptureCallback = 1680 mock(CameraCaptureSession.CaptureCallback.class); 1681 1682 if (VERBOSE) { 1683 Log.v(TAG, String.format("Capturing shot for device %s, template %d", 1684 id, template)); 1685 } 1686 1687 if (executor != null) { 1688 startCapture(requestBuilder.build(), repeating, mockCaptureCallback, executor); 1689 } else { 1690 startCapture(requestBuilder.build(), repeating, mockCaptureCallback, mHandler); 1691 } 1692 waitForSessionState(SESSION_ACTIVE, SESSION_ACTIVE_TIMEOUT_MS); 1693 1694 int expectedCaptureResultCount = repeating ? REPEATING_CAPTURE_EXPECTED_RESULT_COUNT : 1; 1695 verifyCaptureResults(mockCaptureCallback, expectedCaptureResultCount); 1696 1697 if (repeating) { 1698 if (abort) { 1699 mSession.abortCaptures(); 1700 // Have to make sure abort and new requests aren't interleave together. 1701 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1702 1703 // Capture a single capture, and verify the result. 1704 SimpleCaptureCallback resultCallback = new SimpleCaptureCallback(); 1705 CaptureRequest singleRequest = requestBuilder.build(); 1706 if (executor != null) { 1707 mSession.captureSingleRequest(singleRequest, executor, resultCallback); 1708 } else { 1709 mSession.capture(singleRequest, resultCallback, mHandler); 1710 } 1711 resultCallback.getCaptureResultForRequest(singleRequest, CAPTURE_RESULT_TIMEOUT_MS); 1712 1713 // Resume the repeating, and verify that results are returned. 1714 if (executor != null) { 1715 mSession.setSingleRepeatingRequest(singleRequest, executor, resultCallback); 1716 } else { 1717 mSession.setRepeatingRequest(singleRequest, resultCallback, mHandler); 1718 } 1719 for (int i = 0; i < REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; i++) { 1720 resultCallback.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS); 1721 } 1722 } 1723 mSession.stopRepeating(); 1724 } 1725 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1726 } 1727 captureBurstShot( String id, int[] templates, int len, boolean repeating, boolean abort, boolean useExecutor)1728 private void captureBurstShot( 1729 String id, 1730 int[] templates, 1731 int len, 1732 boolean repeating, 1733 boolean abort, boolean useExecutor) throws Exception { 1734 1735 assertEquals("Bad initial state for preparing to capture", 1736 mLatestSessionState, SESSION_READY); 1737 1738 assertTrue("Invalid args to capture function", len <= templates.length); 1739 List<CaptureRequest> requests = new ArrayList<CaptureRequest>(); 1740 List<CaptureRequest> postAbortRequests = new ArrayList<CaptureRequest>(); 1741 final Executor executor = useExecutor ? new HandlerExecutor(mHandler) : null; 1742 for (int i = 0; i < len; i++) { 1743 // Skip video snapshots for LEGACY mode 1744 if (mStaticInfo.isHardwareLevelLegacy() && 1745 templates[i] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 1746 continue; 1747 } 1748 // Skip non-PREVIEW templates for non-color outpu 1749 if (!mStaticInfo.isColorOutputSupported() && 1750 templates[i] != CameraDevice.TEMPLATE_PREVIEW) { 1751 continue; 1752 } 1753 1754 CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(templates[i]); 1755 assertNotNull("Failed to create capture request", requestBuilder); 1756 requestBuilder.addTarget(mReaderSurface); 1757 requests.add(requestBuilder.build()); 1758 if (abort) { 1759 postAbortRequests.add(requestBuilder.build()); 1760 } 1761 } 1762 CameraCaptureSession.CaptureCallback mockCaptureCallback = 1763 mock(CameraCaptureSession.CaptureCallback.class); 1764 1765 if (VERBOSE) { 1766 Log.v(TAG, String.format("Capturing burst shot for device %s", id)); 1767 } 1768 1769 if (!repeating) { 1770 if (executor != null) { 1771 mSession.captureBurstRequests(requests, executor, mockCaptureCallback); 1772 } else { 1773 mSession.captureBurst(requests, mockCaptureCallback, mHandler); 1774 } 1775 } 1776 else { 1777 if (executor != null) { 1778 mSession.setRepeatingBurstRequests(requests, executor, mockCaptureCallback); 1779 } else { 1780 mSession.setRepeatingBurst(requests, mockCaptureCallback, mHandler); 1781 } 1782 } 1783 waitForSessionState(SESSION_ACTIVE, SESSION_READY_TIMEOUT_MS); 1784 1785 int expectedResultCount = requests.size(); 1786 if (repeating) { 1787 expectedResultCount *= REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; 1788 } 1789 1790 verifyCaptureResults(mockCaptureCallback, expectedResultCount); 1791 1792 if (repeating) { 1793 if (abort) { 1794 mSession.abortCaptures(); 1795 // Have to make sure abort and new requests aren't interleave together. 1796 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1797 1798 // Capture a burst of captures, and verify the results. 1799 SimpleCaptureCallback resultCallback = new SimpleCaptureCallback(); 1800 if (executor != null) { 1801 mSession.captureBurstRequests(postAbortRequests, executor, resultCallback); 1802 } else { 1803 mSession.captureBurst(postAbortRequests, resultCallback, mHandler); 1804 } 1805 // Verify that the results are returned. 1806 for (int i = 0; i < postAbortRequests.size(); i++) { 1807 resultCallback.getCaptureResultForRequest( 1808 postAbortRequests.get(i), CAPTURE_RESULT_TIMEOUT_MS); 1809 } 1810 1811 // Resume the repeating, and verify that results are returned. 1812 if (executor != null) { 1813 mSession.setRepeatingBurstRequests(requests, executor, resultCallback); 1814 } else { 1815 mSession.setRepeatingBurst(requests, resultCallback, mHandler); 1816 } 1817 for (int i = 0; i < REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; i++) { 1818 resultCallback.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS); 1819 } 1820 } 1821 mSession.stopRepeating(); 1822 } 1823 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1824 } 1825 1826 /** 1827 * Precondition: Device must be in known OPENED state (has been waited for). 1828 * 1829 * <p>Creates a new capture session and waits until it is in the {@code SESSION_READY} state. 1830 * </p> 1831 * 1832 * <p>Any existing capture session will be closed as a result of calling this.</p> 1833 * */ prepareCapture()1834 private void prepareCapture() throws Exception { 1835 if (VERBOSE) Log.v(TAG, "prepareCapture"); 1836 1837 assertTrue("Bad initial state for preparing to capture", 1838 mLatestDeviceState == STATE_OPENED); 1839 1840 if (mSession != null) { 1841 if (VERBOSE) Log.v(TAG, "prepareCapture - closing existing session"); 1842 closeSession(); 1843 } 1844 1845 // Create a new session listener each time, it's not reusable across cameras 1846 mSessionMockListener = spy(new BlockingSessionCallback()); 1847 mSessionWaiter = mSessionMockListener.getStateWaiter(); 1848 1849 if (!mStaticInfo.isColorOutputSupported()) { 1850 createDefaultImageReader(getMaxDepthSize(mCamera.getId(), mCameraManager), 1851 ImageFormat.DEPTH16, MAX_NUM_IMAGES, new ImageDropperListener()); 1852 } else { 1853 createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888, MAX_NUM_IMAGES, 1854 new ImageDropperListener()); 1855 } 1856 1857 List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(mReaderSurface)); 1858 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 1859 1860 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1861 waitForSessionState(SESSION_CONFIGURED, SESSION_CONFIGURE_TIMEOUT_MS); 1862 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1863 } 1864 waitForDeviceState(int state, long timeoutMs)1865 private void waitForDeviceState(int state, long timeoutMs) { 1866 mCameraMockListener.waitForState(state, timeoutMs); 1867 mLatestDeviceState = state; 1868 } 1869 waitForSessionState(int state, long timeoutMs)1870 private void waitForSessionState(int state, long timeoutMs) { 1871 mSessionWaiter.waitForState(state, timeoutMs); 1872 mLatestSessionState = state; 1873 } 1874 verifyCaptureResults( CameraCaptureSession.CaptureCallback mockListener, int expectResultCount)1875 private void verifyCaptureResults( 1876 CameraCaptureSession.CaptureCallback mockListener, 1877 int expectResultCount) { 1878 final int TIMEOUT_PER_RESULT_MS = 2000; 1879 // Should receive expected number of capture results. 1880 verify(mockListener, 1881 timeout(TIMEOUT_PER_RESULT_MS * expectResultCount).atLeast(expectResultCount)) 1882 .onCaptureCompleted( 1883 eq(mSession), 1884 isA(CaptureRequest.class), 1885 argThat(new IsCaptureResultNotEmpty())); 1886 // Should not receive any capture failed callbacks. 1887 verify(mockListener, never()) 1888 .onCaptureFailed( 1889 eq(mSession), 1890 isA(CaptureRequest.class), 1891 isA(CaptureFailure.class)); 1892 // Should receive expected number of capture shutter calls 1893 verify(mockListener, 1894 atLeast(expectResultCount)) 1895 .onCaptureStarted( 1896 eq(mSession), 1897 isA(CaptureRequest.class), 1898 anyLong(), 1899 anyLong()); 1900 } 1901 checkFpsRange(CaptureRequest.Builder request, int template, CameraCharacteristics props)1902 private void checkFpsRange(CaptureRequest.Builder request, int template, 1903 CameraCharacteristics props) { 1904 CaptureRequest.Key<Range<Integer>> fpsRangeKey = CONTROL_AE_TARGET_FPS_RANGE; 1905 Range<Integer> fpsRange; 1906 if ((fpsRange = mCollector.expectKeyValueNotNull(request, fpsRangeKey)) == null) { 1907 return; 1908 } 1909 1910 int minFps = fpsRange.getLower(); 1911 int maxFps = fpsRange.getUpper(); 1912 Range<Integer>[] availableFpsRange = props 1913 .get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 1914 boolean foundRange = false; 1915 for (int i = 0; i < availableFpsRange.length; i += 1) { 1916 if (minFps == availableFpsRange[i].getLower() 1917 && maxFps == availableFpsRange[i].getUpper()) { 1918 foundRange = true; 1919 break; 1920 } 1921 } 1922 if (!foundRange) { 1923 mCollector.addMessage(String.format("Unable to find the fps range (%d, %d)", 1924 minFps, maxFps)); 1925 return; 1926 } 1927 1928 1929 if (template != CameraDevice.TEMPLATE_MANUAL && 1930 template != CameraDevice.TEMPLATE_STILL_CAPTURE) { 1931 if (maxFps < MIN_FPS_REQUIRED_FOR_STREAMING) { 1932 mCollector.addMessage("Max fps should be at least " 1933 + MIN_FPS_REQUIRED_FOR_STREAMING); 1934 return; 1935 } 1936 1937 // Relax framerate constraints on legacy mode 1938 if (mStaticInfo.isHardwareLevelAtLeastLimited()) { 1939 // Need give fixed frame rate for video recording template. 1940 if (template == CameraDevice.TEMPLATE_RECORD) { 1941 if (maxFps != minFps) { 1942 mCollector.addMessage("Video recording frame rate should be fixed"); 1943 } 1944 } 1945 } 1946 } 1947 } 1948 checkAfMode(CaptureRequest.Builder request, int template, CameraCharacteristics props)1949 private void checkAfMode(CaptureRequest.Builder request, int template, 1950 CameraCharacteristics props) { 1951 boolean hasFocuser = props.getKeys().contains(CameraCharacteristics. 1952 LENS_INFO_MINIMUM_FOCUS_DISTANCE) && 1953 (props.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) > 0f); 1954 1955 if (!hasFocuser) { 1956 return; 1957 } 1958 1959 int targetAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO; 1960 int[] availableAfMode = props.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); 1961 if (template == CameraDevice.TEMPLATE_PREVIEW || 1962 template == CameraDevice.TEMPLATE_STILL_CAPTURE || 1963 template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG) { 1964 // Default to CONTINUOUS_PICTURE if it is available, otherwise AUTO. 1965 for (int i = 0; i < availableAfMode.length; i++) { 1966 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) { 1967 targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE; 1968 break; 1969 } 1970 } 1971 } else if (template == CameraDevice.TEMPLATE_RECORD || 1972 template == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 1973 // Default to CONTINUOUS_VIDEO if it is available, otherwise AUTO. 1974 for (int i = 0; i < availableAfMode.length; i++) { 1975 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) { 1976 targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO; 1977 break; 1978 } 1979 } 1980 } else if (template == CameraDevice.TEMPLATE_MANUAL) { 1981 targetAfMode = CaptureRequest.CONTROL_AF_MODE_OFF; 1982 } 1983 1984 mCollector.expectKeyValueEquals(request, CONTROL_AF_MODE, targetAfMode); 1985 if (mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FOCUS_DISTANCE)) { 1986 mCollector.expectKeyValueNotNull(request, LENS_FOCUS_DISTANCE); 1987 } 1988 } 1989 checkAntiBandingMode(CaptureRequest.Builder request, int template)1990 private void checkAntiBandingMode(CaptureRequest.Builder request, int template) { 1991 if (template == CameraDevice.TEMPLATE_MANUAL) { 1992 return; 1993 } 1994 1995 if (!mStaticInfo.isColorOutputSupported()) return; 1996 1997 List<Integer> availableAntiBandingModes = 1998 Arrays.asList(toObject(mStaticInfo.getAeAvailableAntiBandingModesChecked())); 1999 2000 if (availableAntiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO)) { 2001 mCollector.expectKeyValueEquals(request, CONTROL_AE_ANTIBANDING_MODE, 2002 CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO); 2003 } else { 2004 mCollector.expectKeyValueIsIn(request, CONTROL_AE_ANTIBANDING_MODE, 2005 CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ, 2006 CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ); 2007 } 2008 } 2009 2010 /** 2011 * <p>Check if 3A metering settings are "up to HAL" in request template</p> 2012 * 2013 * <p>This function doesn't fail the test immediately, it updates the 2014 * test pass/fail status and appends the failure message to the error collector each key.</p> 2015 * 2016 * @param regions The metering rectangles to be checked 2017 */ checkMeteringRect(MeteringRectangle[] regions)2018 private void checkMeteringRect(MeteringRectangle[] regions) { 2019 if (regions == null) { 2020 return; 2021 } 2022 mCollector.expectNotEquals("Number of metering region should not be 0", 0, regions.length); 2023 for (int i = 0; i < regions.length; i++) { 2024 mCollector.expectEquals("Default metering regions should have all zero weight", 2025 0, regions[i].getMeteringWeight()); 2026 } 2027 } 2028 2029 /** 2030 * <p>Check if the request settings are suitable for a given request template.</p> 2031 * 2032 * <p>This function doesn't fail the test immediately, it updates the 2033 * test pass/fail status and appends the failure message to the error collector each key.</p> 2034 * 2035 * @param request The request to be checked. 2036 * @param template The capture template targeted by this request. 2037 * @param props The CameraCharacteristics this request is checked against with. 2038 */ checkRequestForTemplate(CaptureRequest.Builder request, int template, CameraCharacteristics props)2039 private void checkRequestForTemplate(CaptureRequest.Builder request, int template, 2040 CameraCharacteristics props) { 2041 Integer hwLevel = props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 2042 boolean isExternalCamera = (hwLevel == 2043 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 2044 2045 // 3A settings--AE/AWB/AF. 2046 Integer maxRegionsAeVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE); 2047 int maxRegionsAe = maxRegionsAeVal != null ? maxRegionsAeVal : 0; 2048 Integer maxRegionsAwbVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB); 2049 int maxRegionsAwb = maxRegionsAwbVal != null ? maxRegionsAwbVal : 0; 2050 Integer maxRegionsAfVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF); 2051 int maxRegionsAf = maxRegionsAfVal != null ? maxRegionsAfVal : 0; 2052 2053 checkFpsRange(request, template, props); 2054 2055 checkAfMode(request, template, props); 2056 checkAntiBandingMode(request, template); 2057 2058 if (template == CameraDevice.TEMPLATE_MANUAL) { 2059 mCollector.expectKeyValueEquals(request, CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF); 2060 mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE, 2061 CaptureRequest.CONTROL_AE_MODE_OFF); 2062 mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE, 2063 CaptureRequest.CONTROL_AWB_MODE_OFF); 2064 } else { 2065 mCollector.expectKeyValueEquals(request, CONTROL_MODE, 2066 CaptureRequest.CONTROL_MODE_AUTO); 2067 if (mStaticInfo.isColorOutputSupported()) { 2068 mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE, 2069 CaptureRequest.CONTROL_AE_MODE_ON); 2070 mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0); 2071 mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER, 2072 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 2073 // if AE lock is not supported, expect the control key to be non-exist or false 2074 if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) { 2075 mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false); 2076 } 2077 2078 mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER, 2079 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 2080 2081 mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE, 2082 CaptureRequest.CONTROL_AWB_MODE_AUTO); 2083 // if AWB lock is not supported, expect the control key to be non-exist or false 2084 if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) { 2085 mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false); 2086 } 2087 2088 // Check 3A regions. 2089 if (VERBOSE) { 2090 Log.v(TAG, String.format("maxRegions is: {AE: %s, AWB: %s, AF: %s}", 2091 maxRegionsAe, maxRegionsAwb, maxRegionsAf)); 2092 } 2093 if (maxRegionsAe > 0) { 2094 mCollector.expectKeyValueNotNull(request, CONTROL_AE_REGIONS); 2095 MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS); 2096 checkMeteringRect(aeRegions); 2097 } 2098 if (maxRegionsAwb > 0) { 2099 mCollector.expectKeyValueNotNull(request, CONTROL_AWB_REGIONS); 2100 MeteringRectangle[] awbRegions = request.get(CONTROL_AWB_REGIONS); 2101 checkMeteringRect(awbRegions); 2102 } 2103 if (maxRegionsAf > 0) { 2104 mCollector.expectKeyValueNotNull(request, CONTROL_AF_REGIONS); 2105 MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS); 2106 checkMeteringRect(afRegions); 2107 } 2108 } 2109 } 2110 2111 // Sensor settings. 2112 2113 mCollector.expectEquals("Lens aperture must be present in request if available apertures " + 2114 "are present in metadata, and vice-versa.", 2115 mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES), 2116 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_APERTURE)); 2117 if (mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES)) { 2118 float[] availableApertures = 2119 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES); 2120 if (availableApertures.length > 1) { 2121 mCollector.expectKeyValueNotNull(request, LENS_APERTURE); 2122 } 2123 } 2124 2125 mCollector.expectEquals("Lens filter density must be present in request if available " + 2126 "filter densities are present in metadata, and vice-versa.", 2127 mStaticInfo.areKeysAvailable(CameraCharacteristics. 2128 LENS_INFO_AVAILABLE_FILTER_DENSITIES), 2129 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FILTER_DENSITY)); 2130 if (mStaticInfo.areKeysAvailable(CameraCharacteristics. 2131 LENS_INFO_AVAILABLE_FILTER_DENSITIES)) { 2132 float[] availableFilters = 2133 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES); 2134 if (availableFilters.length > 1) { 2135 mCollector.expectKeyValueNotNull(request, LENS_FILTER_DENSITY); 2136 } 2137 } 2138 2139 2140 if (!isExternalCamera) { 2141 float[] availableFocalLen = 2142 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); 2143 if (availableFocalLen.length > 1) { 2144 mCollector.expectKeyValueNotNull(request, LENS_FOCAL_LENGTH); 2145 } 2146 } 2147 2148 2149 mCollector.expectEquals("Lens optical stabilization must be present in request if " + 2150 "available optical stabilizations are present in metadata, and vice-versa.", 2151 mStaticInfo.areKeysAvailable(CameraCharacteristics. 2152 LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION), 2153 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE)); 2154 if (mStaticInfo.areKeysAvailable(CameraCharacteristics. 2155 LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) { 2156 int[] availableOIS = 2157 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION); 2158 if (availableOIS.length > 1) { 2159 mCollector.expectKeyValueNotNull(request, LENS_OPTICAL_STABILIZATION_MODE); 2160 } 2161 } 2162 2163 if (mStaticInfo.areKeysAvailable(SENSOR_TEST_PATTERN_MODE)) { 2164 mCollector.expectKeyValueEquals(request, SENSOR_TEST_PATTERN_MODE, 2165 CaptureRequest.SENSOR_TEST_PATTERN_MODE_OFF); 2166 } 2167 2168 if (mStaticInfo.areKeysAvailable(BLACK_LEVEL_LOCK)) { 2169 mCollector.expectKeyValueEquals(request, BLACK_LEVEL_LOCK, false); 2170 } 2171 2172 if (mStaticInfo.areKeysAvailable(SENSOR_FRAME_DURATION)) { 2173 mCollector.expectKeyValueNotNull(request, SENSOR_FRAME_DURATION); 2174 } 2175 2176 if (mStaticInfo.areKeysAvailable(SENSOR_EXPOSURE_TIME)) { 2177 mCollector.expectKeyValueNotNull(request, SENSOR_EXPOSURE_TIME); 2178 } 2179 2180 if (mStaticInfo.areKeysAvailable(SENSOR_SENSITIVITY)) { 2181 mCollector.expectKeyValueNotNull(request, SENSOR_SENSITIVITY); 2182 } 2183 2184 // ISP-processing settings. 2185 if (mStaticInfo.isColorOutputSupported()) { 2186 mCollector.expectKeyValueEquals( 2187 request, STATISTICS_FACE_DETECT_MODE, 2188 CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF); 2189 mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); 2190 } 2191 2192 List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked(); 2193 if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) { 2194 // If the device doesn't support RAW, all template should have OFF as default. 2195 if (!availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2196 mCollector.expectKeyValueEquals( 2197 request, STATISTICS_LENS_SHADING_MAP_MODE, 2198 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF); 2199 } 2200 } 2201 2202 boolean supportReprocessing = 2203 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) || 2204 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 2205 2206 2207 if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) { 2208 2209 // Ok with either FAST or HIGH_QUALITY 2210 if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_MODE)) { 2211 mCollector.expectKeyValueNotEquals( 2212 request, COLOR_CORRECTION_MODE, 2213 CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX); 2214 } 2215 2216 // Edge enhancement, noise reduction and aberration correction modes. 2217 mCollector.expectEquals("Edge mode must be present in request if " + 2218 "available edge modes are present in metadata, and vice-versa.", 2219 mStaticInfo.areKeysAvailable(CameraCharacteristics. 2220 EDGE_AVAILABLE_EDGE_MODES), 2221 mStaticInfo.areKeysAvailable(CaptureRequest.EDGE_MODE)); 2222 if (mStaticInfo.areKeysAvailable(EDGE_MODE)) { 2223 List<Integer> availableEdgeModes = 2224 Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked())); 2225 // Don't need check fast as fast or high quality must be both present or both not. 2226 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY)) { 2227 mCollector.expectKeyValueEquals(request, EDGE_MODE, 2228 CaptureRequest.EDGE_MODE_HIGH_QUALITY); 2229 } else { 2230 mCollector.expectKeyValueEquals(request, EDGE_MODE, 2231 CaptureRequest.EDGE_MODE_OFF); 2232 } 2233 } 2234 if (mStaticInfo.areKeysAvailable(SHADING_MODE)) { 2235 List<Integer> availableShadingModes = 2236 Arrays.asList(toObject(mStaticInfo.getAvailableShadingModesChecked())); 2237 mCollector.expectKeyValueEquals(request, SHADING_MODE, 2238 CaptureRequest.SHADING_MODE_HIGH_QUALITY); 2239 } 2240 2241 mCollector.expectEquals("Noise reduction mode must be present in request if " + 2242 "available noise reductions are present in metadata, and vice-versa.", 2243 mStaticInfo.areKeysAvailable(CameraCharacteristics. 2244 NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES), 2245 mStaticInfo.areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE)); 2246 if (mStaticInfo.areKeysAvailable( 2247 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) { 2248 List<Integer> availableNoiseReductionModes = 2249 Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked())); 2250 // Don't need check fast as fast or high quality must be both present or both not. 2251 if (availableNoiseReductionModes 2252 .contains(CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) { 2253 mCollector.expectKeyValueEquals( 2254 request, NOISE_REDUCTION_MODE, 2255 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 2256 } else { 2257 mCollector.expectKeyValueEquals( 2258 request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF); 2259 } 2260 } 2261 2262 mCollector.expectEquals("Hot pixel mode must be present in request if " + 2263 "available hot pixel modes are present in metadata, and vice-versa.", 2264 mStaticInfo.areKeysAvailable(CameraCharacteristics. 2265 HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES), 2266 mStaticInfo.areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE)); 2267 2268 if (mStaticInfo.areKeysAvailable(HOT_PIXEL_MODE)) { 2269 List<Integer> availableHotPixelModes = 2270 Arrays.asList(toObject( 2271 mStaticInfo.getAvailableHotPixelModesChecked())); 2272 if (availableHotPixelModes 2273 .contains(CaptureRequest.HOT_PIXEL_MODE_HIGH_QUALITY)) { 2274 mCollector.expectKeyValueEquals( 2275 request, HOT_PIXEL_MODE, 2276 CaptureRequest.HOT_PIXEL_MODE_HIGH_QUALITY); 2277 } else { 2278 mCollector.expectKeyValueEquals( 2279 request, HOT_PIXEL_MODE, CaptureRequest.HOT_PIXEL_MODE_OFF); 2280 } 2281 } 2282 2283 boolean supportAvailableAberrationModes = mStaticInfo.areKeysAvailable( 2284 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES); 2285 boolean supportAberrationRequestKey = mStaticInfo.areKeysAvailable( 2286 CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE); 2287 mCollector.expectEquals("Aberration correction mode must be present in request if " + 2288 "available aberration correction reductions are present in metadata, and " 2289 + "vice-versa.", supportAvailableAberrationModes, supportAberrationRequestKey); 2290 if (supportAberrationRequestKey) { 2291 List<Integer> availableAberrationModes = Arrays.asList( 2292 toObject(mStaticInfo.getAvailableColorAberrationModesChecked())); 2293 // Don't need check fast as fast or high quality must be both present or both not. 2294 if (availableAberrationModes 2295 .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY)) { 2296 mCollector.expectKeyValueEquals( 2297 request, COLOR_CORRECTION_ABERRATION_MODE, 2298 CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); 2299 } else { 2300 mCollector.expectKeyValueEquals( 2301 request, COLOR_CORRECTION_ABERRATION_MODE, 2302 CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF); 2303 } 2304 } 2305 } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && supportReprocessing) { 2306 mCollector.expectKeyValueEquals(request, EDGE_MODE, 2307 CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 2308 mCollector.expectKeyValueEquals(request, NOISE_REDUCTION_MODE, 2309 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 2310 } else if (template == CameraDevice.TEMPLATE_PREVIEW || 2311 template == CameraDevice.TEMPLATE_RECORD) { 2312 2313 // Ok with either FAST or HIGH_QUALITY 2314 if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_MODE)) { 2315 mCollector.expectKeyValueNotEquals( 2316 request, COLOR_CORRECTION_MODE, 2317 CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX); 2318 } 2319 2320 if (mStaticInfo.areKeysAvailable(EDGE_MODE)) { 2321 List<Integer> availableEdgeModes = 2322 Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked())); 2323 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) { 2324 mCollector.expectKeyValueEquals(request, EDGE_MODE, 2325 CaptureRequest.EDGE_MODE_FAST); 2326 } else { 2327 mCollector.expectKeyValueEquals(request, EDGE_MODE, 2328 CaptureRequest.EDGE_MODE_OFF); 2329 } 2330 } 2331 2332 if (mStaticInfo.areKeysAvailable(SHADING_MODE)) { 2333 List<Integer> availableShadingModes = 2334 Arrays.asList(toObject(mStaticInfo.getAvailableShadingModesChecked())); 2335 mCollector.expectKeyValueEquals(request, SHADING_MODE, 2336 CaptureRequest.SHADING_MODE_FAST); 2337 } 2338 2339 if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) { 2340 List<Integer> availableNoiseReductionModes = 2341 Arrays.asList(toObject( 2342 mStaticInfo.getAvailableNoiseReductionModesChecked())); 2343 if (availableNoiseReductionModes 2344 .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) { 2345 mCollector.expectKeyValueEquals( 2346 request, NOISE_REDUCTION_MODE, 2347 CaptureRequest.NOISE_REDUCTION_MODE_FAST); 2348 } else { 2349 mCollector.expectKeyValueEquals( 2350 request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF); 2351 } 2352 } 2353 2354 if (mStaticInfo.areKeysAvailable(HOT_PIXEL_MODE)) { 2355 List<Integer> availableHotPixelModes = 2356 Arrays.asList(toObject( 2357 mStaticInfo.getAvailableHotPixelModesChecked())); 2358 if (availableHotPixelModes 2359 .contains(CaptureRequest.HOT_PIXEL_MODE_FAST)) { 2360 mCollector.expectKeyValueEquals( 2361 request, HOT_PIXEL_MODE, 2362 CaptureRequest.HOT_PIXEL_MODE_FAST); 2363 } else { 2364 mCollector.expectKeyValueEquals( 2365 request, HOT_PIXEL_MODE, CaptureRequest.HOT_PIXEL_MODE_OFF); 2366 } 2367 } 2368 2369 if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) { 2370 List<Integer> availableAberrationModes = Arrays.asList( 2371 toObject(mStaticInfo.getAvailableColorAberrationModesChecked())); 2372 if (availableAberrationModes 2373 .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST)) { 2374 mCollector.expectKeyValueEquals( 2375 request, COLOR_CORRECTION_ABERRATION_MODE, 2376 CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST); 2377 } else { 2378 mCollector.expectKeyValueEquals( 2379 request, COLOR_CORRECTION_ABERRATION_MODE, 2380 CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF); 2381 } 2382 } 2383 } else { 2384 if (mStaticInfo.areKeysAvailable(EDGE_MODE)) { 2385 mCollector.expectKeyValueNotNull(request, EDGE_MODE); 2386 } 2387 2388 if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) { 2389 mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE); 2390 } 2391 2392 if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) { 2393 mCollector.expectKeyValueNotNull(request, COLOR_CORRECTION_ABERRATION_MODE); 2394 } 2395 } 2396 2397 // Tone map and lens shading modes. 2398 if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) { 2399 mCollector.expectEquals("Tonemap mode must be present in request if " + 2400 "available tonemap modes are present in metadata, and vice-versa.", 2401 mStaticInfo.areKeysAvailable(CameraCharacteristics. 2402 TONEMAP_AVAILABLE_TONE_MAP_MODES), 2403 mStaticInfo.areKeysAvailable(CaptureRequest.TONEMAP_MODE)); 2404 if (mStaticInfo.areKeysAvailable( 2405 CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES)) { 2406 List<Integer> availableToneMapModes = 2407 Arrays.asList(toObject(mStaticInfo.getAvailableToneMapModesChecked())); 2408 if (availableToneMapModes.contains(CaptureRequest.TONEMAP_MODE_HIGH_QUALITY)) { 2409 mCollector.expectKeyValueEquals(request, TONEMAP_MODE, 2410 CaptureRequest.TONEMAP_MODE_HIGH_QUALITY); 2411 } else { 2412 mCollector.expectKeyValueEquals(request, TONEMAP_MODE, 2413 CaptureRequest.TONEMAP_MODE_FAST); 2414 } 2415 } 2416 2417 // Still capture template should have android.statistics.lensShadingMapMode ON when 2418 // RAW capability is supported. 2419 if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE) && 2420 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2421 mCollector.expectKeyValueEquals(request, STATISTICS_LENS_SHADING_MAP_MODE, 2422 STATISTICS_LENS_SHADING_MAP_MODE_ON); 2423 } 2424 } else { 2425 if (mStaticInfo.areKeysAvailable(TONEMAP_MODE)) { 2426 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, 2427 CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE); 2428 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, 2429 CaptureRequest.TONEMAP_MODE_GAMMA_VALUE); 2430 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, 2431 CaptureRequest.TONEMAP_MODE_PRESET_CURVE); 2432 } 2433 if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) { 2434 mCollector.expectKeyValueEquals(request, STATISTICS_LENS_SHADING_MAP_MODE, 2435 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF); 2436 } 2437 if (mStaticInfo.areKeysAvailable(STATISTICS_HOT_PIXEL_MAP_MODE)) { 2438 mCollector.expectKeyValueEquals(request, STATISTICS_HOT_PIXEL_MAP_MODE, 2439 false); 2440 } 2441 } 2442 2443 // Enable ZSL 2444 if (template != CameraDevice.TEMPLATE_STILL_CAPTURE) { 2445 if (mStaticInfo.areKeysAvailable(CONTROL_ENABLE_ZSL)) { 2446 mCollector.expectKeyValueEquals(request, CONTROL_ENABLE_ZSL, false); 2447 } 2448 } 2449 2450 int[] outputFormats = mStaticInfo.getAvailableFormats( 2451 StaticMetadata.StreamDirection.Output); 2452 boolean supportRaw = false; 2453 for (int format : outputFormats) { 2454 if (format == ImageFormat.RAW_SENSOR || format == ImageFormat.RAW10 || 2455 format == ImageFormat.RAW12 || format == ImageFormat.RAW_PRIVATE) { 2456 supportRaw = true; 2457 break; 2458 } 2459 } 2460 if (supportRaw) { 2461 mCollector.expectKeyValueEquals(request, 2462 CONTROL_POST_RAW_SENSITIVITY_BOOST, 2463 DEFAULT_POST_RAW_SENSITIVITY_BOOST); 2464 } 2465 2466 switch(template) { 2467 case CameraDevice.TEMPLATE_PREVIEW: 2468 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, 2469 CameraCharacteristics.CONTROL_CAPTURE_INTENT_PREVIEW); 2470 break; 2471 case CameraDevice.TEMPLATE_STILL_CAPTURE: 2472 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, 2473 CameraCharacteristics.CONTROL_CAPTURE_INTENT_STILL_CAPTURE); 2474 break; 2475 case CameraDevice.TEMPLATE_RECORD: 2476 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, 2477 CameraCharacteristics.CONTROL_CAPTURE_INTENT_VIDEO_RECORD); 2478 break; 2479 case CameraDevice.TEMPLATE_VIDEO_SNAPSHOT: 2480 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, 2481 CameraCharacteristics.CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT); 2482 break; 2483 case CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG: 2484 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, 2485 CameraCharacteristics.CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG); 2486 break; 2487 case CameraDevice.TEMPLATE_MANUAL: 2488 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, 2489 CameraCharacteristics.CONTROL_CAPTURE_INTENT_MANUAL); 2490 break; 2491 default: 2492 // Skip unknown templates here 2493 } 2494 2495 // Check distortion correction mode 2496 if (mStaticInfo.isDistortionCorrectionSupported()) { 2497 mCollector.expectKeyValueNotEquals(request, DISTORTION_CORRECTION_MODE, 2498 CaptureRequest.DISTORTION_CORRECTION_MODE_OFF); 2499 } 2500 2501 // TODO: use the list of keys from CameraCharacteristics to avoid expecting 2502 // keys which are not available by this CameraDevice. 2503 } 2504 captureTemplateTestByCamera(String cameraId, int template)2505 private void captureTemplateTestByCamera(String cameraId, int template) throws Exception { 2506 try { 2507 openDevice(cameraId, mCameraMockListener); 2508 2509 assertTrue("Camera template " + template + " is out of range!", 2510 template >= CameraDevice.TEMPLATE_PREVIEW 2511 && template <= CameraDevice.TEMPLATE_MANUAL); 2512 2513 mCollector.setCameraId(cameraId); 2514 2515 try { 2516 CaptureRequest.Builder request = mCamera.createCaptureRequest(template); 2517 assertNotNull("Failed to create capture request for template " + template, request); 2518 2519 CameraCharacteristics props = mStaticInfo.getCharacteristics(); 2520 checkRequestForTemplate(request, template, props); 2521 } catch (IllegalArgumentException e) { 2522 if (template == CameraDevice.TEMPLATE_MANUAL && 2523 !mStaticInfo.isCapabilitySupported(CameraCharacteristics. 2524 REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 2525 // OK 2526 } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && 2527 !mStaticInfo.isCapabilitySupported(CameraCharacteristics. 2528 REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING)) { 2529 // OK. 2530 } else if (sLegacySkipTemplates.contains(template) && 2531 mStaticInfo.isHardwareLevelLegacy()) { 2532 // OK 2533 } else if (template != CameraDevice.TEMPLATE_PREVIEW && 2534 mStaticInfo.isDepthOutputSupported() && 2535 !mStaticInfo.isColorOutputSupported()) { 2536 // OK, depth-only devices need only support PREVIEW template 2537 } else { 2538 throw e; // rethrow 2539 } 2540 } 2541 } 2542 finally { 2543 try { 2544 closeSession(); 2545 } finally { 2546 closeDevice(cameraId, mCameraMockListener); 2547 } 2548 } 2549 } 2550 2551 /** 2552 * Start capture with given {@link #CaptureRequest}. 2553 * 2554 * @param request The {@link #CaptureRequest} to be captured. 2555 * @param repeating If the capture is single capture or repeating. 2556 * @param listener The {@link #CaptureCallback} camera device used to notify callbacks. 2557 * @param handler The handler camera device used to post callbacks. 2558 */ 2559 @Override startCapture(CaptureRequest request, boolean repeating, CameraCaptureSession.CaptureCallback listener, Handler handler)2560 protected void startCapture(CaptureRequest request, boolean repeating, 2561 CameraCaptureSession.CaptureCallback listener, Handler handler) 2562 throws CameraAccessException { 2563 if (VERBOSE) Log.v(TAG, "Starting capture from session"); 2564 2565 if (repeating) { 2566 mSession.setRepeatingRequest(request, listener, handler); 2567 } else { 2568 mSession.capture(request, listener, handler); 2569 } 2570 } 2571 2572 /** 2573 * Start capture with given {@link #CaptureRequest}. 2574 * 2575 * @param request The {@link #CaptureRequest} to be captured. 2576 * @param repeating If the capture is single capture or repeating. 2577 * @param listener The {@link #CaptureCallback} camera device used to notify callbacks. 2578 * @param executor The executor used to invoke callbacks. 2579 */ startCapture(CaptureRequest request, boolean repeating, CameraCaptureSession.CaptureCallback listener, Executor executor)2580 protected void startCapture(CaptureRequest request, boolean repeating, 2581 CameraCaptureSession.CaptureCallback listener, Executor executor) 2582 throws CameraAccessException { 2583 if (VERBOSE) Log.v(TAG, "Starting capture from session"); 2584 2585 if (repeating) { 2586 mSession.setSingleRepeatingRequest(request, executor, listener); 2587 } else { 2588 mSession.captureSingleRequest(request, executor, listener); 2589 } 2590 } 2591 2592 /** 2593 * Close a {@link #CameraCaptureSession capture session}; blocking until 2594 * the close finishes with a transition to {@link CameraCaptureSession.StateCallback#onClosed}. 2595 */ closeSession()2596 protected void closeSession() { 2597 if (mSession == null) { 2598 return; 2599 } 2600 2601 mSession.close(); 2602 waitForSessionState(SESSION_CLOSED, SESSION_CLOSE_TIMEOUT_MS); 2603 mSession = null; 2604 2605 mSessionMockListener = null; 2606 mSessionWaiter = null; 2607 } 2608 2609 /** 2610 * A camera capture session listener that keeps all the configured and closed sessions. 2611 */ 2612 private class MultipleSessionCallback extends CameraCaptureSession.StateCallback { 2613 public static final int SESSION_CONFIGURED = 0; 2614 public static final int SESSION_CLOSED = 1; 2615 2616 final List<CameraCaptureSession> mSessions = new ArrayList<>(); 2617 final Map<CameraCaptureSession, Integer> mSessionStates = new HashMap<>(); 2618 CameraCaptureSession mCurrentConfiguredSession = null; 2619 2620 final ReentrantLock mLock = new ReentrantLock(); 2621 final Condition mNewStateCond = mLock.newCondition(); 2622 2623 final boolean mFailOnConfigureFailed; 2624 2625 /** 2626 * If failOnConfigureFailed is true, it calls fail() when onConfigureFailed() is invoked 2627 * for any session. 2628 */ MultipleSessionCallback(boolean failOnConfigureFailed)2629 public MultipleSessionCallback(boolean failOnConfigureFailed) { 2630 mFailOnConfigureFailed = failOnConfigureFailed; 2631 } 2632 2633 @Override onClosed(CameraCaptureSession session)2634 public void onClosed(CameraCaptureSession session) { 2635 mLock.lock(); 2636 mSessionStates.put(session, SESSION_CLOSED); 2637 mNewStateCond.signal(); 2638 mLock.unlock(); 2639 } 2640 2641 @Override onConfigured(CameraCaptureSession session)2642 public void onConfigured(CameraCaptureSession session) { 2643 mLock.lock(); 2644 mSessions.add(session); 2645 mSessionStates.put(session, SESSION_CONFIGURED); 2646 mNewStateCond.signal(); 2647 mLock.unlock(); 2648 } 2649 2650 @Override onConfigureFailed(CameraCaptureSession session)2651 public void onConfigureFailed(CameraCaptureSession session) { 2652 if (mFailOnConfigureFailed) { 2653 fail("Configuring a session failed"); 2654 } 2655 } 2656 2657 /** 2658 * Get a number of sessions that have been configured. 2659 */ getAllSessions(int numSessions, int timeoutMs)2660 public List<CameraCaptureSession> getAllSessions(int numSessions, int timeoutMs) 2661 throws Exception { 2662 long remainingTime = timeoutMs; 2663 mLock.lock(); 2664 try { 2665 while (mSessions.size() < numSessions) { 2666 long startTime = SystemClock.elapsedRealtime(); 2667 boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS); 2668 remainingTime -= (SystemClock.elapsedRealtime() - startTime); 2669 ret &= remainingTime > 0; 2670 2671 assertTrue("Get " + numSessions + " sessions timed out after " + timeoutMs + 2672 "ms", ret); 2673 } 2674 2675 return mSessions; 2676 } finally { 2677 mLock.unlock(); 2678 } 2679 } 2680 2681 /** 2682 * Wait until a previously-configured sessoin is closed or it times out. 2683 */ waitForSessionClose(CameraCaptureSession session, int timeoutMs)2684 public void waitForSessionClose(CameraCaptureSession session, int timeoutMs) throws Exception { 2685 long remainingTime = timeoutMs; 2686 mLock.lock(); 2687 try { 2688 while (mSessionStates.get(session).equals(SESSION_CLOSED) == false) { 2689 long startTime = SystemClock.elapsedRealtime(); 2690 boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS); 2691 remainingTime -= (SystemClock.elapsedRealtime() - startTime); 2692 ret &= remainingTime > 0; 2693 2694 assertTrue("Wait for session close timed out after " + timeoutMs + "ms", ret); 2695 } 2696 } finally { 2697 mLock.unlock(); 2698 } 2699 } 2700 } 2701 } 2702