1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.camera2.cts.testcases;
18 
19 import static android.hardware.camera2.cts.CameraTestUtils.*;
20 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
21 
22 import android.content.Context;
23 import android.content.pm.PackageManager;
24 import android.graphics.Rect;
25 
26 import android.hardware.camera2.cts.CameraTestUtils;
27 import android.hardware.camera2.CameraCaptureSession;
28 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
29 import android.hardware.camera2.CameraCharacteristics;
30 import android.hardware.camera2.CameraDevice;
31 import android.hardware.camera2.CameraManager;
32 import android.hardware.camera2.CaptureRequest;
33 import android.hardware.camera2.params.OutputConfiguration;
34 import android.hardware.camera2.params.SessionConfiguration;
35 import android.util.Size;
36 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
37 import android.hardware.camera2.cts.helpers.StaticMetadata;
38 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
39 import android.media.Image;
40 import android.media.Image.Plane;
41 import android.media.ImageReader;
42 import android.os.Bundle;
43 import android.os.Handler;
44 import android.os.HandlerThread;
45 import android.util.Log;
46 import android.view.Surface;
47 import android.view.WindowManager;
48 
49 import androidx.test.InstrumentationRegistry;
50 
51 import com.android.ex.camera2.blocking.BlockingSessionCallback;
52 import com.android.ex.camera2.blocking.BlockingStateCallback;
53 
54 import org.junit.rules.ExternalResource;
55 
56 import java.io.File;
57 import java.nio.ByteBuffer;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.HashMap;
61 import java.util.List;
62 
63 public class Camera2AndroidTestRule extends ExternalResource {
64     private static final String TAG = "Camera2AndroidBasicTestCase";
65     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
66 
67     // Default capture size: VGA size is required by CDD.
68     protected static final Size DEFAULT_CAPTURE_SIZE = new Size(640, 480);
69     protected static final int CAPTURE_WAIT_TIMEOUT_MS = 5000;
70 
71     private CameraManager mCameraManager;
72     private CameraDevice mCamera;
73     private CameraCaptureSession mCameraSession;
74     private BlockingSessionCallback mCameraSessionListener;
75     private BlockingStateCallback mCameraListener;
76     private String[] mCameraIdsUnderTest;
77     // include both standalone camera IDs and "hidden" physical camera IDs
78     private String[] mAllCameraIds;
79     private HashMap<String, StaticMetadata> mAllStaticInfo;
80     private ImageReader mReader;
81     private Surface mReaderSurface;
82     private Handler mHandler;
83     private HandlerThread mHandlerThread;
84     private StaticMetadata mStaticInfo;
85     private CameraErrorCollector mCollector;
86     private List<Size> mOrderedPreviewSizes; // In descending order.
87     private List<Size> mOrderedVideoSizes; // In descending order.
88     private List<Size> mOrderedStillSizes; // In descending order.
89     private String mDebugFileNameBase;
90 
91     private WindowManager mWindowManager;
92     private Context mContext;
93 
94     private static final String CAMERA_ID_INSTR_ARG_KEY = "camera-id";
95     private static final String CAMERA_PERF_MEASURE = "perf-measure";
96     private static final String CAMERA_PERF_CLASS_TEST = "perf-class-test";
97     private static final Bundle mBundle = InstrumentationRegistry.getArguments();
98     private static final String mOverrideCameraId = mBundle.getString(CAMERA_ID_INSTR_ARG_KEY);
99     private static final String mPerfMeasure = mBundle.getString(CAMERA_PERF_MEASURE);
100     private static final String mPerfClassTest = mBundle.getString(CAMERA_PERF_CLASS_TEST);
101 
Camera2AndroidTestRule(Context context)102     public Camera2AndroidTestRule(Context context) {
103         mContext = context;
104     }
105 
getDebugFileNameBase()106     public String getDebugFileNameBase() {
107         return mDebugFileNameBase;
108     }
109 
getContext()110     public Context getContext() {
111         return mContext;
112     }
113 
getCameraIdsUnderTest()114     public String[] getCameraIdsUnderTest() throws Exception {
115         // If external camera is supported, verify that it is connected as part of the camera Ids
116         // under test. If the external camera is not connected, an exception will be thrown to
117         // prevent bypassing CTS testing for external camera
118         CameraTestUtils.verifyExternalCameraConnected(mCameraIdsUnderTest,
119                 mContext.getPackageManager(), mCameraManager);
120 
121         return mCameraIdsUnderTest;
122     }
123 
getStaticInfo()124     public StaticMetadata getStaticInfo() {
125         return mStaticInfo;
126     }
127 
getCameraManager()128     public CameraManager getCameraManager() {
129         return mCameraManager;
130     }
131 
setStaticInfo(StaticMetadata staticInfo)132     public void setStaticInfo(StaticMetadata staticInfo) {
133         mStaticInfo = staticInfo;
134     }
135 
getCameraSession()136     public CameraCaptureSession getCameraSession() {
137         return mCameraSession;
138     }
139 
getCamera()140     public CameraDevice getCamera() {
141         return mCamera;
142     }
143 
setCamera(CameraDevice camera)144     public void setCamera(CameraDevice camera) {
145         mCamera = camera;
146     }
147 
setCameraSession(CameraCaptureSession session)148     public void setCameraSession(CameraCaptureSession session) {
149         mCameraSession = session;
150     }
151 
getCameraListener()152     public BlockingStateCallback getCameraListener() {
153         return mCameraListener;
154     }
155 
getCameraSessionListener()156     public BlockingSessionCallback getCameraSessionListener() {
157         return mCameraSessionListener;
158     }
159 
getHandler()160     public Handler getHandler() {
161         return mHandler;
162     }
163 
setCameraSessionListener(BlockingSessionCallback listener)164     public void setCameraSessionListener(BlockingSessionCallback listener) {
165         mCameraSessionListener = listener;
166     }
167 
getReader()168     public ImageReader getReader() {
169         return mReader;
170     }
171 
getAllStaticInfo()172     public HashMap<String, StaticMetadata> getAllStaticInfo() {
173         return mAllStaticInfo;
174     }
175 
getOrderedPreviewSizes()176     public List<Size> getOrderedPreviewSizes() {
177         return mOrderedPreviewSizes;
178     }
179 
getOrderedStillSizes()180     public List<Size> getOrderedStillSizes() {
181         return mOrderedStillSizes;
182     }
183 
getReaderSurface()184     public Surface getReaderSurface() {
185         return mReaderSurface;
186     }
187 
setOrderedPreviewSizes(List<Size> sizes)188     public void setOrderedPreviewSizes(List<Size> sizes) {
189         mOrderedPreviewSizes = sizes;
190     }
191 
getWindowManager()192     public WindowManager getWindowManager() {
193         return mWindowManager;
194     }
195 
getCollector()196     public CameraErrorCollector getCollector() {
197         return mCollector;
198     }
199 
isPerfMeasure()200     public boolean isPerfMeasure() {
201         return mPerfMeasure != null && mPerfMeasure.equals("on");
202     }
203 
isPerfClassTest()204     public boolean isPerfClassTest() {
205         return mPerfClassTest != null && mPerfClassTest.equals("on");
206     }
207 
isCameraIdOverriddenForTest()208     public boolean isCameraIdOverriddenForTest() {
209         return mOverrideCameraId != null;
210     }
211 
deriveCameraIdsUnderTest()212     private String[] deriveCameraIdsUnderTest() throws Exception {
213         String[] idsUnderTest = mCameraManager.getCameraIdList();
214         assertNotNull("Camera ids shouldn't be null", idsUnderTest);
215         if (mOverrideCameraId != null) {
216             if (Arrays.asList(idsUnderTest).contains(mOverrideCameraId)) {
217                 idsUnderTest = new String[]{mOverrideCameraId};
218             } else {
219                 idsUnderTest = new String[]{};
220             }
221         }
222 
223         return idsUnderTest;
224     }
225 
226     /**
227      * Set up the camera2 test case required environments, including CameraManager,
228      * HandlerThread, Camera IDs, and CameraStateCallback etc.
229      */
230     @Override
before()231     public void before() throws Exception {
232         Log.v(TAG, "Set up...");
233         mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
234         assertNotNull("Can't connect to camera manager!", mCameraManager);
235         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
236         /**
237          * Workaround for mockito and JB-MR2 incompatibility
238          *
239          * Avoid java.lang.IllegalArgumentException: dexcache == null
240          * https://code.google.com/p/dexmaker/issues/detail?id=2
241          */
242         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
243 
244         mCameraIdsUnderTest = deriveCameraIdsUnderTest();
245         mHandlerThread = new HandlerThread(TAG);
246         mHandlerThread.start();
247         mHandler = new Handler(mHandlerThread.getLooper());
248         mCameraListener = new BlockingStateCallback();
249         mCollector = new CameraErrorCollector();
250 
251         File filesDir = mContext.getPackageManager().isInstantApp()
252                 ? mContext.getFilesDir()
253                 : mContext.getExternalFilesDir(null);
254 
255         mDebugFileNameBase = filesDir.getPath();
256 
257         mAllStaticInfo = new HashMap<String, StaticMetadata>();
258         List<String> hiddenPhysicalIds = new ArrayList<>();
259         for (String cameraId : mCameraIdsUnderTest) {
260             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId);
261             StaticMetadata staticMetadata = new StaticMetadata(props,
262                     CheckLevel.ASSERT, /*collector*/null);
263             mAllStaticInfo.put(cameraId, staticMetadata);
264 
265             for (String physicalId : props.getPhysicalCameraIds()) {
266                 if (!Arrays.asList(mCameraIdsUnderTest).contains(physicalId) &&
267                         !hiddenPhysicalIds.contains(physicalId)) {
268                     hiddenPhysicalIds.add(physicalId);
269                     props = mCameraManager.getCameraCharacteristics(physicalId);
270                     staticMetadata = new StaticMetadata(
271                             mCameraManager.getCameraCharacteristics(physicalId),
272                             CheckLevel.ASSERT, /*collector*/null);
273                     mAllStaticInfo.put(physicalId, staticMetadata);
274                 }
275             }
276         }
277         mAllCameraIds = new String[mCameraIdsUnderTest.length + hiddenPhysicalIds.size()];
278         System.arraycopy(mCameraIdsUnderTest, 0, mAllCameraIds, 0, mCameraIdsUnderTest.length);
279         for (int i = 0; i < hiddenPhysicalIds.size(); i++) {
280             mAllCameraIds[mCameraIdsUnderTest.length + i] = hiddenPhysicalIds.get(i);
281         }
282     }
283 
284     @Override
after()285     public void after() {
286         Log.v(TAG, "Tear down...");
287         if (mCameraManager != null) {
288             try {
289                 String[] cameraIdsPostTest = deriveCameraIdsUnderTest();
290                 Log.i(TAG, "Camera ids in setup:" + Arrays.toString(mCameraIdsUnderTest));
291                 Log.i(TAG, "Camera ids in tearDown:" + Arrays.toString(cameraIdsPostTest));
292                 assertTrue(
293                         "Number of cameras changed from " + mCameraIdsUnderTest.length + " to " +
294                                 cameraIdsPostTest.length,
295                         mCameraIdsUnderTest.length == cameraIdsPostTest.length);
296                 mHandlerThread.quitSafely();
297                 mHandler = null;
298                 closeDefaultImageReader();
299                 mCollector.verify();
300             } catch (Throwable e) {
301                 // When new Exception(e) is used, exception info will be printed twice.
302                 throw new RuntimeException(e.getMessage());
303             }
304         }
305     }
306 
307     /**
308      * Start capture with given {@link #CaptureRequest}.
309      *
310      * @param request The {@link #CaptureRequest} to be captured.
311      * @param repeating If the capture is single capture or repeating.
312      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
313      * @param handler The handler camera device used to post callbacks.
314      */
startCapture(CaptureRequest request, boolean repeating, CaptureCallback listener, Handler handler)315     public void startCapture(CaptureRequest request, boolean repeating,
316             CaptureCallback listener, Handler handler) throws Exception {
317         if (VERBOSE) Log.v(TAG, "Starting capture from device");
318 
319         if (repeating) {
320             mCameraSession.setRepeatingRequest(request, listener, handler);
321         } else {
322             mCameraSession.capture(request, listener, handler);
323         }
324     }
325 
326     /**
327      * Stop the current active capture.
328      *
329      * @param fast When it is true, {@link CameraDevice#flush} is called, the stop capture
330      * could be faster.
331      */
stopCapture(boolean fast)332     public void stopCapture(boolean fast) throws Exception {
333         if (VERBOSE) Log.v(TAG, "Stopping capture");
334 
335         if (fast) {
336             /**
337              * Flush is useful for canceling long exposure single capture, it also could help
338              * to make the streaming capture stop sooner.
339              */
340             mCameraSession.abortCaptures();
341             mCameraSessionListener.getStateWaiter().
342                     waitForState(BlockingSessionCallback.SESSION_READY, CAMERA_IDLE_TIMEOUT_MS);
343         } else {
344             mCameraSession.close();
345             mCameraSessionListener.getStateWaiter().
346                     waitForState(BlockingSessionCallback.SESSION_CLOSED, CAMERA_IDLE_TIMEOUT_MS);
347         }
348     }
349 
350     /**
351      * Open a {@link #CameraDevice camera device} and get the StaticMetadata for a given camera id.
352      * The default mCameraListener is used to wait for states.
353      *
354      * @param cameraId The id of the camera device to be opened.
355      */
openDevice(String cameraId)356     public void openDevice(String cameraId) throws Exception {
357         openDevice(cameraId, mCameraListener);
358     }
359 
360     /**
361      * Open a {@link #CameraDevice} and get the StaticMetadata for a given camera id and listener.
362      *
363      * @param cameraId The id of the camera device to be opened.
364      * @param listener The {@link #BlockingStateCallback} used to wait for states.
365      */
openDevice(String cameraId, BlockingStateCallback listener)366     public void openDevice(String cameraId, BlockingStateCallback listener) throws Exception {
367         mCamera = CameraTestUtils.openCamera(
368                 mCameraManager, cameraId, listener, mHandler);
369         mCollector.setCameraId(cameraId);
370         mStaticInfo = mAllStaticInfo.get(cameraId);
371         if (mStaticInfo.isColorOutputSupported()) {
372             mOrderedPreviewSizes = getSupportedPreviewSizes(
373                     cameraId, mCameraManager,
374                     getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
375             mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
376             mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
377         }
378 
379         if (VERBOSE) {
380             Log.v(TAG, "Camera " + cameraId + " is opened");
381         }
382     }
383 
384     /**
385      * Create a {@link #CameraCaptureSession} using the currently open camera.
386      *
387      * @param outputSurfaces The set of output surfaces to configure for this session
388      */
createSession(List<Surface> outputSurfaces)389     public void createSession(List<Surface> outputSurfaces) throws Exception {
390         mCameraSessionListener = new BlockingSessionCallback();
391         mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
392                 mCameraSessionListener, mHandler);
393     }
394 
395     /**
396      * Create a {@link #CameraCaptureSession} using the currently open camera with
397      * OutputConfigurations.
398      *
399      * @param outputSurfaces The set of output surfaces to configure for this session
400      */
createSessionByConfigs(List<OutputConfiguration> outputConfigs)401     public void createSessionByConfigs(List<OutputConfiguration> outputConfigs) throws Exception {
402         mCameraSessionListener = new BlockingSessionCallback();
403         mCameraSession = CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputConfigs,
404                 mCameraSessionListener, mHandler);
405     }
406 
407     /**
408      * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a
409      * given camera id. The default mCameraListener is used to wait for states.
410      * <p>
411      * This function must be used along with the {@link #openDevice} for the
412      * same camera id.
413      * </p>
414      *
415      * @param cameraId The id of the {@link #CameraDevice camera device} to be closed.
416      */
closeDevice(String cameraId)417     public void closeDevice(String cameraId) {
418         closeDevice(cameraId, mCameraListener);
419     }
420 
421     /**
422      * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a
423      * given camera id and listener.
424      * <p>
425      * This function must be used along with the {@link #openDevice} for the
426      * same camera id.
427      * </p>
428      *
429      * @param cameraId The id of the camera device to be closed.
430      * @param listener The BlockingStateCallback used to wait for states.
431      */
closeDevice(String cameraId, BlockingStateCallback listener)432     public void closeDevice(String cameraId, BlockingStateCallback listener) {
433         if (mCamera != null) {
434             if (!cameraId.equals(mCamera.getId())) {
435                 throw new IllegalStateException("Try to close a device that is not opened yet");
436             }
437             mCamera.close();
438             listener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
439             mCamera = null;
440             mCameraSession = null;
441             mCameraSessionListener = null;
442             mStaticInfo = null;
443             mOrderedPreviewSizes = null;
444             mOrderedVideoSizes = null;
445             mOrderedStillSizes = null;
446 
447             if (VERBOSE) {
448                 Log.v(TAG, "Camera " + cameraId + " is closed");
449             }
450         }
451     }
452 
453     /**
454      * Create an {@link ImageReader} object and get the surface.
455      * <p>
456      * This function creates {@link ImageReader} object and surface, then assign
457      * to the default {@link mReader} and {@link mReaderSurface}. It closes the
458      * current default active {@link ImageReader} if it exists.
459      * </p>
460      *
461      * @param size The size of this ImageReader to be created.
462      * @param format The format of this ImageReader to be created
463      * @param maxNumImages The max number of images that can be acquired
464      *            simultaneously.
465      * @param listener The listener used by this ImageReader to notify
466      *            callbacks.
467      */
createDefaultImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)468     public void createDefaultImageReader(Size size, int format, int maxNumImages,
469             ImageReader.OnImageAvailableListener listener) throws Exception {
470         closeDefaultImageReader();
471 
472         mReader = createImageReader(size, format, maxNumImages, listener);
473         mReaderSurface = mReader.getSurface();
474         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
475     }
476 
477     /**
478      * Create an {@link ImageReader} object and get the surface.
479      * <p>
480      * This function creates {@link ImageReader} object and surface, then assign
481      * to the default {@link mReader} and {@link mReaderSurface}. It closes the
482      * current default active {@link ImageReader} if it exists.
483      * </p>
484      *
485      * @param size The size of this ImageReader to be created.
486      * @param format The format of this ImageReader to be created
487      * @param maxNumImages The max number of images that can be acquired
488      *            simultaneously.
489      * @param usage The usage flag of the ImageReader
490      * @param listener The listener used by this ImageReader to notify
491      *            callbacks.
492      */
createDefaultImageReader(Size size, int format, int maxNumImages, long usage, ImageReader.OnImageAvailableListener listener)493     public void createDefaultImageReader(Size size, int format, int maxNumImages, long usage,
494             ImageReader.OnImageAvailableListener listener) throws Exception {
495         closeDefaultImageReader();
496 
497         mReader = createImageReader(size, format, maxNumImages, usage, listener);
498         mReaderSurface = mReader.getSurface();
499         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
500     }
501 
502     /**
503      * Create an {@link ImageReader} object.
504      *
505      * <p>This function creates image reader object for given format, maxImages, and size.</p>
506      *
507      * @param size The size of this ImageReader to be created.
508      * @param format The format of this ImageReader to be created
509      * @param maxNumImages The max number of images that can be acquired simultaneously.
510      * @param listener The listener used by this ImageReader to notify callbacks.
511      */
512 
createImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)513     public ImageReader createImageReader(Size size, int format, int maxNumImages,
514             ImageReader.OnImageAvailableListener listener) throws Exception {
515 
516         ImageReader reader = null;
517         reader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
518                 format, maxNumImages);
519 
520         reader.setOnImageAvailableListener(listener, mHandler);
521         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
522         return reader;
523     }
524 
525     /**
526      * Create an {@link ImageReader} object.
527      *
528      * <p>This function creates image reader object for given format, maxImages, usage and size.</p>
529      *
530      * @param size The size of this ImageReader to be created.
531      * @param format The format of this ImageReader to be created
532      * @param maxNumImages The max number of images that can be acquired simultaneously.
533      * @param usage The usage flag of the ImageReader
534      * @param listener The listener used by this ImageReader to notify callbacks.
535      */
536 
createImageReader(Size size, int format, int maxNumImages, long usage, ImageReader.OnImageAvailableListener listener)537     public ImageReader createImageReader(Size size, int format, int maxNumImages, long usage,
538             ImageReader.OnImageAvailableListener listener) throws Exception {
539         ImageReader reader = null;
540         reader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
541                 format, maxNumImages, usage);
542 
543         reader.setOnImageAvailableListener(listener, mHandler);
544         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
545         return reader;
546     }
547 
548     /**
549      * Close the pending images then close current default {@link ImageReader} object.
550      */
closeDefaultImageReader()551     public void closeDefaultImageReader() {
552         closeImageReader(mReader);
553         mReader = null;
554         mReaderSurface = null;
555     }
556 
557     /**
558      * Close an image reader instance.
559      *
560      * @param reader
561      */
closeImageReader(ImageReader reader)562     public void closeImageReader(ImageReader reader) {
563         if (reader != null) {
564             try {
565                 // Close all possible pending images first.
566                 Image image = reader.acquireLatestImage();
567                 if (image != null) {
568                     image.close();
569                 }
570             } finally {
571                 reader.close();
572                 reader = null;
573             }
574         }
575     }
576 
checkImageReaderSessionConfiguration(String msg)577     public void checkImageReaderSessionConfiguration(String msg) throws Exception {
578         List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
579         outputConfigs.add(new OutputConfiguration(mReaderSurface));
580 
581         checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, /*inputConfig*/ null,
582                 SessionConfiguration.SESSION_REGULAR, mCameraManager, /*expectedResult*/ true, msg);
583     }
584 
prepareCaptureRequest()585     public CaptureRequest prepareCaptureRequest() throws Exception {
586         return prepareCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
587     }
588 
prepareCaptureRequest(int template)589     public CaptureRequest prepareCaptureRequest(int template) throws Exception {
590         List<Surface> outputSurfaces = new ArrayList<Surface>();
591         Surface surface = mReader.getSurface();
592         assertNotNull("Fail to get surface from ImageReader", surface);
593         outputSurfaces.add(surface);
594         return prepareCaptureRequestForSurfaces(outputSurfaces, template)
595                 .build();
596     }
597 
prepareCaptureRequestForSurfaces(List<Surface> surfaces, int template)598     public CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces,
599             int template)
600             throws Exception {
601         createSession(surfaces);
602 
603         CaptureRequest.Builder captureBuilder =
604                 mCamera.createCaptureRequest(template);
605         assertNotNull("Fail to get captureRequest", captureBuilder);
606         for (Surface surface : surfaces) {
607             captureBuilder.addTarget(surface);
608         }
609 
610         return captureBuilder;
611     }
612 
prepareCaptureRequestForConfigs( List<OutputConfiguration> outputConfigs, int template)613     public CaptureRequest.Builder prepareCaptureRequestForConfigs(
614             List<OutputConfiguration> outputConfigs, int template) throws Exception {
615         createSessionByConfigs(outputConfigs);
616 
617         CaptureRequest.Builder captureBuilder =
618                 mCamera.createCaptureRequest(template);
619         assertNotNull("Fail to get captureRequest", captureBuilder);
620         for (OutputConfiguration config : outputConfigs) {
621             for (Surface s : config.getSurfaces()) {
622                 captureBuilder.addTarget(s);
623             }
624         }
625 
626         return captureBuilder;
627     }
628 
629     /**
630      * Test the invalid Image access: accessing a closed image must result in
631      * {@link IllegalStateException}.
632      *
633      * @param closedImage The closed image.
634      * @param closedBuffer The ByteBuffer from a closed Image. buffer invalid
635      *            access will be skipped if it is null.
636      */
imageInvalidAccessTestAfterClose(Image closedImage, Plane closedPlane, ByteBuffer closedBuffer)637     public void imageInvalidAccessTestAfterClose(Image closedImage,
638             Plane closedPlane, ByteBuffer closedBuffer) {
639         if (closedImage == null) {
640             throw new IllegalArgumentException(" closedImage must be non-null");
641         }
642         if (closedBuffer != null && !closedBuffer.isDirect()) {
643             throw new IllegalArgumentException("The input ByteBuffer should be direct ByteBuffer");
644         }
645 
646         if (closedPlane != null) {
647             // Plane#getBuffer test
648             try {
649                 closedPlane.getBuffer(); // An ISE should be thrown here.
650                 fail("Image should throw IllegalStateException when calling getBuffer"
651                         + " after the image is closed");
652             } catch (IllegalStateException e) {
653                 // Expected.
654             }
655 
656             // Plane#getPixelStride test
657             try {
658                 closedPlane.getPixelStride(); // An ISE should be thrown here.
659                 fail("Image should throw IllegalStateException when calling getPixelStride"
660                         + " after the image is closed");
661             } catch (IllegalStateException e) {
662                 // Expected.
663             }
664 
665             // Plane#getRowStride test
666             try {
667                 closedPlane.getRowStride(); // An ISE should be thrown here.
668                 fail("Image should throw IllegalStateException when calling getRowStride"
669                         + " after the image is closed");
670             } catch (IllegalStateException e) {
671                 // Expected.
672             }
673         }
674 
675         // ByteBuffer access test
676         if (closedBuffer != null) {
677             try {
678                 closedBuffer.get(); // An ISE should be thrown here.
679                 fail("Image should throw IllegalStateException when accessing a byte buffer"
680                         + " after the image is closed");
681             } catch (IllegalStateException e) {
682                 // Expected.
683             }
684         }
685 
686         // Image#getFormat test
687         try {
688             closedImage.getFormat();
689             fail("Image should throw IllegalStateException when calling getFormat"
690                     + " after the image is closed");
691         } catch (IllegalStateException e) {
692             // Expected.
693         }
694 
695         // Image#getWidth test
696         try {
697             closedImage.getWidth();
698             fail("Image should throw IllegalStateException when calling getWidth"
699                     + " after the image is closed");
700         } catch (IllegalStateException e) {
701             // Expected.
702         }
703 
704         // Image#getHeight test
705         try {
706             closedImage.getHeight();
707             fail("Image should throw IllegalStateException when calling getHeight"
708                     + " after the image is closed");
709         } catch (IllegalStateException e) {
710             // Expected.
711         }
712 
713         // Image#getTimestamp test
714         try {
715             closedImage.getTimestamp();
716             fail("Image should throw IllegalStateException when calling getTimestamp"
717                     + " after the image is closed");
718         } catch (IllegalStateException e) {
719             // Expected.
720         }
721 
722         // Image#getTimestamp test
723         try {
724             closedImage.getTimestamp();
725             fail("Image should throw IllegalStateException when calling getTimestamp"
726                     + " after the image is closed");
727         } catch (IllegalStateException e) {
728             // Expected.
729         }
730 
731         // Image#getCropRect test
732         try {
733             closedImage.getCropRect();
734             fail("Image should throw IllegalStateException when calling getCropRect"
735                     + " after the image is closed");
736         } catch (IllegalStateException e) {
737             // Expected.
738         }
739 
740         // Image#setCropRect test
741         try {
742             Rect rect = new Rect();
743             closedImage.setCropRect(rect);
744             fail("Image should throw IllegalStateException when calling setCropRect"
745                     + " after the image is closed");
746         } catch (IllegalStateException e) {
747             // Expected.
748         }
749 
750         // Image#getPlanes test
751         try {
752             closedImage.getPlanes();
753             fail("Image should throw IllegalStateException when calling getPlanes"
754                     + " after the image is closed");
755         } catch (IllegalStateException e) {
756             // Expected.
757         }
758     }
759 }
760