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