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.*; 20 import static com.android.ex.camera2.blocking.BlockingStateCallback.STATE_CLOSED; 21 22 import android.hardware.camera2.params.StreamConfigurationMap; 23 import android.media.ImageReader; 24 import android.os.Environment; 25 import android.os.Handler; 26 import android.os.HandlerThread; 27 import android.os.Looper; 28 import android.test.ActivityInstrumentationTestCase2; 29 import android.util.Log; 30 import android.view.Surface; 31 import android.view.SurfaceHolder; 32 import android.content.Context; 33 import android.graphics.ImageFormat; 34 import android.hardware.camera2.CameraAccessException; 35 import android.hardware.camera2.CameraCaptureSession; 36 import android.hardware.camera2.CameraCaptureSession.CaptureCallback; 37 import android.hardware.camera2.CameraCharacteristics; 38 import android.hardware.camera2.CameraDevice; 39 import android.hardware.camera2.CameraManager; 40 import android.hardware.camera2.CameraMetadata; 41 import android.hardware.camera2.CaptureRequest; 42 import android.hardware.camera2.CaptureResult; 43 import android.util.Size; 44 import android.util.Range; 45 import android.hardware.camera2.cts.Camera2SurfaceViewCtsActivity; 46 import android.hardware.camera2.cts.CameraTestUtils; 47 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 48 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 49 import android.hardware.camera2.cts.helpers.StaticMetadata; 50 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel; 51 52 import com.android.ex.camera2.blocking.BlockingSessionCallback; 53 import com.android.ex.camera2.blocking.BlockingStateCallback; 54 import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 55 56 import java.util.ArrayList; 57 import java.util.HashMap; 58 import java.util.List; 59 60 /** 61 * Camera2 Preview test case base class by using SurfaceView as rendering target. 62 * 63 * <p>This class encapsulates the SurfaceView based preview common functionalities. 64 * The setup and teardown of CameraManager, test HandlerThread, Activity, Camera IDs 65 * and CameraStateCallback are handled in this class. Some basic preview related utility 66 * functions are provided to facilitate the derived preview-based test classes. 67 * </p> 68 */ 69 70 public class Camera2SurfaceViewTestCase extends 71 ActivityInstrumentationTestCase2<Camera2SurfaceViewCtsActivity> { 72 private static final String TAG = "SurfaceViewTestCase"; 73 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 74 private static final int WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS = 1000; 75 76 // TODO: Use internal storage for this to make sure the file is only visible to test. 77 protected static final String DEBUG_FILE_NAME_BASE = 78 Environment.getExternalStorageDirectory().getPath(); 79 protected static final int WAIT_FOR_RESULT_TIMEOUT_MS = 3000; 80 protected static final float FRAME_DURATION_ERROR_MARGIN = 0.005f; // 0.5 percent error margin. 81 protected static final int NUM_RESULTS_WAIT_TIMEOUT = 100; 82 protected static final int NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY = 8; 83 84 protected Context mContext; 85 protected CameraManager mCameraManager; 86 protected String[] mCameraIds; 87 protected HandlerThread mHandlerThread; 88 protected Handler mHandler; 89 protected BlockingStateCallback mCameraListener; 90 protected BlockingSessionCallback mSessionListener; 91 protected CameraErrorCollector mCollector; 92 // Per device fields: 93 protected StaticMetadata mStaticInfo; 94 protected CameraDevice mCamera; 95 protected CameraCaptureSession mSession; 96 protected ImageReader mReader; 97 protected Surface mReaderSurface; 98 protected Surface mPreviewSurface; 99 protected Size mPreviewSize; 100 protected List<Size> mOrderedPreviewSizes; // In descending order. 101 protected List<Size> mOrderedVideoSizes; // In descending order. 102 protected List<Size> mOrderedStillSizes; // In descending order. 103 protected HashMap<Size, Long> mMinPreviewFrameDurationMap; 104 105 106 public Camera2SurfaceViewTestCase() { 107 super(Camera2SurfaceViewCtsActivity.class); 108 } 109 110 @Override 111 protected void setUp() throws Exception { 112 /** 113 * Set up the camera preview required environments, including activity, 114 * CameraManager, HandlerThread, Camera IDs, and CameraStateCallback. 115 */ 116 super.setUp(); 117 mContext = getActivity(); 118 /** 119 * Workaround for mockito and JB-MR2 incompatibility 120 * 121 * Avoid java.lang.IllegalArgumentException: dexcache == null 122 * https://code.google.com/p/dexmaker/issues/detail?id=2 123 */ 124 System.setProperty("dexmaker.dexcache", mContext.getCacheDir().toString()); 125 mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); 126 assertNotNull("Unable to get CameraManager", mCameraManager); 127 mCameraIds = mCameraManager.getCameraIdList(); 128 assertNotNull("Unable to get camera ids", mCameraIds); 129 mHandlerThread = new HandlerThread(TAG); 130 mHandlerThread.start(); 131 mHandler = new Handler(mHandlerThread.getLooper()); 132 mCameraListener = new BlockingStateCallback(); 133 mCollector = new CameraErrorCollector(); 134 } 135 136 @Override 137 protected void tearDown() throws Exception { 138 // Teardown the camera preview required environments. 139 mHandlerThread.quitSafely(); 140 mHandler = null; 141 mCameraListener = null; 142 143 try { 144 mCollector.verify(); 145 } catch (Throwable e) { 146 // When new Exception(e) is used, exception info will be printed twice. 147 throw new Exception(e.getMessage()); 148 } finally { 149 super.tearDown(); 150 } 151 } 152 153 /** 154 * Start camera preview by using the given request, preview size and capture 155 * listener. 156 * <p> 157 * If preview is already started, calling this function will stop the 158 * current preview stream and start a new preview stream with given 159 * parameters. No need to call stopPreview between two startPreview calls. 160 * </p> 161 * 162 * @param request The request builder used to start the preview. 163 * @param previewSz The size of the camera device output preview stream. 164 * @param listener The callbacks the camera device will notify when preview 165 * capture is available. 166 */ 167 protected void startPreview(CaptureRequest.Builder request, Size previewSz, 168 CaptureCallback listener) throws Exception { 169 // Update preview size. 170 updatePreviewSurface(previewSz); 171 if (VERBOSE) { 172 Log.v(TAG, "start preview with size " + mPreviewSize.toString()); 173 } 174 175 configurePreviewOutput(request); 176 177 mSession.setRepeatingRequest(request.build(), listener, mHandler); 178 } 179 180 /** 181 * Configure the preview output stream. 182 * 183 * @param request The request to be configured with preview surface 184 */ 185 protected void configurePreviewOutput(CaptureRequest.Builder request) 186 throws CameraAccessException { 187 List<Surface> outputSurfaces = new ArrayList<Surface>(/*capacity*/1); 188 outputSurfaces.add(mPreviewSurface); 189 mSessionListener = new BlockingSessionCallback(); 190 mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); 191 192 request.addTarget(mPreviewSurface); 193 } 194 195 /** 196 * Create a {@link CaptureRequest#Builder} and add the default preview surface. 197 * 198 * @return The {@link CaptureRequest#Builder} to be created 199 * @throws CameraAccessException When create capture request from camera fails 200 */ 201 protected CaptureRequest.Builder createRequestForPreview() throws CameraAccessException { 202 if (mPreviewSurface == null) { 203 throw new IllegalStateException( 204 "Preview surface is not set yet, call updatePreviewSurface or startPreview" 205 + "first to set the preview surface properly."); 206 } 207 CaptureRequest.Builder requestBuilder = 208 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 209 requestBuilder.addTarget(mPreviewSurface); 210 return requestBuilder; 211 } 212 213 /** 214 * Stop preview for current camera device. 215 */ 216 protected void stopPreview() throws Exception { 217 if (VERBOSE) Log.v(TAG, "Stopping preview and waiting for idle"); 218 // Stop repeat, wait for captures to complete, and disconnect from surfaces 219 mSession.close(); 220 } 221 222 /** 223 * Setup still (JPEG) capture configuration and start preview. 224 * <p> 225 * The default max number of image is set to image reader. 226 * </p> 227 * 228 * @param previewRequest The capture request to be used for preview 229 * @param stillRequest The capture request to be used for still capture 230 * @param previewSz Preview size 231 * @param stillSz The still capture size 232 * @param resultListener Capture result listener 233 * @param imageListener The still capture image listener 234 */ 235 protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 236 CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, 237 CaptureCallback resultListener, 238 ImageReader.OnImageAvailableListener imageListener) throws Exception { 239 prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz, 240 ImageFormat.JPEG, resultListener, MAX_READER_IMAGES, imageListener); 241 } 242 243 /** 244 * Setup still (JPEG) capture configuration and start preview. 245 * 246 * @param previewRequest The capture request to be used for preview 247 * @param stillRequest The capture request to be used for still capture 248 * @param previewSz Preview size 249 * @param stillSz The still capture size 250 * @param resultListener Capture result listener 251 * @param maxNumImages The max number of images set to the image reader 252 * @param imageListener The still capture image listener 253 */ 254 protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 255 CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, 256 CaptureCallback resultListener, int maxNumImages, 257 ImageReader.OnImageAvailableListener imageListener) throws Exception { 258 prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz, 259 ImageFormat.JPEG, resultListener, maxNumImages, imageListener); 260 } 261 262 /** 263 * Setup raw capture configuration and start preview. 264 * 265 * <p> 266 * The default max number of image is set to image reader. 267 * </p> 268 * 269 * @param previewRequest The capture request to be used for preview 270 * @param rawRequest The capture request to be used for raw capture 271 * @param previewSz Preview size 272 * @param rawSz The raw capture size 273 * @param resultListener Capture result listener 274 * @param imageListener The raw capture image listener 275 */ 276 protected void prepareRawCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 277 CaptureRequest.Builder rawRequest, Size previewSz, Size rawSz, 278 CaptureCallback resultListener, 279 ImageReader.OnImageAvailableListener imageListener) throws Exception { 280 prepareCaptureAndStartPreview(previewRequest, rawRequest, previewSz, rawSz, 281 ImageFormat.RAW_SENSOR, resultListener, MAX_READER_IMAGES, imageListener); 282 } 283 284 /** 285 * Wait for expected result key value available in a certain number of results. 286 * 287 * <p> 288 * Check the result immediately if numFramesWait is 0. 289 * </p> 290 * 291 * @param listener The capture listener to get capture result 292 * @param resultKey The capture result key associated with the result value 293 * @param expectedValue The result value need to be waited for 294 * @param numResultsWait Number of frame to wait before times out 295 * @throws TimeoutRuntimeException If more than numResultsWait results are 296 * seen before the result matching myRequest arrives, or each individual wait 297 * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms. 298 */ 299 protected static <T> void waitForResultValue(SimpleCaptureCallback listener, 300 CaptureResult.Key<T> resultKey, 301 T expectedValue, int numResultsWait) { 302 List<T> expectedValues = new ArrayList<T>(); 303 expectedValues.add(expectedValue); 304 waitForAnyResultValue(listener, resultKey, expectedValues, numResultsWait); 305 } 306 307 /** 308 * Wait for any expected result key values available in a certain number of results. 309 * 310 * <p> 311 * Check the result immediately if numFramesWait is 0. 312 * </p> 313 * 314 * @param listener The capture listener to get capture result. 315 * @param resultKey The capture result key associated with the result value. 316 * @param expectedValues The list of result value need to be waited for, 317 * return immediately if the list is empty. 318 * @param numResultsWait Number of frame to wait before times out. 319 * @throws TimeoutRuntimeException If more than numResultsWait results are. 320 * seen before the result matching myRequest arrives, or each individual wait 321 * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms. 322 */ 323 protected static <T> void waitForAnyResultValue(SimpleCaptureCallback listener, 324 CaptureResult.Key<T> resultKey, 325 List<T> expectedValues, int numResultsWait) { 326 if (numResultsWait < 0 || listener == null || expectedValues == null) { 327 throw new IllegalArgumentException( 328 "Input must be non-negative number and listener/expectedValues " 329 + "must be non-null"); 330 } 331 332 int i = 0; 333 CaptureResult result; 334 do { 335 result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 336 T value = result.get(resultKey); 337 for ( T expectedValue : expectedValues) { 338 if (VERBOSE) { 339 Log.v(TAG, "Current result value for key " + resultKey.getName() + " is: " 340 + value.toString()); 341 } 342 if (value.equals(expectedValue)) { 343 return; 344 } 345 } 346 } while (i++ < numResultsWait); 347 348 throw new TimeoutRuntimeException( 349 "Unable to get the expected result value " + expectedValues + " for key " + 350 resultKey.getName() + " after waiting for " + numResultsWait + " results"); 351 } 352 353 /** 354 * Submit a capture once, then submit additional captures in order to ensure that 355 * the camera will be synchronized. 356 * 357 * <p> 358 * The additional capture count is determined by android.sync.maxLatency (or 359 * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). 360 * </p> 361 * 362 * <p>Returns the number of captures that were submitted (at least 1), which is useful 363 * with {@link #waitForNumResults}.</p> 364 * 365 * @param request capture request to forward to {@link CameraDevice#capture} 366 * @param listener request listener to forward to {@link CameraDevice#capture} 367 * @param handler handler to forward to {@link CameraDevice#capture} 368 * 369 * @return the number of captures that were submitted 370 * 371 * @throws CameraAccessException if capturing failed 372 */ 373 protected int captureRequestsSynchronized( 374 CaptureRequest request, CaptureCallback listener, Handler handler) 375 throws CameraAccessException { 376 return captureRequestsSynchronized(request, /*count*/1, listener, handler); 377 } 378 379 /** 380 * Submit a capture {@code count} times, then submit additional captures in order to ensure that 381 * the camera will be synchronized. 382 * 383 * <p> 384 * The additional capture count is determined by android.sync.maxLatency (or 385 * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). 386 * </p> 387 * 388 * <p>Returns the number of captures that were submitted (at least 1), which is useful 389 * with {@link #waitForNumResults}.</p> 390 * 391 * @param request capture request to forward to {@link CameraDevice#capture} 392 * @param count the number of times to submit the request (minimally), must be at least 1 393 * @param listener request listener to forward to {@link CameraDevice#capture} 394 * @param handler handler to forward to {@link CameraDevice#capture} 395 * 396 * @return the number of captures that were submitted 397 * 398 * @throws IllegalArgumentException if {@code count} was not at least 1 399 * @throws CameraAccessException if capturing failed 400 */ 401 protected int captureRequestsSynchronized( 402 CaptureRequest request, int count, CaptureCallback listener, Handler handler) 403 throws CameraAccessException { 404 if (count < 1) { 405 throw new IllegalArgumentException("count must be positive"); 406 } 407 408 int maxLatency = mStaticInfo.getSyncMaxLatency(); 409 if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { 410 maxLatency = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY; 411 } 412 413 assertTrue("maxLatency is non-negative", maxLatency >= 0); 414 415 int numCaptures = maxLatency + count; 416 417 for (int i = 0; i < numCaptures; ++i) { 418 mSession.capture(request, listener, handler); 419 } 420 421 return numCaptures; 422 } 423 424 /** 425 * Wait for numResultWait frames 426 * 427 * @param resultListener The capture listener to get capture result back. 428 * @param numResultsWait Number of frame to wait 429 * 430 * @return the last result, or {@code null} if there was none 431 */ 432 protected static CaptureResult waitForNumResults(SimpleCaptureCallback resultListener, 433 int numResultsWait) { 434 if (numResultsWait < 0 || resultListener == null) { 435 throw new IllegalArgumentException( 436 "Input must be positive number and listener must be non-null"); 437 } 438 439 CaptureResult result = null; 440 for (int i = 0; i < numResultsWait; i++) { 441 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 442 } 443 444 return result; 445 } 446 447 /** 448 * Wait for enough results for settings to be applied 449 * 450 * @param resultListener The capture listener to get capture result back. 451 * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is 452 * unknown. 453 */ 454 protected void waitForSettingsApplied(SimpleCaptureCallback resultListener, 455 int numResultWaitForUnknownLatency) { 456 int maxLatency = mStaticInfo.getSyncMaxLatency(); 457 if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { 458 maxLatency = numResultWaitForUnknownLatency; 459 } 460 // Wait for settings to take effect 461 waitForNumResults(resultListener, maxLatency); 462 } 463 464 465 /** 466 * Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED. 467 * 468 * <p>Waits for {@code android.sync.maxLatency} number of results first, to make sure 469 * that the result is synchronized (or {@code numResultWaitForUnknownLatency} if the latency 470 * is unknown.</p> 471 * 472 * <p>This is a no-op for {@code LEGACY} devices since they don't report 473 * the {@code aeState} result.</p> 474 * 475 * @param resultListener The capture listener to get capture result back. 476 * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is 477 * unknown. 478 */ 479 protected void waitForAeStable(SimpleCaptureCallback resultListener, 480 int numResultWaitForUnknownLatency) { 481 waitForSettingsApplied(resultListener, numResultWaitForUnknownLatency); 482 483 if (!mStaticInfo.isHardwareLevelLimitedOrBetter()) { 484 // No-op for metadata 485 return; 486 } 487 List<Integer> expectedAeStates = new ArrayList<Integer>(); 488 expectedAeStates.add(new Integer(CaptureResult.CONTROL_AE_STATE_CONVERGED)); 489 expectedAeStates.add(new Integer(CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED)); 490 waitForAnyResultValue(resultListener, CaptureResult.CONTROL_AE_STATE, expectedAeStates, 491 NUM_RESULTS_WAIT_TIMEOUT); 492 } 493 494 /** 495 * Wait for AE to be: LOCKED 496 * 497 * <p>Waits for {@code android.sync.maxLatency} number of results first, to make sure 498 * that the result is synchronized (or {@code numResultWaitForUnknownLatency} if the latency 499 * is unknown.</p> 500 * 501 * <p>This is a no-op for {@code LEGACY} devices since they don't report 502 * the {@code aeState} result.</p> 503 * 504 * @param resultListener The capture listener to get capture result back. 505 * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is 506 * unknown. 507 */ 508 protected void waitForAeLocked(SimpleCaptureCallback resultListener, 509 int numResultWaitForUnknownLatency) { 510 511 waitForSettingsApplied(resultListener, numResultWaitForUnknownLatency); 512 513 if (!mStaticInfo.isHardwareLevelLimitedOrBetter()) { 514 // No-op for legacy devices 515 return; 516 } 517 518 List<Integer> expectedAeStates = new ArrayList<Integer>(); 519 expectedAeStates.add(new Integer(CaptureResult.CONTROL_AE_STATE_LOCKED)); 520 waitForAnyResultValue(resultListener, CaptureResult.CONTROL_AE_STATE, expectedAeStates, 521 NUM_RESULTS_WAIT_TIMEOUT); 522 } 523 524 /** 525 * Create an {@link ImageReader} object and get the surface. 526 * 527 * @param size The size of this ImageReader to be created. 528 * @param format The format of this ImageReader to be created 529 * @param maxNumImages The max number of images that can be acquired simultaneously. 530 * @param listener The listener used by this ImageReader to notify callbacks. 531 */ 532 protected void createImageReader(Size size, int format, int maxNumImages, 533 ImageReader.OnImageAvailableListener listener) throws Exception { 534 closeImageReader(); 535 536 ImageReader r = makeImageReader(size, format, maxNumImages, listener, 537 mHandler); 538 mReader = r; 539 mReaderSurface = r.getSurface(); 540 } 541 542 /** 543 * Close the pending images then close current active {@link ImageReader} object. 544 */ 545 protected void closeImageReader() { 546 CameraTestUtils.closeImageReader(mReader); 547 mReader = null; 548 mReaderSurface = null; 549 } 550 551 /** 552 * Open a camera device and get the StaticMetadata for a given camera id. 553 * 554 * @param cameraId The id of the camera device to be opened. 555 */ 556 protected void openDevice(String cameraId) throws Exception { 557 mCamera = CameraTestUtils.openCamera( 558 mCameraManager, cameraId, mCameraListener, mHandler); 559 mCollector.setCameraId(cameraId); 560 mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId), 561 CheckLevel.ASSERT, /*collector*/null); 562 mOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND); 563 mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND); 564 mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null); 565 // Use ImageFormat.YUV_420_888 for now. TODO: need figure out what's format for preview 566 // in public API side. 567 mMinPreviewFrameDurationMap = 568 mStaticInfo.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.YUV_420_888); 569 } 570 571 /** 572 * Close the current actively used camera device. 573 */ 574 protected void closeDevice() { 575 if (mCamera != null) { 576 mCamera.close(); 577 mCameraListener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS); 578 mCamera = null; 579 mSession = null; 580 mSessionListener = null; 581 mStaticInfo = null; 582 mOrderedPreviewSizes = null; 583 mOrderedVideoSizes = null; 584 mOrderedStillSizes = null; 585 } 586 } 587 588 /** 589 * Update the preview surface size. 590 * 591 * @param size The preview size to be updated. 592 */ 593 protected void updatePreviewSurface(Size size) { 594 if (size.equals(mPreviewSize) && mPreviewSurface != null) { 595 Log.w(TAG, "Skipping update preview surface size..."); 596 return; 597 } 598 599 mPreviewSize = size; 600 Camera2SurfaceViewCtsActivity ctsActivity = getActivity(); 601 final SurfaceHolder holder = ctsActivity.getSurfaceView().getHolder(); 602 Handler handler = new Handler(Looper.getMainLooper()); 603 handler.post(new Runnable() { 604 @Override 605 public void run() { 606 holder.setFixedSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); 607 } 608 }); 609 610 boolean res = ctsActivity.waitForSurfaceSizeChanged( 611 WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS, mPreviewSize.getWidth(), 612 mPreviewSize.getHeight()); 613 assertTrue("wait for surface change to " + mPreviewSize.toString() + " timed out", res); 614 mPreviewSurface = holder.getSurface(); 615 assertTrue("Preview surface is invalid", mPreviewSurface.isValid()); 616 assertNotNull("Preview surface is null", mPreviewSurface); 617 } 618 619 /** 620 * Setup single capture configuration and start preview. 621 * 622 * @param previewRequest The capture request to be used for preview 623 * @param stillRequest The capture request to be used for still capture 624 * @param previewSz Preview size 625 * @param captureSz Still capture size 626 * @param format The single capture image format 627 * @param resultListener Capture result listener 628 * @param maxNumImages The max number of images set to the image reader 629 * @param imageListener The single capture capture image listener 630 */ 631 protected void prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 632 CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format, 633 CaptureCallback resultListener, int maxNumImages, 634 ImageReader.OnImageAvailableListener imageListener) throws Exception { 635 if (VERBOSE) { 636 Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)", 637 captureSz.toString(), previewSz.toString())); 638 } 639 640 // Update preview size. 641 updatePreviewSurface(previewSz); 642 643 // Create ImageReader. 644 createImageReader(captureSz, format, maxNumImages, imageListener); 645 646 // Configure output streams with preview and jpeg streams. 647 List<Surface> outputSurfaces = new ArrayList<Surface>(); 648 outputSurfaces.add(mPreviewSurface); 649 outputSurfaces.add(mReaderSurface); 650 mSessionListener = new BlockingSessionCallback(); 651 mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); 652 653 // Configure the requests. 654 previewRequest.addTarget(mPreviewSurface); 655 stillRequest.addTarget(mPreviewSurface); 656 stillRequest.addTarget(mReaderSurface); 657 658 // Start preview. 659 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 660 } 661 662 /** 663 * Get the max preview size that supports the given fpsRange. 664 * 665 * @param fpsRange The fps range the returned size must support. 666 * @return max size that support the given fps range. 667 */ 668 protected Size getMaxPreviewSizeForFpsRange(Range<Integer> fpsRange) { 669 if (fpsRange == null || fpsRange.getLower() <= 0 || fpsRange.getUpper() <= 0) { 670 throw new IllegalArgumentException("Invalid fps range argument"); 671 } 672 if (mOrderedPreviewSizes == null || mMinPreviewFrameDurationMap == null) { 673 throw new IllegalStateException("mOrderedPreviewSizes and mMinPreviewFrameDurationMap" 674 + " must be initialized"); 675 } 676 677 long[] frameDurationRange = 678 new long[]{(long) (1e9 / fpsRange.getUpper()), (long) (1e9 / fpsRange.getLower())}; 679 for (Size size : mOrderedPreviewSizes) { 680 Long minDuration = mMinPreviewFrameDurationMap.get(size); 681 if (minDuration == null || 682 minDuration == 0) { 683 if (mStaticInfo.isCapabilitySupported( 684 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 685 throw new IllegalArgumentException( 686 "No min frame duration available for the size " + size); 687 } 688 continue; 689 } 690 if (minDuration <= frameDurationRange[0]) { 691 return size; 692 } 693 } 694 695 return null; 696 } 697 } 698