Home | History | Annotate | Download | only in mediaframeworktest
      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 com.android.ex.camera2.blocking.BlockingSessionCallback;
     20 import com.android.ex.camera2.blocking.BlockingStateCallback;
     21 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
     22 import com.android.mediaframeworktest.helpers.CameraErrorCollector;
     23 import com.android.mediaframeworktest.helpers.CameraTestResultPrinter;
     24 import com.android.mediaframeworktest.helpers.CameraTestUtils;
     25 import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
     26 import com.android.mediaframeworktest.helpers.StaticMetadata;
     27 import com.android.mediaframeworktest.helpers.StaticMetadata.CheckLevel;
     28 
     29 import android.content.Context;
     30 import android.graphics.ImageFormat;
     31 import android.hardware.camera2.CameraAccessException;
     32 import android.hardware.camera2.CameraCaptureSession;
     33 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
     34 import android.hardware.camera2.CameraCharacteristics;
     35 import android.hardware.camera2.CameraDevice;
     36 import android.hardware.camera2.CameraManager;
     37 import android.hardware.camera2.CameraMetadata;
     38 import android.hardware.camera2.CaptureRequest;
     39 import android.hardware.camera2.CaptureResult;
     40 import android.hardware.camera2.params.StreamConfigurationMap;
     41 import android.media.ImageReader;
     42 import android.graphics.SurfaceTexture;
     43 import android.os.Bundle;
     44 import android.os.Environment;
     45 import android.os.Handler;
     46 import android.os.HandlerThread;
     47 import android.os.Looper;
     48 import android.test.ActivityInstrumentationTestCase2;
     49 import android.test.InstrumentationTestRunner;
     50 import android.util.Log;
     51 import android.util.Range;
     52 import android.util.Size;
     53 import android.view.Surface;
     54 import android.view.SurfaceHolder;
     55 import android.view.WindowManager;
     56 
     57 import java.text.NumberFormat;
     58 import java.text.ParseException;
     59 import java.util.ArrayList;
     60 import java.util.HashMap;
     61 import java.util.List;
     62 
     63 import static com.android.ex.camera2.blocking.BlockingStateCallback.STATE_CLOSED;
     64 import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAMERA_CLOSE_TIMEOUT_MS;
     65 import static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES;
     66 import static com.android.mediaframeworktest.helpers.CameraTestUtils.PREVIEW_SIZE_BOUND;
     67 import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
     68 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getPreviewSizeBound;
     69 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedPreviewSizes;
     70 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedStillSizes;
     71 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
     72 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSortedSizesForFormat;
     73 import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
     74 
     75 /**
     76  * Camera2 Preview test case base class by using SurfaceView as rendering target.
     77  *
     78  * <p>This class encapsulates the SurfaceView based preview common functionalities.
     79  * The setup and teardown of CameraManager, test HandlerThread, Activity, Camera IDs
     80  * and CameraStateCallback are handled in this class. Some basic preview related utility
     81  * functions are provided to facilitate the derived preview-based test classes.
     82  * </p>
     83  */
     84 /**
     85  * (non-Javadoc)
     86  * @see android.hardware.camera2.cts.Camera2SurfaceViewTestCase
     87  */
     88 public class Camera2SurfaceViewTestCase extends
     89         ActivityInstrumentationTestCase2<Camera2SurfaceViewActivity> {
     90 
     91     private static final String TAG = "SurfaceViewTestCase";
     92     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     93     private static final int WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS = 1000;
     94 
     95     // Instrumentation arguments
     96     protected static final String ARG_KEY_ITERATIONS = "iterations";
     97     protected static final String ARG_KEY_WAIT_INTERVAL_MS = "waitIntervalMs";
     98     protected static final String ARG_KEY_RESULT_TO_FILE = "resultToFile";
     99 
    100     // TODO: Use internal storage for this to make sure the file is only visible to test.
    101     protected static final String DEBUG_FILE_NAME_BASE =
    102             Environment.getExternalStorageDirectory().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 
    143     public Camera2SurfaceViewTestCase() {
    144         super(Camera2SurfaceViewActivity.class);
    145     }
    146 
    147     @Override
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    781     protected Bundle getArguments() {
    782         return ((InstrumentationTestRunner)getInstrumentation()).getArguments();
    783     }
    784 
    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 
    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 
    811     protected int getIterationCount() {
    812         return mIterations;
    813     }
    814 
    815     protected long getTestWaitIntervalMs() {
    816         return mTestWaitIntervalMs;
    817     }
    818 
    819     public CameraTestResultPrinter getResultPrinter() {
    820         return mResultPrinter;
    821     }
    822 }
    823