1 package org.robolectric.shadows; 2 3 import static org.robolectric.shadow.api.Shadow.newInstanceOf; 4 5 import android.graphics.ImageFormat; 6 import android.hardware.Camera; 7 import android.view.SurfaceHolder; 8 import java.util.ArrayList; 9 import java.util.Arrays; 10 import java.util.Collections; 11 import java.util.HashMap; 12 import java.util.List; 13 import java.util.Map; 14 import org.robolectric.Shadows; 15 import org.robolectric.annotation.Implementation; 16 import org.robolectric.annotation.Implements; 17 import org.robolectric.annotation.RealObject; 18 19 @Implements(Camera.class) 20 public class ShadowCamera { 21 22 private static int lastOpenedCameraId; 23 24 private int id; 25 private boolean locked; 26 private boolean previewing; 27 private boolean released; 28 private Camera.Parameters parameters; 29 private Camera.PreviewCallback previewCallback; 30 private List<byte[]> callbackBuffers = new ArrayList<>(); 31 private SurfaceHolder surfaceHolder; 32 private int displayOrientation; 33 private Camera.AutoFocusCallback autoFocusCallback; 34 private boolean autoFocusing; 35 36 private static Map<Integer, Camera.CameraInfo> cameras = new HashMap<>(); 37 38 @RealObject 39 private Camera realCamera; 40 41 @Implementation 42 public void __constructor__() { 43 locked = true; 44 previewing = false; 45 released = false; 46 } 47 48 @Implementation 49 public static Camera open() { 50 lastOpenedCameraId = 0; 51 Camera camera = newInstanceOf(Camera.class); 52 Shadows.shadowOf(camera).id = 0; 53 return camera; 54 } 55 56 @Implementation 57 public static Camera open(int cameraId) { 58 lastOpenedCameraId = cameraId; 59 Camera camera = newInstanceOf(Camera.class); 60 Shadows.shadowOf(camera).id = cameraId; 61 return camera; 62 } 63 64 public static int getLastOpenedCameraId() { 65 return lastOpenedCameraId; 66 } 67 68 @Implementation 69 public void unlock() { 70 locked = false; 71 } 72 73 @Implementation 74 public void reconnect() { 75 locked = true; 76 } 77 78 @Implementation 79 public Camera.Parameters getParameters() { 80 if (null == parameters) { 81 parameters = newInstanceOf(Camera.Parameters.class); 82 } 83 return parameters; 84 } 85 86 @Implementation 87 public void setParameters(Camera.Parameters params) { 88 parameters = params; 89 } 90 91 @Implementation 92 public void setPreviewDisplay(SurfaceHolder holder) { 93 surfaceHolder = holder; 94 } 95 96 @Implementation 97 public void startPreview() { 98 previewing = true; 99 } 100 101 @Implementation 102 public void stopPreview() { 103 previewing = false; 104 } 105 106 @Implementation 107 public void release() { 108 released = true; 109 } 110 111 @Implementation 112 public void setPreviewCallback(Camera.PreviewCallback cb) { 113 previewCallback = cb; 114 } 115 116 @Implementation 117 public void setOneShotPreviewCallback(Camera.PreviewCallback cb) { 118 previewCallback = cb; 119 } 120 121 @Implementation 122 public void setPreviewCallbackWithBuffer(Camera.PreviewCallback cb) { 123 previewCallback = cb; 124 } 125 126 /** 127 * Allows test cases to invoke the preview callback, to simulate a frame of camera data. 128 * 129 * @param data byte buffer of simulated camera data 130 */ 131 public void invokePreviewCallback(byte[] data) { 132 if (previewCallback != null) { 133 previewCallback.onPreviewFrame(data, realCamera); 134 } 135 } 136 137 @Implementation 138 public void addCallbackBuffer(byte[] callbackBuffer) { 139 callbackBuffers.add(callbackBuffer); 140 } 141 142 public List<byte[]> getAddedCallbackBuffers() { 143 return Collections.unmodifiableList(callbackBuffers); 144 } 145 146 @Implementation 147 public void setDisplayOrientation(int degrees) { 148 displayOrientation = degrees; 149 if (cameras.containsKey(id)) { 150 cameras.get(id).orientation = degrees; 151 } 152 } 153 154 public int getDisplayOrientation() { 155 return displayOrientation; 156 } 157 158 @Implementation 159 public void autoFocus(Camera.AutoFocusCallback callback) { 160 autoFocusCallback = callback; 161 autoFocusing = true; 162 } 163 164 @Implementation 165 public void cancelAutoFocus() { 166 autoFocusCallback = null; 167 autoFocusing = false; 168 } 169 170 public boolean hasRequestedAutoFocus() { 171 return autoFocusing; 172 } 173 174 public void invokeAutoFocusCallback(boolean success, Camera camera) { 175 if (autoFocusCallback == null) { 176 throw new IllegalStateException( 177 "cannot invoke AutoFocusCallback before autoFocus() has been called " 178 + "or after cancelAutoFocus() has been called " 179 + "or after the callback has been invoked."); 180 } 181 autoFocusCallback.onAutoFocus(success, camera); 182 autoFocusCallback = null; 183 autoFocusing = false; 184 } 185 186 @Implementation 187 public static void getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo ) { 188 Camera.CameraInfo foundCam = cameras.get( cameraId ); 189 cameraInfo.facing = foundCam.facing; 190 cameraInfo.orientation = foundCam.orientation; 191 } 192 193 @Implementation 194 public static int getNumberOfCameras() { 195 return cameras.size(); 196 } 197 198 public boolean isLocked() { 199 return locked; 200 } 201 202 public boolean isPreviewing() { 203 return previewing; 204 } 205 206 public boolean isReleased() { 207 return released; 208 } 209 210 public SurfaceHolder getPreviewDisplay() { 211 return surfaceHolder; 212 } 213 214 /** 215 * Add a mock {@code Camera.CameraInfo} object to simulate 216 * the existence of one or more cameras. By default, no 217 * cameras are defined. 218 * 219 * @param id The camera id 220 * @param camInfo The CameraInfo 221 */ 222 public static void addCameraInfo(int id, Camera.CameraInfo camInfo) { 223 cameras.put(id, camInfo); 224 } 225 226 public static void clearCameraInfo() { 227 cameras.clear(); 228 } 229 230 /** 231 * Shadows the Android {@code Camera.Parameters} class. 232 */ 233 @Implements(Camera.Parameters.class) 234 public static class ShadowParameters { 235 236 private int pictureWidth = 1280; 237 private int pictureHeight = 960; 238 private int previewWidth = 640; 239 private int previewHeight = 480; 240 private int previewFormat = ImageFormat.NV21; 241 private int previewFpsMin = 10; 242 private int previewFpsMax = 30; 243 private int previewFps = 30; 244 private int exposureCompensation = 0; 245 private String focusMode; 246 private List<String> supportedFocusModes = new ArrayList<>(); 247 248 @Implementation 249 public Camera.Size getPictureSize() { 250 Camera.Size pictureSize = newInstanceOf(Camera.class).new Size(0, 0); 251 pictureSize.width = pictureWidth; 252 pictureSize.height = pictureHeight; 253 return pictureSize; 254 } 255 256 @Implementation 257 public int getPreviewFormat() { 258 return previewFormat; 259 } 260 261 @Implementation 262 public void getPreviewFpsRange(int[] range) { 263 range[0] = previewFpsMin; 264 range[1] = previewFpsMax; 265 } 266 267 @Implementation 268 public int getPreviewFrameRate() { 269 return previewFps; 270 } 271 272 @Implementation 273 public Camera.Size getPreviewSize() { 274 Camera.Size previewSize = newInstanceOf(Camera.class).new Size(0, 0); 275 previewSize.width = previewWidth; 276 previewSize.height = previewHeight; 277 return previewSize; 278 } 279 280 @Implementation 281 public List<Camera.Size> getSupportedPictureSizes() { 282 List<Camera.Size> supportedSizes = new ArrayList<>(); 283 addSize(supportedSizes, 320, 240); 284 addSize(supportedSizes, 640, 480); 285 addSize(supportedSizes, 800, 600); 286 return supportedSizes; 287 } 288 289 @Implementation 290 public List<Integer> getSupportedPictureFormats() { 291 List<Integer> formats = new ArrayList<>(); 292 formats.add(ImageFormat.NV21); 293 formats.add(ImageFormat.JPEG); 294 return formats; 295 } 296 297 @Implementation 298 public List<Integer> getSupportedPreviewFormats() { 299 List<Integer> formats = new ArrayList<>(); 300 formats.add(ImageFormat.NV21); 301 formats.add(ImageFormat.JPEG); 302 return formats; 303 } 304 305 @Implementation 306 public List<int[]> getSupportedPreviewFpsRange() { 307 List<int[]> supportedRanges = new ArrayList<>(); 308 addRange(supportedRanges, 15000, 15000); 309 addRange(supportedRanges, 10000, 30000); 310 return supportedRanges; 311 } 312 313 @Implementation 314 public List<Integer> getSupportedPreviewFrameRates() { 315 List<Integer> supportedRates = new ArrayList<>(); 316 supportedRates.add(10); 317 supportedRates.add(15); 318 supportedRates.add(30); 319 return supportedRates; 320 } 321 322 @Implementation 323 public List<Camera.Size> getSupportedPreviewSizes() { 324 List<Camera.Size> supportedSizes = new ArrayList<>(); 325 addSize(supportedSizes, 320, 240); 326 addSize(supportedSizes, 640, 480); 327 return supportedSizes; 328 } 329 330 public void setSupportedFocusModes(String... focusModes) { 331 supportedFocusModes = Arrays.asList(focusModes); 332 } 333 334 @Implementation 335 public List<String> getSupportedFocusModes() { 336 return supportedFocusModes; 337 } 338 339 @Implementation 340 public String getFocusMode() { 341 return focusMode; 342 } 343 344 @Implementation 345 public void setFocusMode(String focusMode) { 346 this.focusMode = focusMode; 347 } 348 349 @Implementation 350 public void setPictureSize(int width, int height) { 351 pictureWidth = width; 352 pictureHeight = height; 353 } 354 355 @Implementation 356 public void setPreviewFormat(int pixel_format) { 357 previewFormat = pixel_format; 358 } 359 360 @Implementation 361 public void setPreviewFpsRange(int min, int max) { 362 previewFpsMin = min; 363 previewFpsMax = max; 364 } 365 366 @Implementation 367 public void setPreviewFrameRate(int fps) { 368 previewFps = fps; 369 } 370 371 @Implementation 372 public void setPreviewSize(int width, int height) { 373 previewWidth = width; 374 previewHeight = height; 375 } 376 377 @Implementation 378 public int getMinExposureCompensation() { 379 return -6; 380 } 381 382 @Implementation 383 public int getMaxExposureCompensation() { 384 return 6; 385 } 386 387 @Implementation 388 public float getExposureCompensationStep() { 389 return 0.5f; 390 } 391 392 @Implementation 393 public int getExposureCompensation() { 394 return exposureCompensation; 395 } 396 397 @Implementation 398 public void setExposureCompensation(int compensation) { 399 exposureCompensation = compensation; 400 } 401 402 public int getPreviewWidth() { 403 return previewWidth; 404 } 405 406 public int getPreviewHeight() { 407 return previewHeight; 408 } 409 410 public int getPictureWidth() { 411 return pictureWidth; 412 } 413 414 public int getPictureHeight() { 415 return pictureHeight; 416 } 417 418 private void addSize(List<Camera.Size> sizes, int width, int height) { 419 Camera.Size newSize = newInstanceOf(Camera.class).new Size(0, 0); 420 newSize.width = width; 421 newSize.height = height; 422 sizes.add(newSize); 423 } 424 425 private void addRange(List<int[]> ranges, int min, int max) { 426 int[] range = new int[2]; 427 range[0] = min; 428 range[1] = max; 429 ranges.add(range); 430 } 431 432 } 433 434 @Implements(Camera.Size.class) 435 public static class ShadowSize { 436 @RealObject private Camera.Size realCameraSize; 437 438 @Implementation 439 public void __constructor__(Camera camera, int width, int height) { 440 realCameraSize.width = width; 441 realCameraSize.height = height; 442 } 443 } 444 } 445