• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
21 
22 import android.content.Context;
23 import android.hardware.camera2.CameraCaptureSession;
24 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
25 import android.hardware.camera2.CameraDevice;
26 import android.hardware.camera2.CameraManager;
27 import android.hardware.camera2.CaptureRequest;
28 import android.util.Size;
29 import android.hardware.camera2.cts.CameraTestUtils;
30 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
31 import android.hardware.camera2.cts.helpers.StaticMetadata;
32 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
33 import android.media.Image;
34 import android.media.ImageReader;
35 import android.os.Environment;
36 import android.os.Handler;
37 import android.os.HandlerThread;
38 import android.test.AndroidTestCase;
39 import android.util.Log;
40 import android.view.Surface;
41 
42 import com.android.ex.camera2.blocking.BlockingSessionCallback;
43 import com.android.ex.camera2.blocking.BlockingStateCallback;
44 
45 import java.util.List;
46 
47 public class Camera2AndroidTestCase extends AndroidTestCase {
48     private static final String TAG = "Camera2AndroidTestCase";
49     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
50 
51     protected static final String DEBUG_FILE_NAME_BASE =
52             Environment.getExternalStorageDirectory().getPath();
53     // Default capture size: VGA size is required by CDD.
54     protected static final Size DEFAULT_CAPTURE_SIZE = new Size(640, 480);
55     protected static final int CAPTURE_WAIT_TIMEOUT_MS = 5000;
56 
57     protected CameraManager mCameraManager;
58     protected CameraDevice mCamera;
59     protected CameraCaptureSession mCameraSession;
60     protected BlockingSessionCallback mCameraSessionListener;
61     protected BlockingStateCallback mCameraListener;
62     protected String[] mCameraIds;
63     protected ImageReader mReader;
64     protected Surface mReaderSurface;
65     protected Handler mHandler;
66     protected HandlerThread mHandlerThread;
67     protected StaticMetadata mStaticInfo;
68     protected CameraErrorCollector mCollector;
69     protected List<Size> mOrderedPreviewSizes; // In descending order.
70     protected List<Size> mOrderedVideoSizes; // In descending order.
71     protected List<Size> mOrderedStillSizes; // In descending order.
72 
73     @Override
setContext(Context context)74     public void setContext(Context context) {
75         super.setContext(context);
76         mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
77         assertNotNull("Can't connect to camera manager!", mCameraManager);
78     }
79 
80     /**
81      * Set up the camera2 test case required environments, including CameraManager,
82      * HandlerThread, Camera IDs, and CameraStateCallback etc.
83      */
84     @Override
setUp()85     protected void setUp() throws Exception {
86         super.setUp();
87 
88         /**
89          * Workaround for mockito and JB-MR2 incompatibility
90          *
91          * Avoid java.lang.IllegalArgumentException: dexcache == null
92          * https://code.google.com/p/dexmaker/issues/detail?id=2
93          */
94         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
95 
96         mCameraIds = mCameraManager.getCameraIdList();
97         assertNotNull("Camera ids shouldn't be null", mCameraIds);
98         mHandlerThread = new HandlerThread(TAG);
99         mHandlerThread.start();
100         mHandler = new Handler(mHandlerThread.getLooper());
101         mCameraListener = new BlockingStateCallback();
102         mCollector = new CameraErrorCollector();
103     }
104 
105     @Override
tearDown()106     protected void tearDown() throws Exception {
107         mHandlerThread.quitSafely();
108         mHandler = null;
109         closeDefaultImageReader();
110 
111         try {
112             mCollector.verify();
113         } catch (Throwable e) {
114             // When new Exception(e) is used, exception info will be printed twice.
115             throw new Exception(e.getMessage());
116         } finally {
117             super.tearDown();
118         }
119     }
120 
121     /**
122      * Start capture with given {@link #CaptureRequest}.
123      *
124      * @param request The {@link #CaptureRequest} to be captured.
125      * @param repeating If the capture is single capture or repeating.
126      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
127      * @param handler The handler camera device used to post callbacks.
128      */
startCapture(CaptureRequest request, boolean repeating, CaptureCallback listener, Handler handler)129     protected void startCapture(CaptureRequest request, boolean repeating,
130             CaptureCallback listener, Handler handler) throws Exception {
131         if (VERBOSE) Log.v(TAG, "Starting capture from device");
132 
133         if (repeating) {
134             mCameraSession.setRepeatingRequest(request, listener, handler);
135         } else {
136             mCameraSession.capture(request, listener, handler);
137         }
138     }
139 
140     /**
141      * Stop the current active capture.
142      *
143      * @param fast When it is true, {@link CameraDevice#flush} is called, the stop capture
144      * could be faster.
145      */
stopCapture(boolean fast)146     protected void stopCapture(boolean fast) throws Exception {
147         if (VERBOSE) Log.v(TAG, "Stopping capture");
148 
149         if (fast) {
150             /**
151              * Flush is useful for canceling long exposure single capture, it also could help
152              * to make the streaming capture stop sooner.
153              */
154             mCameraSession.abortCaptures();
155             mCameraSessionListener.getStateWaiter().
156                     waitForState(BlockingSessionCallback.SESSION_READY, CAMERA_IDLE_TIMEOUT_MS);
157         } else {
158             mCameraSession.close();
159             mCameraSessionListener.getStateWaiter().
160                     waitForState(BlockingSessionCallback.SESSION_CLOSED, CAMERA_IDLE_TIMEOUT_MS);
161         }
162     }
163 
164     /**
165      * Open a {@link #CameraDevice camera device} and get the StaticMetadata for a given camera id.
166      * The default mCameraListener is used to wait for states.
167      *
168      * @param cameraId The id of the camera device to be opened.
169      */
openDevice(String cameraId)170     protected void openDevice(String cameraId) throws Exception {
171         openDevice(cameraId, mCameraListener);
172     }
173 
174     /**
175      * Open a {@link #CameraDevice} and get the StaticMetadata for a given camera id and listener.
176      *
177      * @param cameraId The id of the camera device to be opened.
178      * @param listener The {@link #BlockingStateCallback} used to wait for states.
179      */
openDevice(String cameraId, BlockingStateCallback listener)180     protected void openDevice(String cameraId, BlockingStateCallback listener) throws Exception {
181         mCamera = CameraTestUtils.openCamera(
182                 mCameraManager, cameraId, listener, mHandler);
183         mCollector.setCameraId(cameraId);
184         mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId),
185                 CheckLevel.ASSERT, /*collector*/null);
186         mOrderedPreviewSizes = getSupportedPreviewSizes(
187                 cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
188         mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
189         mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
190 
191         if (VERBOSE) {
192             Log.v(TAG, "Camera " + cameraId + " is opened");
193         }
194     }
195 
196     /**
197      * Create a {@link #CameraCaptureSession} using the currently open camera.
198      *
199      * @param outputSurfaces The set of output surfaces to configure for this session
200      */
createSession(List<Surface> outputSurfaces)201     protected void createSession(List<Surface> outputSurfaces) throws Exception {
202         mCameraSessionListener = new BlockingSessionCallback();
203         mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
204                 mCameraSessionListener, mHandler);
205     }
206 
207     /**
208      * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a
209      * given camera id. The default mCameraListener is used to wait for states.
210      * <p>
211      * This function must be used along with the {@link #openDevice} for the
212      * same camera id.
213      * </p>
214      *
215      * @param cameraId The id of the {@link #CameraDevice camera device} to be closed.
216      */
closeDevice(String cameraId)217     protected void closeDevice(String cameraId) {
218         closeDevice(cameraId, mCameraListener);
219     }
220 
221     /**
222      * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a
223      * given camera id and listener.
224      * <p>
225      * This function must be used along with the {@link #openDevice} for the
226      * same camera id.
227      * </p>
228      *
229      * @param cameraId The id of the camera device to be closed.
230      * @param listener The BlockingStateCallback used to wait for states.
231      */
closeDevice(String cameraId, BlockingStateCallback listener)232     protected void closeDevice(String cameraId, BlockingStateCallback listener) {
233         if (mCamera != null) {
234             if (!cameraId.equals(mCamera.getId())) {
235                 throw new IllegalStateException("Try to close a device that is not opened yet");
236             }
237             mCamera.close();
238             listener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
239             mCamera = null;
240             mCameraSession = null;
241             mCameraSessionListener = null;
242             mStaticInfo = null;
243             mOrderedPreviewSizes = null;
244             mOrderedVideoSizes = null;
245             mOrderedStillSizes = null;
246 
247             if (VERBOSE) {
248                 Log.v(TAG, "Camera " + cameraId + " is closed");
249             }
250         }
251     }
252 
253     /**
254      * Create an {@link ImageReader} object and get the surface.
255      * <p>
256      * This function creates {@link ImageReader} object and surface, then assign
257      * to the default {@link mReader} and {@link mReaderSurface}. It closes the
258      * current default active {@link ImageReader} if it exists.
259      * </p>
260      *
261      * @param size The size of this ImageReader to be created.
262      * @param format The format of this ImageReader to be created
263      * @param maxNumImages The max number of images that can be acquired
264      *            simultaneously.
265      * @param listener The listener used by this ImageReader to notify
266      *            callbacks.
267      */
createDefaultImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)268     protected void createDefaultImageReader(Size size, int format, int maxNumImages,
269             ImageReader.OnImageAvailableListener listener) throws Exception {
270         closeDefaultImageReader();
271 
272         mReader = createImageReader(size, format, maxNumImages, listener);
273         mReaderSurface = mReader.getSurface();
274         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
275     }
276 
277     /**
278      * Create an {@link ImageReader} object.
279      *
280      * <p>This function creates image reader object for given format, maxImages, and size.</p>
281      *
282      * @param size The size of this ImageReader to be created.
283      * @param format The format of this ImageReader to be created
284      * @param maxNumImages The max number of images that can be acquired simultaneously.
285      * @param listener The listener used by this ImageReader to notify callbacks.
286      */
287 
createImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)288     protected ImageReader createImageReader(Size size, int format, int maxNumImages,
289             ImageReader.OnImageAvailableListener listener) throws Exception {
290 
291         ImageReader reader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
292                 format, maxNumImages);
293         reader.setOnImageAvailableListener(listener, mHandler);
294         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
295         return reader;
296     }
297 
298     /**
299      * Close the pending images then close current default {@link ImageReader} object.
300      */
closeDefaultImageReader()301     protected void closeDefaultImageReader() {
302         closeImageReader(mReader);
303         mReader = null;
304         mReaderSurface = null;
305     }
306 
307     /**
308      * Close an image reader instance.
309      *
310      * @param reader
311      */
closeImageReader(ImageReader reader)312     protected void closeImageReader(ImageReader reader) {
313         if (reader != null) {
314             try {
315                 // Close all possible pending images first.
316                 Image image = reader.acquireLatestImage();
317                 if (image != null) {
318                     image.close();
319                 }
320             } finally {
321                 reader.close();
322                 reader = null;
323             }
324         }
325     }
326 }
327