1 /* 2 * Copyright (C) 2014 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.testcases; 18 19 import static android.hardware.camera2.cts.CameraTestUtils.CAMERA_CLOSE_TIMEOUT_MS; 20 import static android.hardware.camera2.cts.CameraTestUtils.PREVIEW_SIZE_BOUND; 21 import static android.hardware.camera2.cts.CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS; 22 import static android.hardware.camera2.cts.CameraTestUtils.SESSION_CONFIGURE_TIMEOUT_MS; 23 import static android.hardware.camera2.cts.CameraTestUtils.SESSION_READY_TIMEOUT_MS; 24 import static android.hardware.camera2.cts.CameraTestUtils.assertFalse; 25 import static android.hardware.camera2.cts.CameraTestUtils.assertNotNull; 26 import static android.hardware.camera2.cts.CameraTestUtils.assertNull; 27 import static android.hardware.camera2.cts.CameraTestUtils.assertTrue; 28 import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationSupported; 29 import static android.hardware.camera2.cts.CameraTestUtils.configureCameraSession; 30 import static android.hardware.camera2.cts.CameraTestUtils.configureCameraSessionWithConfig; 31 import static android.hardware.camera2.cts.CameraTestUtils.getPreviewSizeBound; 32 import static android.hardware.camera2.cts.CameraTestUtils.getSupportedPreviewSizes; 33 import static android.hardware.camera2.cts.CameraTestUtils.isSessionConfigSupported; 34 35 import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED; 36 import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_READY; 37 import static com.android.ex.camera2.blocking.BlockingStateCallback.STATE_CLOSED; 38 39 import android.app.Activity; 40 import android.content.Context; 41 import android.content.res.Configuration; 42 import android.graphics.Matrix; 43 import android.graphics.RectF; 44 import android.graphics.SurfaceTexture; 45 import android.hardware.camera2.CameraCaptureSession; 46 import android.hardware.camera2.CameraCaptureSession.CaptureCallback; 47 import android.hardware.camera2.CameraDevice; 48 import android.hardware.camera2.CaptureRequest; 49 import android.hardware.camera2.cts.Camera2MultiViewCtsActivity; 50 import android.hardware.camera2.cts.Camera2ParameterizedTestCase; 51 import android.hardware.camera2.cts.helpers.StaticMetadata; 52 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel; 53 import android.hardware.camera2.params.OutputConfiguration; 54 import android.hardware.camera2.params.SessionConfiguration; 55 import android.os.ConditionVariable; 56 import android.os.Handler; 57 import android.os.HandlerThread; 58 import android.os.Looper; 59 import android.util.Log; 60 import android.util.Size; 61 import android.view.Surface; 62 import android.view.TextureView; 63 import android.view.WindowManager; 64 65 import androidx.test.rule.ActivityTestRule; 66 67 import com.android.ex.camera2.blocking.BlockingCameraManager; 68 import com.android.ex.camera2.blocking.BlockingSessionCallback; 69 import com.android.ex.camera2.blocking.BlockingStateCallback; 70 71 import junit.framework.Assert; 72 73 import org.junit.Rule; 74 75 import java.util.Arrays; 76 import java.util.HashMap; 77 import java.util.List; 78 79 /** 80 * Camera2 test case base class by using mixed SurfaceView and TextureView as rendering target. 81 */ 82 83 public class Camera2MultiViewTestCase extends Camera2ParameterizedTestCase { 84 private static final String TAG = "MultiViewTestCase"; 85 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 86 87 protected TextureView[] mTextureView = 88 new TextureView[Camera2MultiViewCtsActivity.MAX_TEXTURE_VIEWS]; 89 protected Handler mHandler; 90 91 private HandlerThread mHandlerThread; 92 private Activity mActivity; 93 94 private CameraHolder[] mCameraHolders; 95 private HashMap<String, Integer> mCameraIdMap; 96 97 protected WindowManager mWindowManager; 98 99 @Rule 100 public ActivityTestRule<Camera2MultiViewCtsActivity> mActivityRule = 101 new ActivityTestRule<>(Camera2MultiViewCtsActivity.class); 102 103 @Override setUp()104 public void setUp() throws Exception { 105 super.setUp(); 106 mActivity = mActivityRule.getActivity(); 107 mHandlerThread = new HandlerThread(TAG); 108 mHandlerThread.start(); 109 mHandler = new Handler(mHandlerThread.getLooper()); 110 Camera2MultiViewCtsActivity activity = (Camera2MultiViewCtsActivity) mActivity; 111 for (int i = 0; i < Camera2MultiViewCtsActivity.MAX_TEXTURE_VIEWS; i++) { 112 mTextureView[i] = activity.getTextureView(i); 113 } 114 assertNotNull("Unable to get texture view", mTextureView); 115 mCameraIdMap = new HashMap<String, Integer>(); 116 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 117 int numCameras = cameraIdsUnderTest.length; 118 mCameraHolders = new CameraHolder[numCameras]; 119 for (int i = 0; i < numCameras; i++) { 120 mCameraHolders[i] = new CameraHolder(cameraIdsUnderTest[i]); 121 mCameraIdMap.put(cameraIdsUnderTest[i], i); 122 } 123 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 124 } 125 126 @Override tearDown()127 public void tearDown() throws Exception { 128 mHandlerThread.quitSafely(); 129 mHandler = null; 130 for (CameraHolder camera : mCameraHolders) { 131 if (camera.isOpened()) { 132 camera.close(); 133 camera = null; 134 } 135 } 136 super.tearDown(); 137 } 138 139 /** 140 * Update preview TextureView rotation to accommodate discrepancy between preview 141 * buffer and the view window orientation. 142 * 143 * Assumptions: 144 * - Aspect ratio for the sensor buffers is in landscape orientation, 145 * - Dimensions of buffers received are rotated to the natural device orientation. 146 * - The contents of each buffer are rotated by the inverse of the display rotation. 147 * - Surface scales the buffer to fit the current view bounds. 148 * TODO: Make this method works for all orientations 149 * 150 */ updatePreviewDisplayRotation(Size previewSize, TextureView textureView)151 protected void updatePreviewDisplayRotation(Size previewSize, TextureView textureView) { 152 int rotationDegrees = 0; 153 Camera2MultiViewCtsActivity activity = (Camera2MultiViewCtsActivity) mActivity; 154 155 int displayRotation = activity.getDisplay().getRotation(); 156 Configuration config = activity.getResources().getConfiguration(); 157 158 // Get UI display rotation 159 switch (displayRotation) { 160 case Surface.ROTATION_0: 161 rotationDegrees = 0; 162 break; 163 case Surface.ROTATION_90: 164 rotationDegrees = 90; 165 break; 166 case Surface.ROTATION_180: 167 rotationDegrees = 180; 168 break; 169 case Surface.ROTATION_270: 170 rotationDegrees = 270; 171 break; 172 } 173 174 // Get device natural orientation 175 int deviceOrientation = Configuration.ORIENTATION_PORTRAIT; 176 if ((rotationDegrees % 180 == 0 && 177 config.orientation == Configuration.ORIENTATION_LANDSCAPE) || 178 ((rotationDegrees % 180 != 0 && 179 config.orientation == Configuration.ORIENTATION_PORTRAIT))) { 180 deviceOrientation = Configuration.ORIENTATION_LANDSCAPE; 181 } 182 183 // Rotate the buffer dimensions if device orientation is portrait. 184 int effectiveWidth = previewSize.getWidth(); 185 int effectiveHeight = previewSize.getHeight(); 186 if (deviceOrientation == Configuration.ORIENTATION_PORTRAIT) { 187 effectiveWidth = previewSize.getHeight(); 188 effectiveHeight = previewSize.getWidth(); 189 } 190 191 // Find and center view rect and buffer rect 192 Matrix transformMatrix = textureView.getTransform(null); 193 int viewWidth = textureView.getWidth(); 194 int viewHeight = textureView.getHeight(); 195 RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); 196 RectF bufRect = new RectF(0, 0, effectiveWidth, effectiveHeight); 197 float centerX = viewRect.centerX(); 198 float centerY = viewRect.centerY(); 199 bufRect.offset(centerX - bufRect.centerX(), centerY - bufRect.centerY()); 200 201 // Undo ScaleToFit.FILL done by the surface 202 transformMatrix.setRectToRect(viewRect, bufRect, Matrix.ScaleToFit.FILL); 203 204 // Rotate buffer contents to proper orientation 205 transformMatrix.postRotate((360 - rotationDegrees) % 360, centerX, centerY); 206 if ((rotationDegrees % 180) == 90) { 207 int temp = effectiveWidth; 208 effectiveWidth = effectiveHeight; 209 effectiveHeight = temp; 210 } 211 212 // Scale to fit view, cropping the longest dimension 213 float scale = 214 Math.max(viewWidth / (float) effectiveWidth, viewHeight / (float) effectiveHeight); 215 transformMatrix.postScale(scale, scale, centerX, centerY); 216 217 Handler handler = new Handler(Looper.getMainLooper()); 218 class TransformUpdater implements Runnable { 219 TextureView mView; 220 Matrix mTransformMatrix; 221 TransformUpdater(TextureView view, Matrix matrix) { 222 mView = view; 223 mTransformMatrix = matrix; 224 } 225 226 @Override 227 public void run() { 228 mView.setTransform(mTransformMatrix); 229 } 230 } 231 handler.post(new TransformUpdater(textureView, transformMatrix)); 232 } 233 openCamera(String cameraId)234 protected void openCamera(String cameraId) throws Exception { 235 CameraHolder camera = getCameraHolder(cameraId); 236 assertFalse("Camera has already opened", camera.isOpened()); 237 camera.open(); 238 return; 239 } 240 closeCamera(String cameraId)241 protected void closeCamera(String cameraId) throws Exception { 242 CameraHolder camera = getCameraHolder(cameraId); 243 camera.close(); 244 } 245 createSessionWithConfigs(String cameraId, List<OutputConfiguration> configs)246 protected void createSessionWithConfigs(String cameraId, List<OutputConfiguration> configs) 247 throws Exception { 248 CameraHolder camera = getCameraHolder(cameraId); 249 camera.createSessionWithConfigs(configs); 250 } 251 startPreview( String cameraId, List<Surface> outputSurfaces, CaptureCallback listener)252 protected void startPreview( 253 String cameraId, List<Surface> outputSurfaces, CaptureCallback listener) 254 throws Exception { 255 CameraHolder camera = getCameraHolder(cameraId); 256 assertTrue("Camera " + cameraId + " is not openned", camera.isOpened()); 257 camera.startPreview(outputSurfaces, listener); 258 } 259 startPreviewWithConfigs(String cameraId, List<OutputConfiguration> outputConfigs, CaptureCallback listener)260 protected int startPreviewWithConfigs(String cameraId, 261 List<OutputConfiguration> outputConfigs, 262 CaptureCallback listener) 263 throws Exception { 264 CameraHolder camera = getCameraHolder(cameraId); 265 assertTrue("Camera " + cameraId + " is not openned", camera.isOpened()); 266 return camera.startPreviewWithConfigs(outputConfigs, listener); 267 } 268 stopPreview(String cameraId)269 protected void stopPreview(String cameraId) throws Exception { 270 CameraHolder camera = getCameraHolder(cameraId); 271 assertTrue("Camera " + cameraId + " preview is not running", camera.isPreviewStarted()); 272 camera.stopPreview(); 273 } 274 stopRepeating(String cameraId)275 protected void stopRepeating(String cameraId) throws Exception { 276 CameraHolder camera = getCameraHolder(cameraId); 277 assertTrue("Camera " + cameraId + " preview is not running", camera.isPreviewStarted()); 278 camera.stopRepeating(); 279 } 280 finalizeOutputConfigs(String cameraId, List<OutputConfiguration> configs, CaptureCallback listener)281 protected void finalizeOutputConfigs(String cameraId, List<OutputConfiguration> configs, 282 CaptureCallback listener) throws Exception { 283 CameraHolder camera = getCameraHolder(cameraId); 284 assertTrue("Camera " + cameraId + " is not opened", camera.isOpened()); 285 camera.finalizeOutputConfigs(configs, listener); 286 } 287 updateRepeatingRequest(String cameraId, List<OutputConfiguration> configs, CaptureCallback listener)288 protected int updateRepeatingRequest(String cameraId, List<OutputConfiguration> configs, 289 CaptureCallback listener) throws Exception { 290 CameraHolder camera = getCameraHolder(cameraId); 291 assertTrue("Camera " + cameraId + " is not opened", camera.isOpened()); 292 return camera.updateRepeatingRequest(configs, listener); 293 } 294 updateOutputConfiguration(String cameraId, OutputConfiguration config)295 protected void updateOutputConfiguration(String cameraId, OutputConfiguration config) 296 throws Exception { 297 CameraHolder camera = getCameraHolder(cameraId); 298 assertTrue("Camera " + cameraId + " is not opened", camera.isOpened()); 299 camera.updateOutputConfiguration(config); 300 } 301 isSessionConfigurationSupported(String cameraId, List<OutputConfiguration> configs)302 protected boolean isSessionConfigurationSupported(String cameraId, 303 List<OutputConfiguration> configs) throws Exception { 304 CameraHolder camera = getCameraHolder(cameraId); 305 assertTrue("Camera " + cameraId + " is not opened", camera.isOpened()); 306 return camera.isSessionConfigurationSupported(configs); 307 } 308 capture(String cameraId, CaptureRequest request, CaptureCallback listener)309 protected void capture(String cameraId, CaptureRequest request, CaptureCallback listener) 310 throws Exception { 311 CameraHolder camera = getCameraHolder(cameraId); 312 assertTrue("Camera " + cameraId + " is not opened", camera.isOpened()); 313 camera.capture(request, listener); 314 } 315 getCaptureBuilder(String cameraId, int templateId)316 protected CaptureRequest.Builder getCaptureBuilder(String cameraId, int templateId) 317 throws Exception { 318 CameraHolder camera = getCameraHolder(cameraId); 319 assertTrue("Camera " + cameraId + " is not opened", camera.isOpened()); 320 return camera.getCaptureBuilder(templateId); 321 } 322 getStaticInfo(String cameraId)323 protected StaticMetadata getStaticInfo(String cameraId) { 324 CameraHolder camera = getCameraHolder(cameraId); 325 StaticMetadata staticInfo = camera.getStaticInfo(); 326 assertNotNull("Camera " + cameraId + " static info is null", staticInfo); 327 return staticInfo; 328 } 329 getOrderedPreviewSizes(String cameraId)330 protected List<Size> getOrderedPreviewSizes(String cameraId) { 331 CameraHolder camera = getCameraHolder(cameraId); 332 assertTrue("Camera is not openned", camera.isOpened()); 333 return camera.getOrderedPreviewSizes(); 334 } 335 verifyCreateSessionWithConfigsFailure(String cameraId, List<OutputConfiguration> configs)336 protected void verifyCreateSessionWithConfigsFailure(String cameraId, 337 List<OutputConfiguration> configs) throws Exception { 338 CameraHolder camera = getCameraHolder(cameraId); 339 camera.verifyCreateSessionWithConfigsFailure(configs); 340 } 341 342 public static class CameraPreviewListener implements TextureView.SurfaceTextureListener { 343 private boolean mFirstPreviewAvailable = false; 344 private float[] mTransformMatrix = new float[16]; 345 private final ConditionVariable mPreviewDone = new ConditionVariable(); 346 347 @Override onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)348 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 349 // Ignored. The SurfaceTexture is polled by getAvailableSurfaceTexture. 350 } 351 352 @Override onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)353 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 354 // Ignored. The CameraDevice should already know the changed size. 355 } 356 357 @Override onSurfaceTextureDestroyed(SurfaceTexture surface)358 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 359 /** 360 * Return true, assume that client detaches the surface before it is 361 * destroyed. For example, CameraDevice should detach this surface when 362 * stopping preview. No need to release the SurfaceTexture here as it 363 * is released by TextureView after onSurfaceTextureDestroyed is called. 364 */ 365 Log.i(TAG, "onSurfaceTextureDestroyed called."); 366 return true; 367 } 368 369 @Override onSurfaceTextureUpdated(SurfaceTexture surface)370 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 371 // Invoked every time there's a new Camera preview frame 372 if (!mFirstPreviewAvailable) { 373 mFirstPreviewAvailable = true; 374 mPreviewDone.open(); 375 } 376 377 synchronized(this) { 378 surface.getTransformMatrix(mTransformMatrix); 379 } 380 } 381 382 /** Waits until the camera preview is up running */ waitForPreviewDone(long timeOutMs)383 public boolean waitForPreviewDone(long timeOutMs) { 384 if (!mPreviewDone.block(timeOutMs)) { 385 // timeout could be expected or unexpected. The caller will decide. 386 Log.w(TAG, "waitForPreviewDone timed out after " + timeOutMs + "ms"); 387 return false; 388 } 389 mPreviewDone.close(); 390 return true; 391 } 392 getPreviewTransform()393 public synchronized float[] getPreviewTransform() { 394 return mTransformMatrix; 395 } 396 397 /** Reset the Listener */ reset()398 public void reset() { 399 mFirstPreviewAvailable = false; 400 mPreviewDone.close(); 401 } 402 } 403 getCameraHolder(String cameraId)404 private CameraHolder getCameraHolder(String cameraId) { 405 Integer cameraIdx = mCameraIdMap.get(cameraId); 406 if (cameraIdx == null) { 407 Assert.fail("Unknown camera Id"); 408 } 409 return mCameraHolders[cameraIdx]; 410 } 411 412 // Per device fields 413 private class CameraHolder { 414 private String mCameraId; 415 private CameraStateListener mCameraStateListener; 416 private BlockingStateCallback mBlockingStateListener; 417 private CameraCaptureSession mSession; 418 private CameraDevice mCamera; 419 private StaticMetadata mStaticInfo; 420 private List<Size> mOrderedPreviewSizes; 421 private BlockingSessionCallback mSessionListener; 422 CameraHolder(String id)423 public CameraHolder(String id){ 424 mCameraId = id; 425 mCameraStateListener = new CameraStateListener(); 426 } 427 getStaticInfo()428 public StaticMetadata getStaticInfo() { 429 return mStaticInfo; 430 } 431 getOrderedPreviewSizes()432 public List<Size> getOrderedPreviewSizes() { 433 return mOrderedPreviewSizes; 434 } 435 436 class CameraStateListener extends CameraDevice.StateCallback { 437 boolean mDisconnected = false; 438 439 @Override onOpened(CameraDevice camera)440 public void onOpened(CameraDevice camera) { 441 } 442 443 @Override onDisconnected(CameraDevice camera)444 public void onDisconnected(CameraDevice camera) { 445 synchronized(this) { 446 mDisconnected = true; 447 } 448 } 449 450 @Override onError(CameraDevice camera, int error)451 public void onError(CameraDevice camera, int error) { 452 } 453 isDisconnected()454 public synchronized boolean isDisconnected() { 455 return mDisconnected; 456 } 457 } 458 open()459 public void open() throws Exception { 460 assertNull("Camera is already opened", mCamera); 461 mBlockingStateListener = new BlockingStateCallback(mCameraStateListener); 462 mCamera = (new BlockingCameraManager(mCameraManager)).openCamera( 463 mCameraId, mBlockingStateListener, mHandler); 464 mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(mCameraId), 465 CheckLevel.ASSERT, /*collector*/null); 466 if (mStaticInfo.isColorOutputSupported()) { 467 mOrderedPreviewSizes = getSupportedPreviewSizes( 468 mCameraId, mCameraManager, 469 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND)); 470 } 471 assertNotNull(String.format("Failed to open camera device ID: %s", mCameraId), mCamera); 472 } 473 isOpened()474 public boolean isOpened() { 475 return (mCamera != null && !mCameraStateListener.isDisconnected()); 476 } 477 close()478 public void close() throws Exception { 479 if (!isOpened()) { 480 return; 481 } 482 mCamera.close(); 483 mBlockingStateListener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS); 484 mCamera = null; 485 mSession = null; 486 mStaticInfo = null; 487 mOrderedPreviewSizes = null; 488 mBlockingStateListener = null; 489 } 490 startPreview(List<Surface> outputSurfaces, CaptureCallback listener)491 public void startPreview(List<Surface> outputSurfaces, CaptureCallback listener) 492 throws Exception { 493 mSessionListener = new BlockingSessionCallback(); 494 mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); 495 if (outputSurfaces.isEmpty()) { 496 return; 497 } 498 499 // TODO: vary the different settings like crop region to cover more cases. 500 CaptureRequest.Builder captureBuilder = 501 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 502 503 for (Surface surface : outputSurfaces) { 504 captureBuilder.addTarget(surface); 505 } 506 mSession.setRepeatingRequest(captureBuilder.build(), listener, mHandler); 507 } 508 createSessionWithConfigs(List<OutputConfiguration> outputConfigs)509 public void createSessionWithConfigs(List<OutputConfiguration> outputConfigs) 510 throws Exception { 511 mSessionListener = new BlockingSessionCallback(); 512 mSession = configureCameraSessionWithConfig(mCamera, outputConfigs, mSessionListener, mHandler); 513 } 514 verifyCreateSessionWithConfigsFailure(List<OutputConfiguration> configs)515 public void verifyCreateSessionWithConfigsFailure(List<OutputConfiguration> configs) 516 throws Exception { 517 BlockingSessionCallback sessionListener = new BlockingSessionCallback(); 518 CameraCaptureSession session = configureCameraSessionWithConfig( 519 mCamera, configs, sessionListener, mHandler); 520 521 Integer[] sessionStates = {BlockingSessionCallback.SESSION_READY, 522 BlockingSessionCallback.SESSION_CONFIGURE_FAILED}; 523 int state = sessionListener.getStateWaiter().waitForAnyOfStates( 524 Arrays.asList(sessionStates), SESSION_CONFIGURE_TIMEOUT_MS); 525 assertTrue("Expecting a createSessionWithConfig failure.", 526 state == BlockingSessionCallback.SESSION_CONFIGURE_FAILED); 527 } 528 startPreviewWithConfigs(List<OutputConfiguration> outputConfigs, CaptureCallback listener)529 public int startPreviewWithConfigs(List<OutputConfiguration> outputConfigs, 530 CaptureCallback listener) 531 throws Exception { 532 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 533 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, mCameraManager, 534 /*defaultSupport*/ true, "Session configuration query should not fail"); 535 createSessionWithConfigs(outputConfigs); 536 537 CaptureRequest.Builder captureBuilder = 538 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 539 540 for (OutputConfiguration config : outputConfigs) { 541 for (Surface surface : config.getSurfaces()) { 542 captureBuilder.addTarget(surface); 543 } 544 } 545 return mSession.setRepeatingRequest(captureBuilder.build(), listener, mHandler); 546 } 547 updateRepeatingRequest(List<OutputConfiguration> configs, CaptureCallback listener)548 public int updateRepeatingRequest(List<OutputConfiguration> configs, 549 CaptureCallback listener) throws Exception { 550 CaptureRequest.Builder captureBuilder = 551 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 552 553 for (OutputConfiguration config : configs) { 554 for (Surface surface : config.getSurfaces()) { 555 captureBuilder.addTarget(surface); 556 } 557 } 558 return mSession.setRepeatingRequest(captureBuilder.build(), listener, mHandler); 559 } 560 updateOutputConfiguration(OutputConfiguration config)561 public void updateOutputConfiguration(OutputConfiguration config) throws Exception { 562 mSession.updateOutputConfiguration(config); 563 } 564 isSessionConfigurationSupported(List<OutputConfiguration> configs)565 public boolean isSessionConfigurationSupported(List<OutputConfiguration> configs) 566 throws Exception { 567 return isSessionConfigSupported(mCamera, mHandler, configs, 568 /*inputConig*/ null, SessionConfiguration.SESSION_REGULAR, 569 mCameraManager, /*expectedResult*/ true).configSupported; 570 } 571 capture(CaptureRequest request, CaptureCallback listener)572 public void capture(CaptureRequest request, CaptureCallback listener) 573 throws Exception { 574 mSession.capture(request, listener, mHandler); 575 } 576 getCaptureBuilder(int templateId)577 public CaptureRequest.Builder getCaptureBuilder(int templateId) throws Exception { 578 return mCamera.createCaptureRequest(templateId); 579 } 580 finalizeOutputConfigs(List<OutputConfiguration> configs, CaptureCallback listener)581 public void finalizeOutputConfigs(List<OutputConfiguration> configs, 582 CaptureCallback listener) throws Exception { 583 mSession.finalizeOutputConfigurations(configs); 584 updateRepeatingRequest(configs, listener); 585 } 586 isPreviewStarted()587 public boolean isPreviewStarted() { 588 return (mSession != null); 589 } 590 stopPreview()591 public void stopPreview() throws Exception { 592 if (VERBOSE) Log.v(TAG, 593 "Stopping camera " + mCameraId +" preview and waiting for idle"); 594 if (!isOpened()) { 595 return; 596 } 597 // Stop repeat, wait for captures to complete, and disconnect from surfaces 598 mSession.close(); 599 mSessionListener.getStateWaiter().waitForState( 600 SESSION_CLOSED, SESSION_CLOSE_TIMEOUT_MS); 601 mSessionListener = null; 602 } 603 stopRepeating()604 public void stopRepeating() throws Exception { 605 if (VERBOSE) Log.v(TAG, 606 "Stopping camera " + mCameraId +" repeating request"); 607 if (!isOpened()) { 608 return; 609 } 610 mSession.stopRepeating(); 611 mSessionListener.getStateWaiter().waitForState( 612 SESSION_READY, SESSION_READY_TIMEOUT_MS); 613 } 614 } 615 } 616