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