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