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 21 import static com.android.ex.camera2.blocking.BlockingStateCallback.STATE_CLOSED; 22 import androidx.test.InstrumentationRegistry; 23 import android.app.UiAutomation; 24 25 import android.content.Context; 26 import android.graphics.ImageFormat; 27 import android.hardware.camera2.CameraAccessException; 28 import android.hardware.camera2.CameraCaptureSession; 29 import android.hardware.camera2.CameraCaptureSession.CaptureCallback; 30 import android.hardware.camera2.CameraCharacteristics; 31 import android.hardware.camera2.CameraDevice; 32 import android.hardware.camera2.CameraManager; 33 import android.hardware.camera2.CameraMetadata; 34 import android.hardware.camera2.CaptureRequest; 35 import android.hardware.camera2.CaptureResult; 36 import android.hardware.camera2.cts.Camera2SurfaceViewCtsActivity; 37 import android.hardware.camera2.cts.Camera2ParameterizedTestCase; 38 import android.hardware.camera2.cts.CameraTestUtils; 39 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 40 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 41 import android.hardware.camera2.cts.helpers.StaticMetadata; 42 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel; 43 import android.media.ImageReader; 44 import android.os.Handler; 45 import android.os.HandlerThread; 46 import android.os.Looper; 47 import android.util.Log; 48 import android.util.Range; 49 import android.util.Size; 50 import android.view.Surface; 51 import android.view.SurfaceHolder; 52 import android.view.View; 53 import android.view.WindowManager; 54 55 import androidx.test.rule.ActivityTestRule; 56 57 import com.android.ex.camera2.blocking.BlockingSessionCallback; 58 import com.android.ex.camera2.blocking.BlockingStateCallback; 59 import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 60 61 import org.junit.After; 62 import org.junit.Before; 63 import org.junit.Ignore; 64 import org.junit.Rule; 65 66 import java.io.File; 67 import java.util.ArrayList; 68 import java.util.Arrays; 69 import java.util.HashMap; 70 import java.util.List; 71 import org.junit.Test; 72 import org.junit.runner.RunWith; 73 import org.junit.runners.Parameterized; 74 import org.junit.runners.Parameterized.Parameter; 75 import org.junit.runners.Parameterized.Parameters; 76 77 78 /** 79 * Camera2 Preview test case base class by using SurfaceView as rendering target. 80 * 81 * <p>This class encapsulates the SurfaceView based preview common functionalities. 82 * The setup and teardown of CameraManager, test HandlerThread, Activity, Camera IDs 83 * and CameraStateCallback are handled in this class. Some basic preview related utility 84 * functions are provided to facilitate the derived preview-based test classes. 85 * </p> 86 */ 87 88 public class Camera2SurfaceViewTestCase extends Camera2ParameterizedTestCase { 89 private static final String TAG = "SurfaceViewTestCase"; 90 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 91 private static final int WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS = 1000; 92 93 protected static final int WAIT_FOR_RESULT_TIMEOUT_MS = 3000; 94 protected static final float FRAME_DURATION_ERROR_MARGIN = 0.01f; // 1 percent error margin. 95 protected static final int NUM_RESULTS_WAIT_TIMEOUT = 100; 96 protected static final int NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY = 8; 97 protected static final int MIN_FRAME_DURATION_ERROR_MARGIN = 100; // ns 98 99 protected HandlerThread mHandlerThread; 100 protected Handler mHandler; 101 protected BlockingStateCallback mCameraListener; 102 protected BlockingSessionCallback mSessionListener; 103 protected CameraErrorCollector mCollector; 104 protected HashMap<String, StaticMetadata> mAllStaticInfo; 105 // Per device fields: 106 protected StaticMetadata mStaticInfo; 107 protected CameraDevice mCamera; 108 protected CameraCaptureSession mSession; 109 protected ImageReader mReader; 110 protected Surface mReaderSurface; 111 protected Surface mPreviewSurface; 112 protected SurfaceHolder mPreviewHolder; 113 protected Size mPreviewSize; 114 protected List<Size> mOrderedPreviewSizes; // In descending order. 115 protected List<Size> m1080pBoundedOrderedPreviewSizes; // In descending order. 116 protected List<Size> mOrderedVideoSizes; // In descending order. 117 protected List<Size> mOrderedStillSizes; // In descending order. 118 protected HashMap<Size, Long> mMinPreviewFrameDurationMap; 119 protected String mDebugFileNameBase; 120 121 protected WindowManager mWindowManager; 122 123 @Rule 124 public ActivityTestRule<Camera2SurfaceViewCtsActivity> mActivityRule = 125 new ActivityTestRule<>(Camera2SurfaceViewCtsActivity.class); 126 127 @Before setUp()128 public void setUp() throws Exception { 129 super.setUp(); 130 mHandlerThread = new HandlerThread(TAG); 131 mHandlerThread.start(); 132 mHandler = new Handler(mHandlerThread.getLooper()); 133 mCameraListener = new BlockingStateCallback(); 134 mCollector = new CameraErrorCollector(); 135 136 File filesDir = mContext.getPackageManager().isInstantApp() 137 ? mContext.getFilesDir() 138 : mContext.getExternalFilesDir(null); 139 140 mDebugFileNameBase = filesDir.getPath(); 141 142 mAllStaticInfo = new HashMap<String, StaticMetadata>(); 143 List<String> hiddenPhysicalIds = new ArrayList<>(); 144 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 145 for (String cameraId : cameraIdsUnderTest) { 146 CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId); 147 StaticMetadata staticMetadata = new StaticMetadata(props, 148 CheckLevel.ASSERT, /*collector*/null); 149 mAllStaticInfo.put(cameraId, staticMetadata); 150 151 for (String physicalId : props.getPhysicalCameraIds()) { 152 if (!Arrays.asList(cameraIdsUnderTest).contains(physicalId) && 153 !hiddenPhysicalIds.contains(physicalId)) { 154 hiddenPhysicalIds.add(physicalId); 155 props = mCameraManager.getCameraCharacteristics(physicalId); 156 staticMetadata = new StaticMetadata( 157 mCameraManager.getCameraCharacteristics(physicalId), 158 CheckLevel.ASSERT, /*collector*/null); 159 mAllStaticInfo.put(physicalId, staticMetadata); 160 } 161 } 162 } 163 164 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 165 } 166 167 @After tearDown()168 public void tearDown() throws Exception { 169 mHandlerThread.quitSafely(); 170 mHandler = null; 171 mCameraListener = null; 172 173 try { 174 mCollector.verify(); 175 } catch (Throwable e) { 176 // When new Exception(e) is used, exception info will be printed twice. 177 throw new Exception(e.getMessage()); 178 } 179 super.tearDown(); 180 } 181 182 /** 183 * Start camera preview by using the given request, preview size and capture 184 * listener. 185 * <p> 186 * If preview is already started, calling this function will stop the 187 * current preview stream and start a new preview stream with given 188 * parameters. No need to call stopPreview between two startPreview calls. 189 * </p> 190 * 191 * @param request The request builder used to start the preview. 192 * @param previewSz The size of the camera device output preview stream. 193 * @param listener The callbacks the camera device will notify when preview 194 * capture is available. 195 */ startPreview(CaptureRequest.Builder request, Size previewSz, CaptureCallback listener)196 protected void startPreview(CaptureRequest.Builder request, Size previewSz, 197 CaptureCallback listener) throws Exception { 198 // Update preview size. 199 updatePreviewSurface(previewSz); 200 if (VERBOSE) { 201 Log.v(TAG, "start preview with size " + mPreviewSize.toString()); 202 } 203 204 configurePreviewOutput(request); 205 206 mSession.setRepeatingRequest(request.build(), listener, mHandler); 207 } 208 209 /** 210 * Configure the preview output stream. 211 * 212 * @param request The request to be configured with preview surface 213 */ configurePreviewOutput(CaptureRequest.Builder request)214 protected void configurePreviewOutput(CaptureRequest.Builder request) 215 throws CameraAccessException { 216 List<Surface> outputSurfaces = new ArrayList<Surface>(/*capacity*/1); 217 outputSurfaces.add(mPreviewSurface); 218 mSessionListener = new BlockingSessionCallback(); 219 mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); 220 221 request.addTarget(mPreviewSurface); 222 } 223 224 /** 225 * Create a {@link CaptureRequest#Builder} and add the default preview surface. 226 * 227 * @return The {@link CaptureRequest#Builder} to be created 228 * @throws CameraAccessException When create capture request from camera fails 229 */ createRequestForPreview()230 protected CaptureRequest.Builder createRequestForPreview() throws CameraAccessException { 231 if (mPreviewSurface == null) { 232 throw new IllegalStateException( 233 "Preview surface is not set yet, call updatePreviewSurface or startPreview" 234 + "first to set the preview surface properly."); 235 } 236 CaptureRequest.Builder requestBuilder = 237 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 238 requestBuilder.addTarget(mPreviewSurface); 239 return requestBuilder; 240 } 241 242 /** 243 * Stop preview for current camera device by closing the session. 244 * Does _not_ wait for the device to go idle 245 */ stopPreview()246 protected void stopPreview() throws Exception { 247 // Stop repeat, wait for captures to complete, and disconnect from surfaces 248 if (mSession != null) { 249 if (VERBOSE) Log.v(TAG, "Stopping preview"); 250 mSession.close(); 251 } 252 } 253 254 /** 255 * Stop preview for current camera device by closing the session and waiting for it to close, 256 * resulting in an idle device. 257 */ stopPreviewAndDrain()258 protected void stopPreviewAndDrain() throws Exception { 259 // Stop repeat, wait for captures to complete, and disconnect from surfaces 260 if (mSession != null) { 261 if (VERBOSE) Log.v(TAG, "Stopping preview and waiting for idle"); 262 mSession.close(); 263 mSessionListener.getStateWaiter().waitForState(BlockingSessionCallback.SESSION_CLOSED, 264 /*timeoutMs*/WAIT_FOR_RESULT_TIMEOUT_MS); 265 } 266 } 267 268 /** 269 * Setup still (JPEG) capture configuration and start preview. 270 * <p> 271 * The default max number of image is set to image reader. 272 * </p> 273 * 274 * @param previewRequest The capture request to be used for preview 275 * @param stillRequest The capture request to be used for still capture 276 * @param previewSz Preview size 277 * @param stillSz The still capture size 278 * @param resultListener Capture result listener 279 * @param imageListener The still capture image listener 280 */ prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, CaptureCallback resultListener, ImageReader.OnImageAvailableListener imageListener, boolean isHeic)281 protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 282 CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, 283 CaptureCallback resultListener, 284 ImageReader.OnImageAvailableListener imageListener, boolean isHeic) throws Exception { 285 prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz, 286 isHeic ? ImageFormat.HEIC : ImageFormat.JPEG, resultListener, MAX_READER_IMAGES, 287 imageListener); 288 } 289 290 /** 291 * Setup still (JPEG) capture configuration and start preview. 292 * 293 * @param previewRequest The capture request to be used for preview 294 * @param stillRequest The capture request to be used for still capture 295 * @param previewSz Preview size 296 * @param stillSz The still capture size 297 * @param resultListener Capture result listener 298 * @param maxNumImages The max number of images set to the image reader 299 * @param imageListener The still capture image listener 300 */ prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, CaptureCallback resultListener, int maxNumImages, ImageReader.OnImageAvailableListener imageListener, boolean isHeic)301 protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 302 CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz, 303 CaptureCallback resultListener, int maxNumImages, 304 ImageReader.OnImageAvailableListener imageListener, boolean isHeic) throws Exception { 305 prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz, 306 isHeic ? ImageFormat.HEIC : ImageFormat.JPEG, resultListener, maxNumImages, imageListener); 307 } 308 309 /** 310 * Setup raw capture configuration and start preview. 311 * 312 * <p> 313 * The default max number of image is set to image reader. 314 * </p> 315 * 316 * @param previewRequest The capture request to be used for preview 317 * @param rawRequest The capture request to be used for raw capture 318 * @param previewSz Preview size 319 * @param rawSz The raw capture size 320 * @param resultListener Capture result listener 321 * @param imageListener The raw capture image listener 322 */ prepareRawCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder rawRequest, Size previewSz, Size rawSz, CaptureCallback resultListener, ImageReader.OnImageAvailableListener imageListener)323 protected void prepareRawCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 324 CaptureRequest.Builder rawRequest, Size previewSz, Size rawSz, 325 CaptureCallback resultListener, 326 ImageReader.OnImageAvailableListener imageListener) throws Exception { 327 prepareCaptureAndStartPreview(previewRequest, rawRequest, previewSz, rawSz, 328 ImageFormat.RAW_SENSOR, resultListener, MAX_READER_IMAGES, imageListener); 329 } 330 331 /** 332 * Wait for expected result key value available in a certain number of results. 333 * 334 * <p> 335 * Check the result immediately if numFramesWait is 0. 336 * </p> 337 * 338 * @param listener The capture listener to get capture result 339 * @param resultKey The capture result key associated with the result value 340 * @param expectedValue The result value need to be waited for 341 * @param numResultsWait Number of frame to wait before times out 342 * @throws TimeoutRuntimeException If more than numResultsWait results are 343 * seen before the result matching myRequest arrives, or each individual wait 344 * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms. 345 */ waitForResultValue(SimpleCaptureCallback listener, CaptureResult.Key<T> resultKey, T expectedValue, int numResultsWait)346 protected static <T> void waitForResultValue(SimpleCaptureCallback listener, 347 CaptureResult.Key<T> resultKey, 348 T expectedValue, int numResultsWait) { 349 CameraTestUtils.waitForResultValue(listener, resultKey, expectedValue, 350 numResultsWait, WAIT_FOR_RESULT_TIMEOUT_MS); 351 } 352 353 /** 354 * Wait for any expected result key values available in a certain number of results. 355 * 356 * <p> 357 * Check the result immediately if numFramesWait is 0. 358 * </p> 359 * 360 * @param listener The capture listener to get capture result. 361 * @param resultKey The capture result key associated with the result value. 362 * @param expectedValues The list of result value need to be waited for, 363 * return immediately if the list is empty. 364 * @param numResultsWait Number of frame to wait before times out. 365 * @throws TimeoutRuntimeException If more than numResultsWait results are. 366 * seen before the result matching myRequest arrives, or each individual wait 367 * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms. 368 */ waitForAnyResultValue(SimpleCaptureCallback listener, CaptureResult.Key<T> resultKey, List<T> expectedValues, int numResultsWait)369 protected static <T> void waitForAnyResultValue(SimpleCaptureCallback listener, 370 CaptureResult.Key<T> resultKey, 371 List<T> expectedValues, int numResultsWait) { 372 CameraTestUtils.waitForAnyResultValue(listener, resultKey, expectedValues, numResultsWait, 373 WAIT_FOR_RESULT_TIMEOUT_MS); 374 } 375 376 /** 377 * Submit a burst of the same capture request, then submit additional captures in order to 378 * ensure that the camera will be synchronized. 379 * 380 * <p> 381 * The additional capture count is determined by android.sync.maxLatency (or 382 * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). 383 * </p> 384 * 385 * <p>Returns the number of captures that were submitted (at least 1), which is useful 386 * with {@link #waitForNumResults}.</p> 387 * 388 * @param request capture request to forward to {@link CameraDevice#capture} 389 * @param listener request listener to forward to {@link CameraDevice#capture} 390 * @param handler handler to forward to {@link CameraDevice#capture} 391 * 392 * @return the number of captures that were submitted 393 * 394 * @throws CameraAccessException if capturing failed 395 */ captureRequestsSynchronizedBurst( CaptureRequest request, int count, CaptureCallback listener, Handler handler)396 protected int captureRequestsSynchronizedBurst( 397 CaptureRequest request, int count, CaptureCallback listener, Handler handler) 398 throws CameraAccessException { 399 return captureRequestsSynchronizedImpl(request, count, listener, handler, true); 400 } 401 /** 402 * Submit a capture once, then submit additional captures in order to ensure that 403 * the camera will be synchronized. 404 * 405 * <p> 406 * The additional capture count is determined by android.sync.maxLatency (or 407 * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). 408 * </p> 409 * 410 * <p>Returns the number of captures that were submitted (at least 1), which is useful 411 * with {@link #waitForNumResults}.</p> 412 * 413 * @param request capture request to forward to {@link CameraDevice#capture} 414 * @param listener request listener to forward to {@link CameraDevice#capture} 415 * @param handler handler to forward to {@link CameraDevice#capture} 416 * 417 * @return the number of captures that were submitted 418 * 419 * @throws CameraAccessException if capturing failed 420 */ captureRequestsSynchronized( CaptureRequest request, CaptureCallback listener, Handler handler)421 protected int captureRequestsSynchronized( 422 CaptureRequest request, CaptureCallback listener, Handler handler) 423 throws CameraAccessException { 424 return captureRequestsSynchronizedImpl(request, /*count*/1, listener, handler, false); 425 } 426 427 /** 428 * Submit a capture {@code count} times, then submit additional captures in order to ensure that 429 * the camera will be synchronized. 430 * 431 * <p> 432 * The additional capture count is determined by android.sync.maxLatency (or 433 * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown). 434 * </p> 435 * 436 * <p>Returns the number of captures that were submitted (at least 1), which is useful 437 * with {@link #waitForNumResults}.</p> 438 * 439 * @param request capture request to forward to {@link CameraDevice#capture} 440 * @param count the number of times to submit the request (minimally), must be at least 1 441 * @param listener request listener to forward to {@link CameraDevice#capture} 442 * @param handler handler to forward to {@link CameraDevice#capture} 443 * 444 * @return the number of captures that were submitted 445 * 446 * @throws IllegalArgumentException if {@code count} was not at least 1 447 * @throws CameraAccessException if capturing failed 448 */ captureRequestsSynchronized( CaptureRequest request, int count, CaptureCallback listener, Handler handler)449 protected int captureRequestsSynchronized( 450 CaptureRequest request, int count, CaptureCallback listener, Handler handler) 451 throws CameraAccessException { 452 return captureRequestsSynchronizedImpl(request, count, listener, handler, false); 453 } 454 455 /** 456 * Wait for numResultWait frames 457 * 458 * @param resultListener The capture listener to get capture result back. 459 * @param numResultsWait Number of frame to wait 460 * 461 * @return the last result, or {@code null} if there was none 462 */ waitForNumResults(SimpleCaptureCallback resultListener, int numResultsWait)463 protected static CaptureResult waitForNumResults(SimpleCaptureCallback resultListener, 464 int numResultsWait) { 465 return CameraTestUtils.waitForNumResults(resultListener, numResultsWait, 466 WAIT_FOR_RESULT_TIMEOUT_MS); 467 } 468 469 /** 470 * Wait for enough results for settings to be applied 471 * 472 * @param resultListener The capture listener to get capture result back. 473 * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is 474 * unknown. 475 */ waitForSettingsApplied(SimpleCaptureCallback resultListener, int numResultWaitForUnknownLatency)476 protected void waitForSettingsApplied(SimpleCaptureCallback resultListener, 477 int numResultWaitForUnknownLatency) { 478 int maxLatency = mStaticInfo.getSyncMaxLatency(); 479 if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { 480 maxLatency = numResultWaitForUnknownLatency; 481 } 482 // Wait for settings to take effect 483 waitForNumResults(resultListener, maxLatency); 484 } 485 486 /** 487 * Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED. 488 * 489 * <p>Waits for {@code android.sync.maxLatency} number of results first, to make sure 490 * that the result is synchronized (or {@code numResultWaitForUnknownLatency} if the latency 491 * is unknown.</p> 492 * 493 * <p>This is a no-op for {@code LEGACY} devices since they don't report 494 * the {@code aeState} result.</p> 495 * 496 * @param resultListener The capture listener to get capture result back. 497 * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is 498 * unknown. 499 */ waitForAeStable(SimpleCaptureCallback resultListener, int numResultWaitForUnknownLatency)500 protected void waitForAeStable(SimpleCaptureCallback resultListener, 501 int numResultWaitForUnknownLatency) { 502 CameraTestUtils.waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY, 503 mStaticInfo, WAIT_FOR_RESULT_TIMEOUT_MS, NUM_RESULTS_WAIT_TIMEOUT); 504 } 505 506 /** 507 * Wait for AE to be: LOCKED 508 * 509 * <p>Waits for {@code android.sync.maxLatency} number of results first, to make sure 510 * that the result is synchronized (or {@code numResultWaitForUnknownLatency} if the latency 511 * is unknown.</p> 512 * 513 * <p>This is a no-op for {@code LEGACY} devices since they don't report 514 * the {@code aeState} result.</p> 515 * 516 * @param resultListener The capture listener to get capture result back. 517 * @param numResultWaitForUnknownLatency Number of frame to wait if camera device latency is 518 * unknown. 519 */ waitForAeLocked(SimpleCaptureCallback resultListener, int numResultWaitForUnknownLatency)520 protected void waitForAeLocked(SimpleCaptureCallback resultListener, 521 int numResultWaitForUnknownLatency) { 522 523 waitForSettingsApplied(resultListener, numResultWaitForUnknownLatency); 524 525 if (!mStaticInfo.isHardwareLevelAtLeastLimited()) { 526 // No-op for legacy devices 527 return; 528 } 529 530 List<Integer> expectedAeStates = new ArrayList<Integer>(); 531 expectedAeStates.add(new Integer(CaptureResult.CONTROL_AE_STATE_LOCKED)); 532 CameraTestUtils.waitForAnyResultValue(resultListener, CaptureResult.CONTROL_AE_STATE, 533 expectedAeStates, NUM_RESULTS_WAIT_TIMEOUT, WAIT_FOR_RESULT_TIMEOUT_MS); 534 } 535 536 /** 537 * Create an {@link ImageReader} object and get the surface. 538 * 539 * @param size The size of this ImageReader to be created. 540 * @param format The format of this ImageReader to be created 541 * @param maxNumImages The max number of images that can be acquired simultaneously. 542 * @param listener The listener used by this ImageReader to notify callbacks. 543 */ createImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)544 protected void createImageReader(Size size, int format, int maxNumImages, 545 ImageReader.OnImageAvailableListener listener) throws Exception { 546 closeImageReader(); 547 548 ImageReader r = makeImageReader(size, format, maxNumImages, listener, 549 mHandler); 550 mReader = r; 551 mReaderSurface = r.getSurface(); 552 } 553 554 /** 555 * Close the pending images then close current active {@link ImageReader} object. 556 */ closeImageReader()557 protected void closeImageReader() { 558 CameraTestUtils.closeImageReader(mReader); 559 mReader = null; 560 mReaderSurface = null; 561 } 562 563 /** 564 * Close the pending images then close current active {@link ImageReader} objects. 565 */ closeImageReaders(ImageReader[] readers)566 protected void closeImageReaders(ImageReader[] readers) { 567 CameraTestUtils.closeImageReaders(readers); 568 } 569 570 /** 571 * Setup still capture configuration and start preview. 572 * 573 * @param previewRequest The capture request to be used for preview 574 * @param stillRequest The capture request to be used for still capture 575 * @param previewSz Preview size 576 * @param captureSizes Still capture sizes 577 * @param formats The single capture image formats 578 * @param resultListener Capture result listener 579 * @param maxNumImages The max number of images set to the image reader 580 * @param imageListeners The single capture capture image listeners 581 * @param isHeic HEIC still capture if true, JPEG still capture if false 582 */ prepareStillCaptureAndStartPreview( CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener, int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners, boolean isHeic)583 protected ImageReader[] prepareStillCaptureAndStartPreview( 584 CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, 585 Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener, 586 int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners, 587 boolean isHeic) 588 throws Exception { 589 590 if ((captureSizes == null) || (formats == null) || (imageListeners == null) && 591 (captureSizes.length != formats.length) || 592 (formats.length != imageListeners.length)) { 593 throw new IllegalArgumentException("Invalid capture sizes/formats or image listeners!"); 594 } 595 596 if (VERBOSE) { 597 Log.v(TAG, String.format("Prepare still capture and preview (%s)", 598 previewSz.toString())); 599 } 600 601 // Update preview size. 602 updatePreviewSurface(previewSz); 603 604 ImageReader[] readers = new ImageReader[captureSizes.length]; 605 List<Surface> outputSurfaces = new ArrayList<Surface>(); 606 outputSurfaces.add(mPreviewSurface); 607 for (int i = 0; i < captureSizes.length; i++) { 608 readers[i] = makeImageReader(captureSizes[i], formats[i], maxNumImages, 609 imageListeners[i], mHandler); 610 outputSurfaces.add(readers[i].getSurface()); 611 } 612 613 mSessionListener = new BlockingSessionCallback(); 614 mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); 615 616 // Configure the requests. 617 previewRequest.addTarget(mPreviewSurface); 618 stillRequest.addTarget(mPreviewSurface); 619 for (int i = 0; i < readers.length; i++) { 620 stillRequest.addTarget(readers[i].getSurface()); 621 } 622 623 // Start preview. 624 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 625 626 return readers; 627 } 628 629 /** 630 * Open a camera device and get the StaticMetadata for a given camera id. 631 * 632 * @param cameraId The id of the camera device to be opened. 633 */ openDevice(String cameraId)634 protected void openDevice(String cameraId) throws Exception { 635 mCamera = CameraTestUtils.openCamera( 636 mCameraManager, cameraId, mCameraListener, mHandler); 637 mCollector.setCameraId(cameraId); 638 mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId), 639 CheckLevel.ASSERT, /*collector*/null); 640 if (mStaticInfo.isColorOutputSupported()) { 641 mOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager, 642 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND)); 643 m1080pBoundedOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager, 644 PREVIEW_SIZE_BOUND); 645 mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND); 646 mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null); 647 // Use ImageFormat.YUV_420_888 for now. TODO: need figure out what's format for preview 648 // in public API side. 649 mMinPreviewFrameDurationMap = 650 mStaticInfo.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.YUV_420_888); 651 } 652 } 653 654 /** 655 * Close the current actively used camera device. 656 */ closeDevice()657 protected void closeDevice() { 658 if (mCamera != null) { 659 mCamera.close(); 660 mCameraListener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS); 661 mCamera = null; 662 mSession = null; 663 mSessionListener = null; 664 mStaticInfo = null; 665 mOrderedPreviewSizes = null; 666 mOrderedVideoSizes = null; 667 mOrderedStillSizes = null; 668 } 669 } 670 671 /** 672 * Update the preview surface size. 673 * 674 * @param size The preview size to be updated. 675 */ updatePreviewSurface(Size size)676 protected void updatePreviewSurface(Size size) { 677 if (size.equals(mPreviewSize) && mPreviewSurface != null && mPreviewSurface.isValid()) { 678 Log.w(TAG, "Skipping update preview surface size..."); 679 return; 680 } 681 682 mPreviewSize = size; 683 Camera2SurfaceViewCtsActivity ctsActivity = mActivityRule.getActivity(); 684 final SurfaceHolder holder = ctsActivity.getSurfaceView().getHolder(); 685 Handler handler = new Handler(Looper.getMainLooper()); 686 handler.post(new Runnable() { 687 @Override 688 public void run() { 689 holder.setFixedSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); 690 } 691 }); 692 693 boolean res = ctsActivity.waitForSurfaceSizeChanged( 694 WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS, mPreviewSize.getWidth(), 695 mPreviewSize.getHeight()); 696 assertTrue("wait for surface change to " + mPreviewSize.toString() + " timed out", res); 697 mPreviewHolder = holder; 698 mPreviewSurface = holder.getSurface(); 699 assertNotNull("Preview surface is null", mPreviewSurface); 700 assertTrue("Preview surface is invalid", mPreviewSurface.isValid()); 701 } 702 703 /** 704 * Recreate the SurfaceView's Surface 705 * 706 * Hide and unhide the activity's preview SurfaceView, so that its backing Surface is 707 * recreated 708 */ recreatePreviewSurface()709 protected void recreatePreviewSurface() { 710 Camera2SurfaceViewCtsActivity ctsActivity = mActivityRule.getActivity(); 711 setPreviewVisibility(View.GONE); 712 boolean res = ctsActivity.waitForSurfaceState( 713 WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS, /*valid*/ false); 714 assertTrue("wait for surface destroyed timed out", res); 715 setPreviewVisibility(View.VISIBLE); 716 res = ctsActivity.waitForSurfaceState( 717 WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS, /*valid*/ true); 718 assertTrue("wait for surface created timed out", res); 719 } 720 721 /** 722 * Show/hide the preview SurfaceView. 723 * 724 * If set to View.GONE, the surfaceDestroyed callback will fire 725 * @param visibility the new new visibility to set, one of View.VISIBLE / INVISIBLE / GONE 726 */ setPreviewVisibility(int visibility)727 protected void setPreviewVisibility(int visibility) { 728 final Camera2SurfaceViewCtsActivity ctsActivity = mActivityRule.getActivity(); 729 Handler handler = new Handler(Looper.getMainLooper()); 730 handler.post(new Runnable() { 731 @Override 732 public void run() { 733 ctsActivity.getSurfaceView().setVisibility(visibility); 734 } 735 }); 736 } 737 738 /** 739 * Setup single capture configuration and start preview. 740 * 741 * @param previewRequest The capture request to be used for preview 742 * @param stillRequest The capture request to be used for still capture 743 * @param previewSz Preview size 744 * @param captureSz Still capture size 745 * @param format The single capture image format 746 * @param resultListener Capture result listener 747 * @param maxNumImages The max number of images set to the image reader 748 * @param imageListener The single capture capture image listener 749 */ prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format, CaptureCallback resultListener, int maxNumImages, ImageReader.OnImageAvailableListener imageListener)750 protected void prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 751 CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format, 752 CaptureCallback resultListener, int maxNumImages, 753 ImageReader.OnImageAvailableListener imageListener) throws Exception { 754 prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, captureSz, 755 format, resultListener, null, maxNumImages, imageListener); 756 } 757 758 /** 759 * Setup single capture configuration and start preview. 760 * 761 * @param previewRequest The capture request to be used for preview 762 * @param stillRequest The capture request to be used for still capture 763 * @param previewSz Preview size 764 * @param captureSz Still capture size 765 * @param format The single capture image format 766 * @param resultListener Capture result listener 767 * @param sessionListener Session listener 768 * @param maxNumImages The max number of images set to the image reader 769 * @param imageListener The single capture capture image listener 770 */ prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format, CaptureCallback resultListener, CameraCaptureSession.StateCallback sessionListener, int maxNumImages, ImageReader.OnImageAvailableListener imageListener)771 protected void prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest, 772 CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format, 773 CaptureCallback resultListener, CameraCaptureSession.StateCallback sessionListener, 774 int maxNumImages, ImageReader.OnImageAvailableListener imageListener) throws Exception { 775 if (VERBOSE) { 776 Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)", 777 captureSz.toString(), previewSz.toString())); 778 } 779 780 // Update preview size. 781 updatePreviewSurface(previewSz); 782 783 // Create ImageReader. 784 createImageReader(captureSz, format, maxNumImages, imageListener); 785 786 // Configure output streams with preview and jpeg streams. 787 List<Surface> outputSurfaces = new ArrayList<Surface>(); 788 outputSurfaces.add(mPreviewSurface); 789 outputSurfaces.add(mReaderSurface); 790 if (sessionListener == null) { 791 mSessionListener = new BlockingSessionCallback(); 792 } else { 793 mSessionListener = new BlockingSessionCallback(sessionListener); 794 } 795 mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); 796 797 // Configure the requests. 798 previewRequest.addTarget(mPreviewSurface); 799 stillRequest.addTarget(mPreviewSurface); 800 stillRequest.addTarget(mReaderSurface); 801 802 // Start preview. 803 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 804 } 805 806 /** 807 * Get the max preview size that supports the given fpsRange. 808 * 809 * @param fpsRange The fps range the returned size must support. 810 * @return max size that support the given fps range. 811 */ getMaxPreviewSizeForFpsRange(Range<Integer> fpsRange)812 protected Size getMaxPreviewSizeForFpsRange(Range<Integer> fpsRange) { 813 if (fpsRange == null || fpsRange.getLower() <= 0 || fpsRange.getUpper() <= 0) { 814 throw new IllegalArgumentException("Invalid fps range argument"); 815 } 816 if (mOrderedPreviewSizes == null || mMinPreviewFrameDurationMap == null) { 817 throw new IllegalStateException("mOrderedPreviewSizes and mMinPreviewFrameDurationMap" 818 + " must be initialized"); 819 } 820 821 long[] frameDurationRange = 822 new long[]{(long) (1e9 / fpsRange.getUpper()), (long) (1e9 / fpsRange.getLower())}; 823 for (Size size : mOrderedPreviewSizes) { 824 Long minDuration = mMinPreviewFrameDurationMap.get(size); 825 if (minDuration == null || 826 minDuration == 0) { 827 if (mStaticInfo.isCapabilitySupported( 828 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 829 throw new IllegalArgumentException( 830 "No min frame duration available for the size " + size); 831 } 832 continue; 833 } 834 if (minDuration <= (frameDurationRange[0] + MIN_FRAME_DURATION_ERROR_MARGIN)) { 835 return size; 836 } 837 } 838 839 // Search again for sizes not bounded by display size 840 for (Size size : m1080pBoundedOrderedPreviewSizes) { 841 Long minDuration = mMinPreviewFrameDurationMap.get(size); 842 if (minDuration == null || 843 minDuration == 0) { 844 if (mStaticInfo.isCapabilitySupported( 845 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 846 throw new IllegalArgumentException( 847 "No min frame duration available for the size " + size); 848 } 849 continue; 850 } 851 if (minDuration <= (frameDurationRange[0] + MIN_FRAME_DURATION_ERROR_MARGIN)) { 852 return size; 853 } 854 } 855 return null; 856 } 857 isReprocessSupported(String cameraId, int format)858 protected boolean isReprocessSupported(String cameraId, int format) 859 throws CameraAccessException { 860 if (format != ImageFormat.YUV_420_888 && format != ImageFormat.PRIVATE) { 861 throw new IllegalArgumentException( 862 "format " + format + " is not supported for reprocessing"); 863 } 864 865 StaticMetadata info = 866 new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId), 867 CheckLevel.ASSERT, /*collector*/ null); 868 int cap = CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING; 869 if (format == ImageFormat.PRIVATE) { 870 cap = CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING; 871 } 872 return info.isCapabilitySupported(cap); 873 } 874 getSuitableFpsRangeForDuration(String cameraId, long frameDuration)875 protected Range<Integer> getSuitableFpsRangeForDuration(String cameraId, long frameDuration) { 876 return CameraTestUtils.getSuitableFpsRangeForDuration(cameraId, frameDuration, mStaticInfo); 877 } 878 captureRequestsSynchronizedImpl( CaptureRequest request, int count, CaptureCallback listener, Handler handler, boolean isBurst)879 private int captureRequestsSynchronizedImpl( 880 CaptureRequest request, int count, CaptureCallback listener, Handler handler, 881 boolean isBurst) throws CameraAccessException { 882 if (count < 1) { 883 throw new IllegalArgumentException("count must be positive"); 884 } 885 886 int maxLatency = mStaticInfo.getSyncMaxLatency(); 887 if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { 888 maxLatency = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY; 889 } 890 891 assertTrue("maxLatency is non-negative", maxLatency >= 0); 892 893 int numCaptures = maxLatency + count; 894 ArrayList<CaptureRequest> burstCaptureRequests = new ArrayList<>(); 895 for (int i = 0; i < numCaptures; ++i) { 896 if (isBurst) { 897 burstCaptureRequests.add(request); 898 } else { 899 mSession.capture(request, listener, handler); 900 } 901 } 902 if (isBurst) { 903 mSession.captureBurst(burstCaptureRequests, listener, handler); 904 } 905 906 return numCaptures; 907 } 908 } 909