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