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