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