1 /* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.cts; 18 19 import static android.hardware.camera2.cts.CameraTestUtils.*; 20 import static com.android.ex.camera2.blocking.BlockingStateCallback.*; 21 import static com.android.ex.camera2.blocking.BlockingSessionCallback.*; 22 import static org.mockito.Mockito.*; 23 import static android.hardware.camera2.CaptureRequest.*; 24 25 import android.content.Context; 26 import android.graphics.SurfaceTexture; 27 import android.graphics.ImageFormat; 28 import android.hardware.camera2.CameraAccessException; 29 import android.hardware.camera2.CameraCaptureSession; 30 import android.hardware.camera2.CameraCharacteristics; 31 import android.hardware.camera2.CameraDevice; 32 import android.hardware.camera2.CameraMetadata; 33 import android.hardware.camera2.CaptureFailure; 34 import android.hardware.camera2.CaptureRequest; 35 import android.hardware.camera2.CaptureResult; 36 import android.hardware.camera2.TotalCaptureResult; 37 import android.hardware.camera2.cts.helpers.StaticMetadata; 38 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 39 import android.hardware.camera2.params.MeteringRectangle; 40 import android.media.ImageReader; 41 import android.os.Handler; 42 import android.os.SystemClock; 43 import android.util.Log; 44 import android.util.Range; 45 import android.view.Surface; 46 47 import com.android.ex.camera2.blocking.BlockingSessionCallback; 48 import com.android.ex.camera2.blocking.BlockingStateCallback; 49 import com.android.ex.camera2.utils.StateWaiter; 50 51 import org.mockito.ArgumentMatcher; 52 53 import java.util.ArrayList; 54 import java.util.Arrays; 55 import java.util.concurrent.locks.Condition; 56 import java.util.concurrent.locks.Lock; 57 import java.util.concurrent.locks.ReentrantLock; 58 import java.util.HashSet; 59 import java.util.List; 60 import java.util.Map; 61 import java.util.HashMap; 62 import java.util.Set; 63 import android.util.Size; 64 import java.util.concurrent.LinkedBlockingQueue; 65 import java.util.concurrent.TimeUnit; 66 67 /** 68 * <p>Basic test for CameraDevice APIs.</p> 69 */ 70 public class CameraDeviceTest extends Camera2AndroidTestCase { 71 private static final String TAG = "CameraDeviceTest"; 72 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 73 private static final int ERROR_LISTENER_WAIT_TIMEOUT_MS = 1000; 74 private static final int REPEATING_CAPTURE_EXPECTED_RESULT_COUNT = 5; 75 private static final int MAX_NUM_IMAGES = 5; 76 private static final int MIN_FPS_REQUIRED_FOR_STREAMING = 20; 77 78 private CameraCaptureSession mSession; 79 80 private BlockingStateCallback mCameraMockListener; 81 private int mLatestDeviceState = STATE_UNINITIALIZED; 82 private BlockingSessionCallback mSessionMockListener; 83 private StateWaiter mSessionWaiter; 84 private int mLatestSessionState = -1; // uninitialized 85 86 private static int[] sTemplates = new int[] { 87 CameraDevice.TEMPLATE_PREVIEW, 88 CameraDevice.TEMPLATE_RECORD, 89 CameraDevice.TEMPLATE_STILL_CAPTURE, 90 CameraDevice.TEMPLATE_VIDEO_SNAPSHOT 91 }; 92 93 // Request templates that are unsupported by LEGACY mode. 94 private static Set<Integer> sLegacySkipTemplates = new HashSet<>(); 95 static { 96 sLegacySkipTemplates.add(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT); 97 sLegacySkipTemplates.add(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 98 sLegacySkipTemplates.add(CameraDevice.TEMPLATE_MANUAL); 99 } 100 101 @Override setContext(Context context)102 public void setContext(Context context) { 103 super.setContext(context); 104 105 /** 106 * Workaround for mockito and JB-MR2 incompatibility 107 * 108 * Avoid java.lang.IllegalArgumentException: dexcache == null 109 * https://code.google.com/p/dexmaker/issues/detail?id=2 110 */ 111 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 112 113 /** 114 * Create error listener in context scope, to catch asynchronous device error. 115 * Use spy object here since we want to use the SimpleDeviceListener callback 116 * implementation (spy doesn't stub the functions unless we ask it to do so). 117 */ 118 mCameraMockListener = spy(new BlockingStateCallback()); 119 } 120 121 @Override setUp()122 protected void setUp() throws Exception { 123 super.setUp(); 124 /** 125 * Due to the asynchronous nature of camera device error callback, we 126 * have to make sure device doesn't run into error state before. If so, 127 * fail the rest of the tests. This is especially needed when error 128 * callback is fired too late. 129 */ 130 verify(mCameraMockListener, never()) 131 .onError( 132 any(CameraDevice.class), 133 anyInt()); 134 verify(mCameraMockListener, never()) 135 .onDisconnected( 136 any(CameraDevice.class)); 137 138 mCameraListener = mCameraMockListener; 139 createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888, MAX_NUM_IMAGES, 140 new ImageDropperListener()); 141 } 142 143 @Override tearDown()144 protected void tearDown() throws Exception { 145 super.tearDown(); 146 } 147 148 /** 149 * <p> 150 * Test camera capture request preview capture template. 151 * </p> 152 * 153 * <p> 154 * The request template returned by the camera device must include a 155 * necessary set of metadata keys, and their values must be set correctly. 156 * It mainly requires below settings: 157 * </p> 158 * <ul> 159 * <li>All 3A settings are auto.</li> 160 * <li>All sensor settings are not null.</li> 161 * <li>All ISP processing settings should be non-manual, and the camera 162 * device should make sure the stable frame rate is guaranteed for the given 163 * settings.</li> 164 * </ul> 165 */ testCameraDevicePreviewTemplate()166 public void testCameraDevicePreviewTemplate() throws Exception { 167 for (int i = 0; i < mCameraIds.length; i++) { 168 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_PREVIEW); 169 } 170 171 // TODO: test the frame rate sustainability in preview use case test. 172 } 173 174 /** 175 * <p> 176 * Test camera capture request still capture template. 177 * </p> 178 * 179 * <p> 180 * The request template returned by the camera device must include a 181 * necessary set of metadata keys, and their values must be set correctly. 182 * It mainly requires below settings: 183 * </p> 184 * <ul> 185 * <li>All 3A settings are auto.</li> 186 * <li>All sensor settings are not null.</li> 187 * <li>All ISP processing settings should be non-manual, and the camera 188 * device should make sure the high quality takes priority to the stable 189 * frame rate for the given settings.</li> 190 * </ul> 191 */ testCameraDeviceStillTemplate()192 public void testCameraDeviceStillTemplate() throws Exception { 193 for (int i = 0; i < mCameraIds.length; i++) { 194 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_STILL_CAPTURE); 195 } 196 } 197 198 /** 199 * <p> 200 * Test camera capture video recording template. 201 * </p> 202 * 203 * <p> 204 * The request template returned by the camera device must include a 205 * necessary set of metadata keys, and their values must be set correctly. 206 * It has the similar requirement as preview, with one difference: 207 * </p> 208 * <ul> 209 * <li>Frame rate should be stable, for example, wide fps range like [7, 30] 210 * is a bad setting.</li> 211 */ testCameraDeviceRecordingTemplate()212 public void testCameraDeviceRecordingTemplate() throws Exception { 213 for (int i = 0; i < mCameraIds.length; i++) { 214 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_RECORD); 215 } 216 217 // TODO: test the frame rate sustainability in recording use case test. 218 } 219 220 /** 221 *<p>Test camera capture video snapshot template.</p> 222 * 223 * <p>The request template returned by the camera device must include a necessary set of 224 * metadata keys, and their values must be set correctly. It has the similar requirement 225 * as recording, with an additional requirement: the settings should maximize image quality 226 * without compromising stable frame rate.</p> 227 */ testCameraDeviceVideoSnapShotTemplate()228 public void testCameraDeviceVideoSnapShotTemplate() throws Exception { 229 for (int i = 0; i < mCameraIds.length; i++) { 230 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_VIDEO_SNAPSHOT); 231 } 232 233 // TODO: test the frame rate sustainability in video snapshot use case test. 234 } 235 236 /** 237 *<p>Test camera capture request zero shutter lag template.</p> 238 * 239 * <p>The request template returned by the camera device must include a necessary set of 240 * metadata keys, and their values must be set correctly. It has the similar requirement 241 * as preview, with an additional requirement: </p> 242 */ testCameraDeviceZSLTemplate()243 public void testCameraDeviceZSLTemplate() throws Exception { 244 for (int i = 0; i < mCameraIds.length; i++) { 245 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 246 } 247 } 248 249 /** 250 * <p> 251 * Test camera capture request manual template. 252 * </p> 253 * 254 * <p> 255 * The request template returned by the camera device must include a 256 * necessary set of metadata keys, and their values must be set correctly. It 257 * mainly requires below settings: 258 * </p> 259 * <ul> 260 * <li>All 3A settings are manual.</li> 261 * <li>ISP processing parameters are set to preview quality.</li> 262 * <li>The manual capture parameters (exposure, sensitivity, and so on) are 263 * set to reasonable defaults.</li> 264 * </ul> 265 */ testCameraDeviceManualTemplate()266 public void testCameraDeviceManualTemplate() throws Exception { 267 for (int i = 0; i < mCameraIds.length; i++) { 268 captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_MANUAL); 269 } 270 } 271 testCameraDeviceCreateCaptureBuilder()272 public void testCameraDeviceCreateCaptureBuilder() throws Exception { 273 for (int i = 0; i < mCameraIds.length; i++) { 274 try { 275 openDevice(mCameraIds[i], mCameraMockListener); 276 /** 277 * Test: that each template type is supported, and that its required fields are 278 * present. 279 */ 280 for (int j = 0; j < sTemplates.length; j++) { 281 // Skip video snapshots for LEGACY mode 282 if (mStaticInfo.isHardwareLevelLegacy() && 283 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 284 continue; 285 } 286 // Skip non-PREVIEW templates for non-color output 287 if (!mStaticInfo.isColorOutputSupported() && 288 sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) { 289 continue; 290 } 291 CaptureRequest.Builder capReq = mCamera.createCaptureRequest(sTemplates[j]); 292 assertNotNull("Failed to create capture request", capReq); 293 if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_EXPOSURE_TIME)) { 294 assertNotNull("Missing field: SENSOR_EXPOSURE_TIME", 295 capReq.get(CaptureRequest.SENSOR_EXPOSURE_TIME)); 296 } 297 if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_SENSITIVITY)) { 298 assertNotNull("Missing field: SENSOR_SENSITIVITY", 299 capReq.get(CaptureRequest.SENSOR_SENSITIVITY)); 300 } 301 } 302 } 303 finally { 304 try { 305 closeSession(); 306 } finally { 307 closeDevice(mCameraIds[i], mCameraMockListener); 308 } 309 } 310 } 311 } 312 testCameraDeviceSetErrorListener()313 public void testCameraDeviceSetErrorListener() throws Exception { 314 for (int i = 0; i < mCameraIds.length; i++) { 315 try { 316 openDevice(mCameraIds[i], mCameraMockListener); 317 /** 318 * Test: that the error listener can be set without problems. 319 * Also, wait some time to check if device doesn't run into error. 320 */ 321 SystemClock.sleep(ERROR_LISTENER_WAIT_TIMEOUT_MS); 322 verify(mCameraMockListener, never()) 323 .onError( 324 any(CameraDevice.class), 325 anyInt()); 326 } 327 finally { 328 try { 329 closeSession(); 330 } finally { 331 closeDevice(mCameraIds[i], mCameraMockListener); 332 } 333 } 334 } 335 } 336 testCameraDeviceCapture()337 public void testCameraDeviceCapture() throws Exception { 338 runCaptureTest(/*burst*/false, /*repeating*/false, /*abort*/false); 339 } 340 testCameraDeviceCaptureBurst()341 public void testCameraDeviceCaptureBurst() throws Exception { 342 runCaptureTest(/*burst*/true, /*repeating*/false, /*abort*/false); 343 } 344 testCameraDeviceRepeatingRequest()345 public void testCameraDeviceRepeatingRequest() throws Exception { 346 runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/false); 347 } 348 testCameraDeviceRepeatingBurst()349 public void testCameraDeviceRepeatingBurst() throws Exception { 350 runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/false); 351 } 352 353 /** 354 * Test {@link android.hardware.camera2.CameraCaptureSession#abortCaptures} API. 355 * 356 * <p>Abort is the fastest way to idle the camera device for reconfiguration with 357 * {@link android.hardware.camera2.CameraCaptureSession#abortCaptures}, at the cost of 358 * discarding in-progress work. Once the abort is complete, the idle callback will be called. 359 * </p> 360 */ testCameraDeviceAbort()361 public void testCameraDeviceAbort() throws Exception { 362 runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/true); 363 runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/true); 364 /** 365 * TODO: this is only basic test of abort. we probably should also test below cases: 366 * 367 * 1. Performance. Make sure abort is faster than stopRepeating, we can test each one a 368 * couple of times, then compare the average. Also, for abortCaptures() alone, we should 369 * make sure it doesn't take too long time (e.g. <100ms for full devices, <500ms for limited 370 * devices), after the abort, we should be able to get all results back very quickly. This 371 * can be done in performance test. 372 * 373 * 2. Make sure all in-flight request comes back after abort, e.g. submit a couple of 374 * long exposure single captures, then abort, then check if we can get the pending 375 * request back quickly. 376 * 377 * 3. Also need check onCaptureSequenceCompleted for repeating burst after abortCaptures(). 378 */ 379 } 380 381 /** 382 * Test invalid capture (e.g. null or empty capture request). 383 */ testInvalidCapture()384 public void testInvalidCapture() throws Exception { 385 for (int i = 0; i < mCameraIds.length; i++) { 386 try { 387 openDevice(mCameraIds[i], mCameraMockListener); 388 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 389 390 prepareCapture(); 391 392 invalidRequestCaptureTestByCamera(); 393 394 closeSession(); 395 } 396 finally { 397 closeDevice(mCameraIds[i], mCameraMockListener); 398 } 399 } 400 } 401 402 /** 403 * Test to ensure that we can call camera2 API methods inside callbacks. 404 * 405 * Tests: 406 * onOpened -> createCaptureSession, createCaptureRequest 407 * onConfigured -> getDevice, abortCaptures, 408 * createCaptureRequest, capture, setRepeatingRequest, stopRepeating 409 * onCaptureCompleted -> createCaptureRequest, getDevice, abortCaptures, 410 * capture, setRepeatingRequest, stopRepeating, session+device.close 411 */ testChainedOperation()412 public void testChainedOperation() throws Throwable { 413 414 final ArrayList<Surface> outputs = new ArrayList<>(); 415 outputs.add(mReaderSurface); 416 417 // A queue for the chained listeners to push results to 418 // A success Throwable indicates no errors; other Throwables detail a test failure; 419 // nulls indicate timeouts. 420 final Throwable success = new Throwable("Success"); 421 final LinkedBlockingQueue<Throwable> results = new LinkedBlockingQueue<>(); 422 423 // Define listeners 424 // A cascade of Device->Session->Capture listeners, each of which invokes at least one 425 // method on the camera device or session. 426 427 class ChainedCaptureCallback extends CameraCaptureSession.CaptureCallback { 428 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 429 TotalCaptureResult result) { 430 try { 431 CaptureRequest.Builder request2 = 432 session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 433 request2.addTarget(mReaderSurface); 434 435 // Some calls to the camera for coverage 436 session.abortCaptures(); 437 session.capture(request2.build(), 438 /*listener*/ null, /*handler*/ null); 439 session.setRepeatingRequest(request2.build(), 440 /*listener*/ null, /*handler*/ null); 441 session.stopRepeating(); 442 443 CameraDevice camera = session.getDevice(); 444 session.close(); 445 camera.close(); 446 447 results.offer(success); 448 } catch (Throwable t) { 449 results.offer(t); 450 } 451 } 452 453 public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, 454 CaptureFailure failure) { 455 try { 456 CameraDevice camera = session.getDevice(); 457 session.close(); 458 camera.close(); 459 fail("onCaptureFailed invoked with failure reason: " + failure.getReason()); 460 } catch (Throwable t) { 461 results.offer(t); 462 } 463 } 464 } 465 466 class ChainedSessionListener extends CameraCaptureSession.StateCallback { 467 private final ChainedCaptureCallback mCaptureCallback = new ChainedCaptureCallback(); 468 469 public void onConfigured(CameraCaptureSession session) { 470 try { 471 CaptureRequest.Builder request = 472 session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 473 request.addTarget(mReaderSurface); 474 // Some calls to the camera for coverage 475 session.getDevice(); 476 session.abortCaptures(); 477 // The important call for the next level of chaining 478 session.capture(request.build(), mCaptureCallback, mHandler); 479 // Some more calls 480 session.setRepeatingRequest(request.build(), 481 /*listener*/ null, /*handler*/ null); 482 session.stopRepeating(); 483 results.offer(success); 484 } catch (Throwable t) { 485 results.offer(t); 486 } 487 } 488 489 public void onConfigureFailed(CameraCaptureSession session) { 490 try { 491 CameraDevice camera = session.getDevice(); 492 session.close(); 493 camera.close(); 494 fail("onConfigureFailed was invoked"); 495 } catch (Throwable t) { 496 results.offer(t); 497 } 498 } 499 } 500 501 class ChainedCameraListener extends CameraDevice.StateCallback { 502 private final ChainedSessionListener mSessionListener = new ChainedSessionListener(); 503 504 public CameraDevice cameraDevice; 505 506 public void onOpened(CameraDevice camera) { 507 508 cameraDevice = camera; 509 try { 510 // Some calls for coverage 511 camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 512 // The important call for next level of chaining 513 camera.createCaptureSession(outputs, mSessionListener, mHandler); 514 results.offer(success); 515 } catch (Throwable t) { 516 try { 517 camera.close(); 518 results.offer(t); 519 } catch (Throwable t2) { 520 Log.e(TAG, 521 "Second failure reached; discarding first exception with trace " + 522 Log.getStackTraceString(t)); 523 results.offer(t2); 524 } 525 } 526 } 527 528 public void onDisconnected(CameraDevice camera) { 529 try { 530 camera.close(); 531 fail("onDisconnected invoked"); 532 } catch (Throwable t) { 533 results.offer(t); 534 } 535 } 536 537 public void onError(CameraDevice camera, int error) { 538 try { 539 camera.close(); 540 fail("onError invoked with error code: " + error); 541 } catch (Throwable t) { 542 results.offer(t); 543 } 544 } 545 } 546 547 // Actual test code 548 549 for (int i = 0; i < mCameraIds.length; i++) { 550 Throwable result; 551 552 if (!(new StaticMetadata(mCameraManager.getCameraCharacteristics(mCameraIds[i]))). 553 isColorOutputSupported()) { 554 Log.i(TAG, "Camera " + mCameraIds[i] + " does not support color outputs, skipping"); 555 continue; 556 } 557 558 // Start chained cascade 559 ChainedCameraListener cameraListener = new ChainedCameraListener(); 560 mCameraManager.openCamera(mCameraIds[i], cameraListener, mHandler); 561 562 // Check if open succeeded 563 result = results.poll(CAMERA_OPEN_TIMEOUT_MS, TimeUnit.MILLISECONDS); 564 if (result != success) { 565 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close(); 566 if (result == null) { 567 fail("Timeout waiting for camera open"); 568 } else { 569 throw result; 570 } 571 } 572 573 // Check if configure succeeded 574 result = results.poll(SESSION_CONFIGURE_TIMEOUT_MS, TimeUnit.MILLISECONDS); 575 if (result != success) { 576 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close(); 577 if (result == null) { 578 fail("Timeout waiting for session configure"); 579 } else { 580 throw result; 581 } 582 } 583 584 // Check if capture succeeded 585 result = results.poll(CAPTURE_RESULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); 586 if (result != success) { 587 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close(); 588 if (result == null) { 589 fail("Timeout waiting for capture completion"); 590 } else { 591 throw result; 592 } 593 } 594 } 595 } 596 597 /** 598 * Verify basic semantics and error conditions of the prepare call. 599 * 600 */ testPrepare()601 public void testPrepare() throws Exception { 602 for (int i = 0; i < mCameraIds.length; i++) { 603 try { 604 openDevice(mCameraIds[i], mCameraMockListener); 605 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 606 if (!mStaticInfo.isColorOutputSupported()) { 607 Log.i(TAG, "Camera " + mCameraIds[i] + 608 " does not support color outputs, skipping"); 609 continue; 610 } 611 612 prepareTestByCamera(); 613 } 614 finally { 615 closeDevice(mCameraIds[i], mCameraMockListener); 616 } 617 } 618 } 619 620 /** 621 * Verify creating sessions back to back. 622 */ testCreateSessions()623 public void testCreateSessions() throws Exception { 624 for (int i = 0; i < mCameraIds.length; i++) { 625 try { 626 openDevice(mCameraIds[i], mCameraMockListener); 627 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 628 if (!mStaticInfo.isColorOutputSupported()) { 629 Log.i(TAG, "Camera " + mCameraIds[i] + 630 " does not support color outputs, skipping"); 631 continue; 632 } 633 634 testCreateSessionsByCamera(mCameraIds[i]); 635 } 636 finally { 637 closeDevice(mCameraIds[i], mCameraMockListener); 638 } 639 } 640 } 641 642 /** 643 * Verify creating sessions back to back and only the last one is valid for 644 * submitting requests. 645 */ testCreateSessionsByCamera(String cameraId)646 private void testCreateSessionsByCamera(String cameraId) throws Exception { 647 final int NUM_SESSIONS = 3; 648 final int SESSION_TIMEOUT_MS = 1000; 649 final int CAPTURE_TIMEOUT_MS = 3000; 650 651 if (VERBOSE) { 652 Log.v(TAG, "Testing creating sessions for camera " + cameraId); 653 } 654 655 Size yuvSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.YUV_420_888, 656 /*bound*/null).get(0); 657 Size jpegSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.JPEG, 658 /*bound*/null).get(0); 659 660 // Create a list of image readers. JPEG for last one and YUV for the rest. 661 List<ImageReader> imageReaders = new ArrayList<>(); 662 List<CameraCaptureSession> allSessions = new ArrayList<>(); 663 664 try { 665 for (int i = 0; i < NUM_SESSIONS - 1; i++) { 666 imageReaders.add(ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(), 667 ImageFormat.YUV_420_888, /*maxImages*/1)); 668 } 669 imageReaders.add(ImageReader.newInstance(jpegSize.getWidth(), jpegSize.getHeight(), 670 ImageFormat.JPEG, /*maxImages*/1)); 671 672 // Create multiple sessions back to back. 673 MultipleSessionCallback sessionListener = 674 new MultipleSessionCallback(/*failOnConfigureFailed*/true); 675 for (int i = 0; i < NUM_SESSIONS; i++) { 676 List<Surface> outputs = new ArrayList<>(); 677 outputs.add(imageReaders.get(i).getSurface()); 678 mCamera.createCaptureSession(outputs, sessionListener, mHandler); 679 } 680 681 // Verify we get onConfigured() for all sessions. 682 allSessions = sessionListener.getAllSessions(NUM_SESSIONS, 683 SESSION_TIMEOUT_MS * NUM_SESSIONS); 684 assertEquals(String.format("Got %d sessions but configured %d sessions", 685 allSessions.size(), NUM_SESSIONS), allSessions.size(), NUM_SESSIONS); 686 687 // Verify all sessions except the last one are closed. 688 for (int i = 0; i < NUM_SESSIONS - 1; i++) { 689 sessionListener.waitForSessionClose(allSessions.get(i), SESSION_TIMEOUT_MS); 690 } 691 692 // Verify we can capture a frame with the last session. 693 CameraCaptureSession session = allSessions.get(allSessions.size() - 1); 694 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 695 ImageReader reader = imageReaders.get(imageReaders.size() - 1); 696 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 697 reader.setOnImageAvailableListener(imageListener, mHandler); 698 699 CaptureRequest.Builder builder = 700 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 701 builder.addTarget(reader.getSurface()); 702 CaptureRequest request = builder.build(); 703 704 session.capture(request, captureListener, mHandler); 705 captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS); 706 imageListener.getImage(CAPTURE_TIMEOUT_MS).close(); 707 } finally { 708 for (ImageReader reader : imageReaders) { 709 reader.close(); 710 } 711 for (CameraCaptureSession session : allSessions) { 712 session.close(); 713 } 714 } 715 } 716 prepareTestByCamera()717 private void prepareTestByCamera() throws Exception { 718 final int PREPARE_TIMEOUT_MS = 10000; 719 720 mSessionMockListener = spy(new BlockingSessionCallback()); 721 722 SurfaceTexture output1 = new SurfaceTexture(1); 723 Surface output1Surface = new Surface(output1); 724 SurfaceTexture output2 = new SurfaceTexture(2); 725 Surface output2Surface = new Surface(output2); 726 727 List<Surface> outputSurfaces = new ArrayList<>( 728 Arrays.asList(output1Surface, output2Surface)); 729 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 730 731 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 732 733 // Try basic prepare 734 735 mSession.prepare(output1Surface); 736 737 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 738 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 739 740 // Should not complain if preparing already prepared stream 741 742 mSession.prepare(output1Surface); 743 744 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2)) 745 .onSurfacePrepared(eq(mSession), eq(output1Surface)); 746 747 // Check surface not included in session 748 749 SurfaceTexture output3 = new SurfaceTexture(3); 750 Surface output3Surface = new Surface(output3); 751 try { 752 mSession.prepare(output3Surface); 753 // Legacy camera prepare always succeed 754 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 755 fail("Preparing surface not part of session must throw IllegalArgumentException"); 756 } 757 } catch (IllegalArgumentException e) { 758 // expected 759 } 760 761 // Ensure second prepare also works 762 763 mSession.prepare(output2Surface); 764 765 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 766 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 767 768 // Use output1 769 770 CaptureRequest.Builder r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 771 r.addTarget(output1Surface); 772 773 mSession.capture(r.build(), null, null); 774 775 try { 776 mSession.prepare(output1Surface); 777 // Legacy camera prepare always succeed 778 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 779 fail("Preparing already-used surface must throw IllegalArgumentException"); 780 } 781 } catch (IllegalArgumentException e) { 782 // expected 783 } 784 785 // Create new session with outputs 1 and 3, ensure output1Surface still can't be prepared 786 // again 787 788 mSessionMockListener = spy(new BlockingSessionCallback()); 789 790 outputSurfaces = new ArrayList<>( 791 Arrays.asList(output1Surface, output3Surface)); 792 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 793 794 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 795 796 try { 797 mSession.prepare(output1Surface); 798 // Legacy camera prepare always succeed 799 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 800 fail("Preparing surface used in previous session must throw " + 801 "IllegalArgumentException"); 802 } 803 } catch (IllegalArgumentException e) { 804 // expected 805 } 806 807 // Use output3, wait for result, then make sure prepare still doesn't work 808 809 r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 810 r.addTarget(output3Surface); 811 812 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 813 mSession.capture(r.build(), resultListener, mHandler); 814 815 resultListener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS); 816 817 try { 818 mSession.prepare(output3Surface); 819 // Legacy camera prepare always succeed 820 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 821 fail("Preparing already-used surface must throw IllegalArgumentException"); 822 } 823 } catch (IllegalArgumentException e) { 824 // expected 825 } 826 827 // Create new session with outputs 1 and 2, ensure output2Surface can be prepared again 828 829 mSessionMockListener = spy(new BlockingSessionCallback()); 830 831 outputSurfaces = new ArrayList<>( 832 Arrays.asList(output1Surface, output2Surface)); 833 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 834 835 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 836 837 mSession.prepare(output2Surface); 838 839 verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1)) 840 .onSurfacePrepared(eq(mSession), eq(output2Surface)); 841 842 try { 843 mSession.prepare(output1Surface); 844 // Legacy camera prepare always succeed 845 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 846 fail("Preparing surface used in previous session must throw " + 847 "IllegalArgumentException"); 848 } 849 } catch (IllegalArgumentException e) { 850 // expected 851 } 852 853 } 854 855 invalidRequestCaptureTestByCamera()856 private void invalidRequestCaptureTestByCamera() throws Exception { 857 if (VERBOSE) Log.v(TAG, "invalidRequestCaptureTestByCamera"); 858 859 List<CaptureRequest> emptyRequests = new ArrayList<CaptureRequest>(); 860 CaptureRequest.Builder requestBuilder = 861 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 862 CaptureRequest unConfiguredRequest = requestBuilder.build(); 863 List<CaptureRequest> unConfiguredRequests = new ArrayList<CaptureRequest>(); 864 unConfiguredRequests.add(unConfiguredRequest); 865 866 try { 867 // Test: CameraCaptureSession capture should throw IAE for null request. 868 mSession.capture(/*request*/null, /*listener*/null, mHandler); 869 mCollector.addMessage( 870 "Session capture should throw IllegalArgumentException for null request"); 871 } catch (IllegalArgumentException e) { 872 // Pass. 873 } 874 875 try { 876 // Test: CameraCaptureSession capture should throw IAE for request 877 // without surface configured. 878 mSession.capture(unConfiguredRequest, /*listener*/null, mHandler); 879 mCollector.addMessage("Session capture should throw " + 880 "IllegalArgumentException for request without surface configured"); 881 } catch (IllegalArgumentException e) { 882 // Pass. 883 } 884 885 try { 886 // Test: CameraCaptureSession setRepeatingRequest should throw IAE for null request. 887 mSession.setRepeatingRequest(/*request*/null, /*listener*/null, mHandler); 888 mCollector.addMessage("Session setRepeatingRequest should throw " + 889 "IllegalArgumentException for null request"); 890 } catch (IllegalArgumentException e) { 891 // Pass. 892 } 893 894 try { 895 // Test: CameraCaptureSession setRepeatingRequest should throw IAE for for request 896 // without surface configured. 897 mSession.setRepeatingRequest(unConfiguredRequest, /*listener*/null, mHandler); 898 mCollector.addMessage("Capture zero burst should throw IllegalArgumentException " + 899 "for request without surface configured"); 900 } catch (IllegalArgumentException e) { 901 // Pass. 902 } 903 904 try { 905 // Test: CameraCaptureSession captureBurst should throw IAE for null request list. 906 mSession.captureBurst(/*requests*/null, /*listener*/null, mHandler); 907 mCollector.addMessage("Session captureBurst should throw " + 908 "IllegalArgumentException for null request list"); 909 } catch (IllegalArgumentException e) { 910 // Pass. 911 } 912 913 try { 914 // Test: CameraCaptureSession captureBurst should throw IAE for empty request list. 915 mSession.captureBurst(emptyRequests, /*listener*/null, mHandler); 916 mCollector.addMessage("Session captureBurst should throw " + 917 " IllegalArgumentException for empty request list"); 918 } catch (IllegalArgumentException e) { 919 // Pass. 920 } 921 922 try { 923 // Test: CameraCaptureSession captureBurst should throw IAE for request 924 // without surface configured. 925 mSession.captureBurst(unConfiguredRequests, /*listener*/null, mHandler); 926 fail("Session captureBurst should throw IllegalArgumentException " + 927 "for null request list"); 928 } catch (IllegalArgumentException e) { 929 // Pass. 930 } 931 932 try { 933 // Test: CameraCaptureSession setRepeatingBurst should throw IAE for null request list. 934 mSession.setRepeatingBurst(/*requests*/null, /*listener*/null, mHandler); 935 mCollector.addMessage("Session setRepeatingBurst should throw " + 936 "IllegalArgumentException for null request list"); 937 } catch (IllegalArgumentException e) { 938 // Pass. 939 } 940 941 try { 942 // Test: CameraCaptureSession setRepeatingBurst should throw IAE for empty request list. 943 mSession.setRepeatingBurst(emptyRequests, /*listener*/null, mHandler); 944 mCollector.addMessage("Session setRepeatingBurst should throw " + 945 "IllegalArgumentException for empty request list"); 946 } catch (IllegalArgumentException e) { 947 // Pass. 948 } 949 950 try { 951 // Test: CameraCaptureSession setRepeatingBurst should throw IAE for request 952 // without surface configured. 953 mSession.setRepeatingBurst(unConfiguredRequests, /*listener*/null, mHandler); 954 mCollector.addMessage("Session setRepeatingBurst should throw " + 955 "IllegalArgumentException for request without surface configured"); 956 } catch (IllegalArgumentException e) { 957 // Pass. 958 } 959 } 960 961 private class IsCaptureResultNotEmpty 962 extends ArgumentMatcher<TotalCaptureResult> { 963 @Override matches(Object obj)964 public boolean matches(Object obj) { 965 /** 966 * Do the simple verification here. Only verify the timestamp for now. 967 * TODO: verify more required capture result metadata fields. 968 */ 969 TotalCaptureResult result = (TotalCaptureResult) obj; 970 Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP); 971 if (timeStamp != null && timeStamp.longValue() > 0L) { 972 return true; 973 } 974 return false; 975 } 976 } 977 978 /** 979 * Run capture test with different test configurations. 980 * 981 * @param burst If the test uses {@link CameraCaptureSession#captureBurst} or 982 * {@link CameraCaptureSession#setRepeatingBurst} to capture the burst. 983 * @param repeating If the test uses {@link CameraCaptureSession#setRepeatingBurst} or 984 * {@link CameraCaptureSession#setRepeatingRequest} for repeating capture. 985 * @param abort If the test uses {@link CameraCaptureSession#abortCaptures} to stop the 986 * repeating capture. It has no effect if repeating is false. 987 */ runCaptureTest(boolean burst, boolean repeating, boolean abort)988 private void runCaptureTest(boolean burst, boolean repeating, boolean abort) throws Exception { 989 for (int i = 0; i < mCameraIds.length; i++) { 990 try { 991 openDevice(mCameraIds[i], mCameraMockListener); 992 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS); 993 994 prepareCapture(); 995 996 if (!burst) { 997 // Test: that a single capture of each template type succeeds. 998 for (int j = 0; j < sTemplates.length; j++) { 999 // Skip video snapshots for LEGACY mode 1000 if (mStaticInfo.isHardwareLevelLegacy() && 1001 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 1002 continue; 1003 } 1004 // Skip non-PREVIEW templates for non-color output 1005 if (!mStaticInfo.isColorOutputSupported() && 1006 sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) { 1007 continue; 1008 } 1009 captureSingleShot(mCameraIds[i], sTemplates[j], repeating, abort); 1010 } 1011 } 1012 else { 1013 // Test: burst of one shot 1014 captureBurstShot(mCameraIds[i], sTemplates, 1, repeating, abort); 1015 1016 int template = mStaticInfo.isColorOutputSupported() ? 1017 CameraDevice.TEMPLATE_STILL_CAPTURE : 1018 CameraDevice.TEMPLATE_PREVIEW; 1019 int[] templates = new int[] { 1020 template, 1021 template, 1022 template, 1023 template, 1024 template 1025 }; 1026 1027 // Test: burst of 5 shots of the same template type 1028 captureBurstShot(mCameraIds[i], templates, templates.length, repeating, abort); 1029 1030 // Test: burst of 5 shots of different template types 1031 captureBurstShot( 1032 mCameraIds[i], sTemplates, sTemplates.length, repeating, abort); 1033 } 1034 verify(mCameraMockListener, never()) 1035 .onError( 1036 any(CameraDevice.class), 1037 anyInt()); 1038 } catch (Exception e) { 1039 mCollector.addError(e); 1040 } finally { 1041 try { 1042 closeSession(); 1043 } catch (Exception e) { 1044 mCollector.addError(e); 1045 }finally { 1046 closeDevice(mCameraIds[i], mCameraMockListener); 1047 } 1048 } 1049 } 1050 } 1051 captureSingleShot( String id, int template, boolean repeating, boolean abort)1052 private void captureSingleShot( 1053 String id, 1054 int template, 1055 boolean repeating, boolean abort) throws Exception { 1056 1057 assertEquals("Bad initial state for preparing to capture", 1058 mLatestSessionState, SESSION_READY); 1059 1060 CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(template); 1061 assertNotNull("Failed to create capture request", requestBuilder); 1062 requestBuilder.addTarget(mReaderSurface); 1063 CameraCaptureSession.CaptureCallback mockCaptureCallback = 1064 mock(CameraCaptureSession.CaptureCallback.class); 1065 1066 if (VERBOSE) { 1067 Log.v(TAG, String.format("Capturing shot for device %s, template %d", 1068 id, template)); 1069 } 1070 1071 startCapture(requestBuilder.build(), repeating, mockCaptureCallback, mHandler); 1072 waitForSessionState(SESSION_ACTIVE, SESSION_ACTIVE_TIMEOUT_MS); 1073 1074 int expectedCaptureResultCount = repeating ? REPEATING_CAPTURE_EXPECTED_RESULT_COUNT : 1; 1075 verifyCaptureResults(mockCaptureCallback, expectedCaptureResultCount); 1076 1077 if (repeating) { 1078 if (abort) { 1079 mSession.abortCaptures(); 1080 } else { 1081 mSession.stopRepeating(); 1082 } 1083 } 1084 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1085 } 1086 captureBurstShot( String id, int[] templates, int len, boolean repeating, boolean abort)1087 private void captureBurstShot( 1088 String id, 1089 int[] templates, 1090 int len, 1091 boolean repeating, 1092 boolean abort) throws Exception { 1093 1094 assertEquals("Bad initial state for preparing to capture", 1095 mLatestSessionState, SESSION_READY); 1096 1097 assertTrue("Invalid args to capture function", len <= templates.length); 1098 List<CaptureRequest> requests = new ArrayList<CaptureRequest>(); 1099 for (int i = 0; i < len; i++) { 1100 // Skip video snapshots for LEGACY mode 1101 if (mStaticInfo.isHardwareLevelLegacy() && 1102 templates[i] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 1103 continue; 1104 } 1105 // Skip non-PREVIEW templates for non-color outpu 1106 if (!mStaticInfo.isColorOutputSupported() && 1107 templates[i] != CameraDevice.TEMPLATE_PREVIEW) { 1108 continue; 1109 } 1110 CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(templates[i]); 1111 assertNotNull("Failed to create capture request", requestBuilder); 1112 requestBuilder.addTarget(mReaderSurface); 1113 requests.add(requestBuilder.build()); 1114 } 1115 CameraCaptureSession.CaptureCallback mockCaptureCallback = 1116 mock(CameraCaptureSession.CaptureCallback.class); 1117 1118 if (VERBOSE) { 1119 Log.v(TAG, String.format("Capturing burst shot for device %s", id)); 1120 } 1121 1122 if (!repeating) { 1123 mSession.captureBurst(requests, mockCaptureCallback, mHandler); 1124 } 1125 else { 1126 mSession.setRepeatingBurst(requests, mockCaptureCallback, mHandler); 1127 } 1128 waitForSessionState(SESSION_ACTIVE, SESSION_READY_TIMEOUT_MS); 1129 1130 int expectedResultCount = requests.size(); 1131 if (repeating) { 1132 expectedResultCount *= REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; 1133 } 1134 1135 verifyCaptureResults(mockCaptureCallback, expectedResultCount); 1136 1137 if (repeating) { 1138 if (abort) { 1139 mSession.abortCaptures(); 1140 } else { 1141 mSession.stopRepeating(); 1142 } 1143 } 1144 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1145 } 1146 1147 /** 1148 * Precondition: Device must be in known OPENED state (has been waited for). 1149 * 1150 * <p>Creates a new capture session and waits until it is in the {@code SESSION_READY} state. 1151 * </p> 1152 * 1153 * <p>Any existing capture session will be closed as a result of calling this.</p> 1154 * */ prepareCapture()1155 private void prepareCapture() throws Exception { 1156 if (VERBOSE) Log.v(TAG, "prepareCapture"); 1157 1158 assertTrue("Bad initial state for preparing to capture", 1159 mLatestDeviceState == STATE_OPENED); 1160 1161 if (mSession != null) { 1162 if (VERBOSE) Log.v(TAG, "prepareCapture - closing existing session"); 1163 closeSession(); 1164 } 1165 1166 // Create a new session listener each time, it's not reusable across cameras 1167 mSessionMockListener = spy(new BlockingSessionCallback()); 1168 mSessionWaiter = mSessionMockListener.getStateWaiter(); 1169 1170 if (!mStaticInfo.isColorOutputSupported()) { 1171 createDefaultImageReader(getMaxDepthSize(mCamera.getId(), mCameraManager), 1172 ImageFormat.DEPTH16, MAX_NUM_IMAGES, new ImageDropperListener()); 1173 } 1174 1175 List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(mReaderSurface)); 1176 mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler); 1177 1178 mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 1179 waitForSessionState(SESSION_CONFIGURED, SESSION_CONFIGURE_TIMEOUT_MS); 1180 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS); 1181 } 1182 waitForDeviceState(int state, long timeoutMs)1183 private void waitForDeviceState(int state, long timeoutMs) { 1184 mCameraMockListener.waitForState(state, timeoutMs); 1185 mLatestDeviceState = state; 1186 } 1187 waitForSessionState(int state, long timeoutMs)1188 private void waitForSessionState(int state, long timeoutMs) { 1189 mSessionWaiter.waitForState(state, timeoutMs); 1190 mLatestSessionState = state; 1191 } 1192 verifyCaptureResults( CameraCaptureSession.CaptureCallback mockListener, int expectResultCount)1193 private void verifyCaptureResults( 1194 CameraCaptureSession.CaptureCallback mockListener, 1195 int expectResultCount) { 1196 final int TIMEOUT_PER_RESULT_MS = 2000; 1197 // Should receive expected number of capture results. 1198 verify(mockListener, 1199 timeout(TIMEOUT_PER_RESULT_MS * expectResultCount).atLeast(expectResultCount)) 1200 .onCaptureCompleted( 1201 eq(mSession), 1202 isA(CaptureRequest.class), 1203 argThat(new IsCaptureResultNotEmpty())); 1204 // Should not receive any capture failed callbacks. 1205 verify(mockListener, never()) 1206 .onCaptureFailed( 1207 eq(mSession), 1208 isA(CaptureRequest.class), 1209 isA(CaptureFailure.class)); 1210 // Should receive expected number of capture shutter calls 1211 verify(mockListener, 1212 atLeast(expectResultCount)) 1213 .onCaptureStarted( 1214 eq(mSession), 1215 isA(CaptureRequest.class), 1216 anyLong(), 1217 anyLong()); 1218 } 1219 checkFpsRange(CaptureRequest.Builder request, int template, CameraCharacteristics props)1220 private void checkFpsRange(CaptureRequest.Builder request, int template, 1221 CameraCharacteristics props) { 1222 CaptureRequest.Key<Range<Integer>> fpsRangeKey = CONTROL_AE_TARGET_FPS_RANGE; 1223 Range<Integer> fpsRange; 1224 if ((fpsRange = mCollector.expectKeyValueNotNull(request, fpsRangeKey)) == null) { 1225 return; 1226 } 1227 1228 int minFps = fpsRange.getLower(); 1229 int maxFps = fpsRange.getUpper(); 1230 Range<Integer>[] availableFpsRange = props 1231 .get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 1232 boolean foundRange = false; 1233 for (int i = 0; i < availableFpsRange.length; i += 1) { 1234 if (minFps == availableFpsRange[i].getLower() 1235 && maxFps == availableFpsRange[i].getUpper()) { 1236 foundRange = true; 1237 break; 1238 } 1239 } 1240 if (!foundRange) { 1241 mCollector.addMessage(String.format("Unable to find the fps range (%d, %d)", 1242 minFps, maxFps)); 1243 return; 1244 } 1245 1246 1247 if (template != CameraDevice.TEMPLATE_MANUAL && 1248 template != CameraDevice.TEMPLATE_STILL_CAPTURE) { 1249 if (maxFps < MIN_FPS_REQUIRED_FOR_STREAMING) { 1250 mCollector.addMessage("Max fps should be at least " 1251 + MIN_FPS_REQUIRED_FOR_STREAMING); 1252 return; 1253 } 1254 1255 // Relax framerate constraints on legacy mode 1256 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 1257 // Need give fixed frame rate for video recording template. 1258 if (template == CameraDevice.TEMPLATE_RECORD) { 1259 if (maxFps != minFps) { 1260 mCollector.addMessage("Video recording frame rate should be fixed"); 1261 } 1262 } 1263 } 1264 } 1265 } 1266 checkAfMode(CaptureRequest.Builder request, int template, CameraCharacteristics props)1267 private void checkAfMode(CaptureRequest.Builder request, int template, 1268 CameraCharacteristics props) { 1269 boolean hasFocuser = props.getKeys().contains(CameraCharacteristics. 1270 LENS_INFO_MINIMUM_FOCUS_DISTANCE) && 1271 (props.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) > 0f); 1272 1273 if (!hasFocuser) { 1274 return; 1275 } 1276 1277 int targetAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO; 1278 int[] availableAfMode = props.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); 1279 if (template == CameraDevice.TEMPLATE_PREVIEW || 1280 template == CameraDevice.TEMPLATE_STILL_CAPTURE || 1281 template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG) { 1282 // Default to CONTINUOUS_PICTURE if it is available, otherwise AUTO. 1283 for (int i = 0; i < availableAfMode.length; i++) { 1284 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) { 1285 targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE; 1286 break; 1287 } 1288 } 1289 } else if (template == CameraDevice.TEMPLATE_RECORD || 1290 template == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { 1291 // Default to CONTINUOUS_VIDEO if it is available, otherwise AUTO. 1292 for (int i = 0; i < availableAfMode.length; i++) { 1293 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) { 1294 targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO; 1295 break; 1296 } 1297 } 1298 } else if (template == CameraDevice.TEMPLATE_MANUAL) { 1299 targetAfMode = CaptureRequest.CONTROL_AF_MODE_OFF; 1300 } 1301 1302 mCollector.expectKeyValueEquals(request, CONTROL_AF_MODE, targetAfMode); 1303 if (mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FOCUS_DISTANCE)) { 1304 mCollector.expectKeyValueNotNull(request, LENS_FOCUS_DISTANCE); 1305 } 1306 } 1307 checkAntiBandingMode(CaptureRequest.Builder request, int template)1308 private void checkAntiBandingMode(CaptureRequest.Builder request, int template) { 1309 if (template == CameraDevice.TEMPLATE_MANUAL) { 1310 return; 1311 } 1312 1313 if (!mStaticInfo.isColorOutputSupported()) return; 1314 1315 List<Integer> availableAntiBandingModes = 1316 Arrays.asList(toObject(mStaticInfo.getAeAvailableAntiBandingModesChecked())); 1317 1318 if (availableAntiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO)) { 1319 mCollector.expectKeyValueEquals(request, CONTROL_AE_ANTIBANDING_MODE, 1320 CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO); 1321 } else { 1322 mCollector.expectKeyValueIsIn(request, CONTROL_AE_ANTIBANDING_MODE, 1323 CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ, 1324 CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ); 1325 } 1326 } 1327 1328 /** 1329 * <p>Check if 3A metering settings are "up to HAL" in request template</p> 1330 * 1331 * <p>This function doesn't fail the test immediately, it updates the 1332 * test pass/fail status and appends the failure message to the error collector each key.</p> 1333 * 1334 * @param regions The metering rectangles to be checked 1335 */ checkMeteringRect(MeteringRectangle[] regions)1336 private void checkMeteringRect(MeteringRectangle[] regions) { 1337 if (regions == null) { 1338 return; 1339 } 1340 mCollector.expectNotEquals("Number of metering region should not be 0", 0, regions.length); 1341 for (int i = 0; i < regions.length; i++) { 1342 mCollector.expectEquals("Default metering regions should have all zero weight", 1343 0, regions[i].getMeteringWeight()); 1344 } 1345 } 1346 1347 /** 1348 * <p>Check if the request settings are suitable for a given request template.</p> 1349 * 1350 * <p>This function doesn't fail the test immediately, it updates the 1351 * test pass/fail status and appends the failure message to the error collector each key.</p> 1352 * 1353 * @param request The request to be checked. 1354 * @param template The capture template targeted by this request. 1355 * @param props The CameraCharacteristics this request is checked against with. 1356 */ checkRequestForTemplate(CaptureRequest.Builder request, int template, CameraCharacteristics props)1357 private void checkRequestForTemplate(CaptureRequest.Builder request, int template, 1358 CameraCharacteristics props) { 1359 // 3A settings--control.mode. 1360 if (template != CameraDevice.TEMPLATE_MANUAL) { 1361 mCollector.expectKeyValueEquals(request, CONTROL_MODE, 1362 CaptureRequest.CONTROL_MODE_AUTO); 1363 } 1364 1365 // 3A settings--AE/AWB/AF. 1366 Integer maxRegionsAeVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE); 1367 int maxRegionsAe = maxRegionsAeVal != null ? maxRegionsAeVal : 0; 1368 Integer maxRegionsAwbVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB); 1369 int maxRegionsAwb = maxRegionsAwbVal != null ? maxRegionsAwbVal : 0; 1370 Integer maxRegionsAfVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF); 1371 int maxRegionsAf = maxRegionsAfVal != null ? maxRegionsAfVal : 0; 1372 1373 checkFpsRange(request, template, props); 1374 1375 checkAfMode(request, template, props); 1376 checkAntiBandingMode(request, template); 1377 1378 if (template == CameraDevice.TEMPLATE_MANUAL) { 1379 mCollector.expectKeyValueEquals(request, CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF); 1380 mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE, 1381 CaptureRequest.CONTROL_AE_MODE_OFF); 1382 mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE, 1383 CaptureRequest.CONTROL_AWB_MODE_OFF); 1384 } else { 1385 if (mStaticInfo.isColorOutputSupported()) { 1386 mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE, 1387 CaptureRequest.CONTROL_AE_MODE_ON); 1388 mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0); 1389 mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER, 1390 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1391 // if AE lock is not supported, expect the control key to be non-exist or false 1392 if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) { 1393 mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false); 1394 } 1395 1396 mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER, 1397 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1398 1399 mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE, 1400 CaptureRequest.CONTROL_AWB_MODE_AUTO); 1401 // if AWB lock is not supported, expect the control key to be non-exist or false 1402 if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) { 1403 mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false); 1404 } 1405 1406 // Check 3A regions. 1407 if (VERBOSE) { 1408 Log.v(TAG, String.format("maxRegions is: {AE: %s, AWB: %s, AF: %s}", 1409 maxRegionsAe, maxRegionsAwb, maxRegionsAf)); 1410 } 1411 if (maxRegionsAe > 0) { 1412 mCollector.expectKeyValueNotNull(request, CONTROL_AE_REGIONS); 1413 MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS); 1414 checkMeteringRect(aeRegions); 1415 } 1416 if (maxRegionsAwb > 0) { 1417 mCollector.expectKeyValueNotNull(request, CONTROL_AWB_REGIONS); 1418 MeteringRectangle[] awbRegions = request.get(CONTROL_AWB_REGIONS); 1419 checkMeteringRect(awbRegions); 1420 } 1421 if (maxRegionsAf > 0) { 1422 mCollector.expectKeyValueNotNull(request, CONTROL_AF_REGIONS); 1423 MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS); 1424 checkMeteringRect(afRegions); 1425 } 1426 } 1427 } 1428 1429 // Sensor settings. 1430 1431 mCollector.expectEquals("Lens aperture must be present in request if available apertures " + 1432 "are present in metadata, and vice-versa.", 1433 mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES), 1434 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_APERTURE)); 1435 if (mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES)) { 1436 float[] availableApertures = 1437 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES); 1438 if (availableApertures.length > 1) { 1439 mCollector.expectKeyValueNotNull(request, LENS_APERTURE); 1440 } 1441 } 1442 1443 mCollector.expectEquals("Lens filter density must be present in request if available " + 1444 "filter densities are present in metadata, and vice-versa.", 1445 mStaticInfo.areKeysAvailable(CameraCharacteristics. 1446 LENS_INFO_AVAILABLE_FILTER_DENSITIES), 1447 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FILTER_DENSITY)); 1448 if (mStaticInfo.areKeysAvailable(CameraCharacteristics. 1449 LENS_INFO_AVAILABLE_FILTER_DENSITIES)) { 1450 float[] availableFilters = 1451 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES); 1452 if (availableFilters.length > 1) { 1453 mCollector.expectKeyValueNotNull(request, LENS_FILTER_DENSITY); 1454 } 1455 } 1456 1457 float[] availableFocalLen = 1458 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); 1459 if (availableFocalLen.length > 1) { 1460 mCollector.expectKeyValueNotNull(request, LENS_FOCAL_LENGTH); 1461 } 1462 1463 mCollector.expectEquals("Lens optical stabilization must be present in request if " + 1464 "available optical stabilizations are present in metadata, and vice-versa.", 1465 mStaticInfo.areKeysAvailable(CameraCharacteristics. 1466 LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION), 1467 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE)); 1468 if (mStaticInfo.areKeysAvailable(CameraCharacteristics. 1469 LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) { 1470 int[] availableOIS = 1471 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION); 1472 if (availableOIS.length > 1) { 1473 mCollector.expectKeyValueNotNull(request, LENS_OPTICAL_STABILIZATION_MODE); 1474 } 1475 } 1476 1477 if (mStaticInfo.areKeysAvailable(BLACK_LEVEL_LOCK)) { 1478 mCollector.expectKeyValueEquals(request, BLACK_LEVEL_LOCK, false); 1479 } 1480 1481 if (mStaticInfo.areKeysAvailable(SENSOR_FRAME_DURATION)) { 1482 mCollector.expectKeyValueNotNull(request, SENSOR_FRAME_DURATION); 1483 } 1484 1485 if (mStaticInfo.areKeysAvailable(SENSOR_EXPOSURE_TIME)) { 1486 mCollector.expectKeyValueNotNull(request, SENSOR_EXPOSURE_TIME); 1487 } 1488 1489 if (mStaticInfo.areKeysAvailable(SENSOR_SENSITIVITY)) { 1490 mCollector.expectKeyValueNotNull(request, SENSOR_SENSITIVITY); 1491 } 1492 1493 // ISP-processing settings. 1494 if (mStaticInfo.isColorOutputSupported()) { 1495 mCollector.expectKeyValueEquals( 1496 request, STATISTICS_FACE_DETECT_MODE, 1497 CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF); 1498 mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); 1499 } 1500 1501 List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked(); 1502 if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) { 1503 // If the device doesn't support RAW, all template should have OFF as default. 1504 if (!availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 1505 mCollector.expectKeyValueEquals( 1506 request, STATISTICS_LENS_SHADING_MAP_MODE, 1507 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF); 1508 } 1509 } 1510 1511 // Edge enhancement and noise reduction modes 1512 boolean supportReprocessing = 1513 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) || 1514 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 1515 1516 if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) { 1517 // Not enforce high quality here, as some devices may not effectively have high quality 1518 // mode. 1519 if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_MODE)) { 1520 mCollector.expectKeyValueNotEquals( 1521 request, COLOR_CORRECTION_MODE, 1522 CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX); 1523 } 1524 1525 mCollector.expectEquals("Edge mode must be present in request if " + 1526 "available edge modes are present in metadata, and vice-versa.", 1527 mStaticInfo.areKeysAvailable(CameraCharacteristics. 1528 EDGE_AVAILABLE_EDGE_MODES), 1529 mStaticInfo.areKeysAvailable(CaptureRequest.EDGE_MODE)); 1530 if (mStaticInfo.areKeysAvailable(EDGE_MODE)) { 1531 List<Integer> availableEdgeModes = 1532 Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked())); 1533 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY)) { 1534 mCollector.expectKeyValueEquals(request, EDGE_MODE, 1535 CaptureRequest.EDGE_MODE_HIGH_QUALITY); 1536 } else if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) { 1537 mCollector.expectKeyValueEquals(request, EDGE_MODE, 1538 CaptureRequest.EDGE_MODE_FAST); 1539 } else { 1540 mCollector.expectKeyValueEquals(request, EDGE_MODE, 1541 CaptureRequest.EDGE_MODE_OFF); 1542 } 1543 } 1544 1545 mCollector.expectEquals("Noise reduction mode must be present in request if " + 1546 "available noise reductions are present in metadata, and vice-versa.", 1547 mStaticInfo.areKeysAvailable(CameraCharacteristics. 1548 NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES), 1549 mStaticInfo.areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE)); 1550 if (mStaticInfo.areKeysAvailable( 1551 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) { 1552 List<Integer> availableNoiseReductionModes = 1553 Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked())); 1554 if (availableNoiseReductionModes 1555 .contains(CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) { 1556 mCollector.expectKeyValueEquals( 1557 request, NOISE_REDUCTION_MODE, 1558 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 1559 } else if (availableNoiseReductionModes 1560 .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) { 1561 mCollector.expectKeyValueEquals( 1562 request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_FAST); 1563 } else { 1564 mCollector.expectKeyValueEquals( 1565 request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF); 1566 } 1567 } 1568 } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && supportReprocessing) { 1569 mCollector.expectKeyValueEquals(request, EDGE_MODE, 1570 CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 1571 mCollector.expectKeyValueEquals(request, NOISE_REDUCTION_MODE, 1572 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 1573 } else { 1574 if (mStaticInfo.areKeysAvailable(EDGE_MODE)) { 1575 mCollector.expectKeyValueNotNull(request, EDGE_MODE); 1576 } 1577 1578 if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) { 1579 mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE); 1580 } 1581 } 1582 1583 // Tone map and lens shading modes. 1584 if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) { 1585 mCollector.expectEquals("Tonemap mode must be present in request if " + 1586 "available tonemap modes are present in metadata, and vice-versa.", 1587 mStaticInfo.areKeysAvailable(CameraCharacteristics. 1588 TONEMAP_AVAILABLE_TONE_MAP_MODES), 1589 mStaticInfo.areKeysAvailable(CaptureRequest.TONEMAP_MODE)); 1590 if (mStaticInfo.areKeysAvailable( 1591 CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES)) { 1592 List<Integer> availableToneMapModes = 1593 Arrays.asList(toObject(mStaticInfo.getAvailableToneMapModesChecked())); 1594 if (availableToneMapModes.contains(CaptureRequest.TONEMAP_MODE_HIGH_QUALITY)) { 1595 mCollector.expectKeyValueEquals(request, TONEMAP_MODE, 1596 CaptureRequest.TONEMAP_MODE_HIGH_QUALITY); 1597 } else { 1598 mCollector.expectKeyValueEquals(request, TONEMAP_MODE, 1599 CaptureRequest.TONEMAP_MODE_FAST); 1600 } 1601 } 1602 1603 // Still capture template should have android.statistics.lensShadingMapMode ON when 1604 // RAW capability is supported. 1605 if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE) && 1606 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 1607 mCollector.expectKeyValueEquals(request, STATISTICS_LENS_SHADING_MAP_MODE, 1608 STATISTICS_LENS_SHADING_MAP_MODE_ON); 1609 } 1610 } else { 1611 if (mStaticInfo.areKeysAvailable(TONEMAP_MODE)) { 1612 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, 1613 CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE); 1614 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, 1615 CaptureRequest.TONEMAP_MODE_GAMMA_VALUE); 1616 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, 1617 CaptureRequest.TONEMAP_MODE_PRESET_CURVE); 1618 } 1619 if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) { 1620 mCollector.expectKeyValueNotNull(request, STATISTICS_LENS_SHADING_MAP_MODE); 1621 } 1622 } 1623 1624 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, template); 1625 1626 // TODO: use the list of keys from CameraCharacteristics to avoid expecting 1627 // keys which are not available by this CameraDevice. 1628 } 1629 captureTemplateTestByCamera(String cameraId, int template)1630 private void captureTemplateTestByCamera(String cameraId, int template) throws Exception { 1631 try { 1632 openDevice(cameraId, mCameraMockListener); 1633 1634 assertTrue("Camera template " + template + " is out of range!", 1635 template >= CameraDevice.TEMPLATE_PREVIEW 1636 && template <= CameraDevice.TEMPLATE_MANUAL); 1637 1638 mCollector.setCameraId(cameraId); 1639 1640 try { 1641 CaptureRequest.Builder request = mCamera.createCaptureRequest(template); 1642 assertNotNull("Failed to create capture request for template " + template, request); 1643 1644 CameraCharacteristics props = mStaticInfo.getCharacteristics(); 1645 checkRequestForTemplate(request, template, props); 1646 } catch (IllegalArgumentException e) { 1647 if (template == CameraDevice.TEMPLATE_MANUAL && 1648 !mStaticInfo.isCapabilitySupported(CameraCharacteristics. 1649 REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1650 // OK 1651 } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && 1652 !mStaticInfo.isCapabilitySupported(CameraCharacteristics. 1653 REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING)) { 1654 // OK. 1655 } else if (sLegacySkipTemplates.contains(template) && 1656 mStaticInfo.isHardwareLevelLegacy()) { 1657 // OK 1658 } else if (template != CameraDevice.TEMPLATE_PREVIEW && 1659 mStaticInfo.isDepthOutputSupported() && 1660 !mStaticInfo.isColorOutputSupported()) { 1661 // OK, depth-only devices need only support PREVIEW template 1662 } else { 1663 throw e; // rethrow 1664 } 1665 } 1666 } 1667 finally { 1668 try { 1669 closeSession(); 1670 } finally { 1671 closeDevice(cameraId, mCameraMockListener); 1672 } 1673 } 1674 } 1675 1676 /** 1677 * Start capture with given {@link #CaptureRequest}. 1678 * 1679 * @param request The {@link #CaptureRequest} to be captured. 1680 * @param repeating If the capture is single capture or repeating. 1681 * @param listener The {@link #CaptureCallback} camera device used to notify callbacks. 1682 * @param handler The handler camera device used to post callbacks. 1683 */ startCapture(CaptureRequest request, boolean repeating, CameraCaptureSession.CaptureCallback listener, Handler handler)1684 protected void startCapture(CaptureRequest request, boolean repeating, 1685 CameraCaptureSession.CaptureCallback listener, Handler handler) 1686 throws CameraAccessException { 1687 if (VERBOSE) Log.v(TAG, "Starting capture from session"); 1688 1689 if (repeating) { 1690 mSession.setRepeatingRequest(request, listener, handler); 1691 } else { 1692 mSession.capture(request, listener, handler); 1693 } 1694 } 1695 1696 /** 1697 * Close a {@link #CameraCaptureSession capture session}; blocking until 1698 * the close finishes with a transition to {@link CameraCaptureSession.StateCallback#onClosed}. 1699 */ closeSession()1700 protected void closeSession() { 1701 if (mSession == null) { 1702 return; 1703 } 1704 1705 mSession.close(); 1706 waitForSessionState(SESSION_CLOSED, SESSION_CLOSE_TIMEOUT_MS); 1707 mSession = null; 1708 1709 mSessionMockListener = null; 1710 mSessionWaiter = null; 1711 } 1712 1713 /** 1714 * A camera capture session listener that keeps all the configured and closed sessions. 1715 */ 1716 private class MultipleSessionCallback extends CameraCaptureSession.StateCallback { 1717 public static final int SESSION_CONFIGURED = 0; 1718 public static final int SESSION_CLOSED = 1; 1719 1720 final List<CameraCaptureSession> mSessions = new ArrayList<>(); 1721 final Map<CameraCaptureSession, Integer> mSessionStates = new HashMap<>(); 1722 CameraCaptureSession mCurrentConfiguredSession = null; 1723 1724 final ReentrantLock mLock = new ReentrantLock(); 1725 final Condition mNewStateCond = mLock.newCondition(); 1726 1727 final boolean mFailOnConfigureFailed; 1728 1729 /** 1730 * If failOnConfigureFailed is true, it calls fail() when onConfigureFailed() is invoked 1731 * for any session. 1732 */ MultipleSessionCallback(boolean failOnConfigureFailed)1733 public MultipleSessionCallback(boolean failOnConfigureFailed) { 1734 mFailOnConfigureFailed = failOnConfigureFailed; 1735 } 1736 1737 @Override onClosed(CameraCaptureSession session)1738 public void onClosed(CameraCaptureSession session) { 1739 mLock.lock(); 1740 mSessionStates.put(session, SESSION_CLOSED); 1741 mNewStateCond.signal(); 1742 mLock.unlock(); 1743 } 1744 1745 @Override onConfigured(CameraCaptureSession session)1746 public void onConfigured(CameraCaptureSession session) { 1747 mLock.lock(); 1748 mSessions.add(session); 1749 mSessionStates.put(session, SESSION_CONFIGURED); 1750 mNewStateCond.signal(); 1751 mLock.unlock(); 1752 } 1753 1754 @Override onConfigureFailed(CameraCaptureSession session)1755 public void onConfigureFailed(CameraCaptureSession session) { 1756 if (mFailOnConfigureFailed) { 1757 fail("Configuring a session failed"); 1758 } 1759 } 1760 1761 /** 1762 * Get a number of sessions that have been configured. 1763 */ getAllSessions(int numSessions, int timeoutMs)1764 public List<CameraCaptureSession> getAllSessions(int numSessions, int timeoutMs) 1765 throws Exception { 1766 long remainingTime = timeoutMs; 1767 mLock.lock(); 1768 try { 1769 while (mSessions.size() < numSessions) { 1770 long startTime = SystemClock.elapsedRealtime(); 1771 boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS); 1772 remainingTime -= (SystemClock.elapsedRealtime() - startTime); 1773 ret &= remainingTime > 0; 1774 1775 assertTrue("Get " + numSessions + " sessions timed out after " + timeoutMs + 1776 "ms", ret); 1777 } 1778 1779 return mSessions; 1780 } finally { 1781 mLock.unlock(); 1782 } 1783 } 1784 1785 /** 1786 * Wait until a previously-configured sessoin is closed or it times out. 1787 */ waitForSessionClose(CameraCaptureSession session, int timeoutMs)1788 public void waitForSessionClose(CameraCaptureSession session, int timeoutMs) throws Exception { 1789 long remainingTime = timeoutMs; 1790 mLock.lock(); 1791 try { 1792 while (mSessionStates.get(session).equals(SESSION_CLOSED) == false) { 1793 long startTime = SystemClock.elapsedRealtime(); 1794 boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS); 1795 remainingTime -= (SystemClock.elapsedRealtime() - startTime); 1796 ret &= remainingTime > 0; 1797 1798 assertTrue("Wait for session close timed out after " + timeoutMs + "ms", ret); 1799 } 1800 } finally { 1801 mLock.unlock(); 1802 } 1803 } 1804 } 1805 } 1806