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