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