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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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