1package org.robolectric.shadows;
2
3import static java.nio.charset.StandardCharsets.UTF_8;
4import static org.assertj.core.api.Assertions.assertThat;
5import static org.assertj.core.api.Fail.fail;
6
7import android.graphics.Canvas;
8import android.graphics.ImageFormat;
9import android.graphics.Rect;
10import android.hardware.Camera;
11import android.view.Surface;
12import android.view.SurfaceHolder;
13import org.junit.After;
14import org.junit.Before;
15import org.junit.Test;
16import org.junit.runner.RunWith;
17import org.robolectric.RobolectricTestRunner;
18import org.robolectric.Shadows;
19
20@RunWith(RobolectricTestRunner.class)
21public class ShadowCameraTest {
22
23  private Camera camera;
24  private ShadowCamera shadowCamera;
25
26  @Before
27  public void setUp() throws Exception {
28    camera = Camera.open();
29    shadowCamera = Shadows.shadowOf(camera);
30  }
31
32  @After
33  public void tearDown() throws Exception {
34    ShadowCamera.clearCameraInfo();
35  }
36
37  @Test
38  public void testOpen() throws Exception {
39    assertThat(camera).isNotNull();
40    assertThat(ShadowCamera.getLastOpenedCameraId()).isEqualTo(0);
41  }
42
43  @Test
44  public void testOpenWithId() throws Exception {
45    camera = Camera.open(12);
46    assertThat(camera).isNotNull();
47    assertThat(ShadowCamera.getLastOpenedCameraId()).isEqualTo(12);
48  }
49
50  @Test
51  public void testUnlock() throws Exception {
52    assertThat(shadowCamera.isLocked()).isTrue();
53    camera.unlock();
54    assertThat(shadowCamera.isLocked()).isFalse();
55  }
56
57  @Test
58  public void testReconnect() throws Exception {
59    camera.unlock();
60    assertThat(shadowCamera.isLocked()).isFalse();
61    camera.reconnect();
62    assertThat(shadowCamera.isLocked()).isTrue();
63  }
64
65  @Test
66  public void testGetParameters() throws Exception {
67    Camera.Parameters parameters = camera.getParameters();
68    assertThat(parameters).isNotNull();
69    assertThat(parameters.getSupportedPreviewFormats()).isNotNull();
70    assertThat(parameters.getSupportedPreviewFormats().size()).isNotEqualTo(0);
71  }
72
73  @Test
74  public void testSetParameters() throws Exception {
75    Camera.Parameters parameters = camera.getParameters();
76    assertThat(parameters.getPreviewFormat()).isEqualTo(ImageFormat.NV21);
77    parameters.setPreviewFormat(ImageFormat.JPEG);
78    camera.setParameters(parameters);
79    assertThat(camera.getParameters().getPreviewFormat()).isEqualTo(ImageFormat.JPEG);
80  }
81
82  @Test
83  public void testSetPreviewDisplay() throws Exception {
84    SurfaceHolder previewSurfaceHolder = new TestSurfaceHolder();
85    camera.setPreviewDisplay(previewSurfaceHolder);
86    assertThat(shadowCamera.getPreviewDisplay()).isSameAs(previewSurfaceHolder);
87  }
88
89  @Test
90  public void testStartPreview() throws Exception {
91    assertThat(shadowCamera.isPreviewing()).isFalse();
92    camera.startPreview();
93    assertThat(shadowCamera.isPreviewing()).isTrue();
94  }
95
96  @Test
97  public void testStopPreview() throws Exception {
98    camera.startPreview();
99    assertThat(shadowCamera.isPreviewing()).isTrue();
100    camera.stopPreview();
101    assertThat(shadowCamera.isPreviewing()).isFalse();
102  }
103
104  @Test
105  public void testRelease() throws Exception {
106    assertThat(shadowCamera.isReleased()).isFalse();
107    camera.release();
108    assertThat(shadowCamera.isReleased()).isTrue();
109  }
110
111  @Test
112  public void testSetPreviewCallbacks() throws Exception {
113    TestPreviewCallback callback = new TestPreviewCallback();
114    assertThat(callback.camera).isNull();
115    assertThat(callback.data).isNull();
116
117    camera.setPreviewCallback(callback);
118    shadowCamera.invokePreviewCallback("foobar".getBytes(UTF_8));
119
120    assertThat(callback.camera).isSameAs(camera);
121    assertThat(callback.data).isEqualTo("foobar".getBytes(UTF_8));
122  }
123
124  @Test
125  public void testSetOneShotPreviewCallbacks() throws Exception {
126    TestPreviewCallback callback = new TestPreviewCallback();
127    assertThat(callback.camera).isNull();
128    assertThat(callback.data).isNull();
129
130    camera.setOneShotPreviewCallback(callback);
131    shadowCamera.invokePreviewCallback("foobar".getBytes(UTF_8));
132
133    assertThat(callback.camera).isSameAs(camera);
134    assertThat(callback.data).isEqualTo("foobar".getBytes(UTF_8));
135  }
136
137  @Test
138  public void testPreviewCallbacksWithBuffers() throws Exception {
139    TestPreviewCallback callback = new TestPreviewCallback();
140    assertThat(callback.camera).isNull();
141    assertThat(callback.data).isNull();
142
143    camera.setPreviewCallbackWithBuffer(callback);
144    shadowCamera.invokePreviewCallback("foobar".getBytes(UTF_8));
145
146    assertThat(callback.camera).isSameAs(camera);
147    assertThat(callback.data).isEqualTo("foobar".getBytes(UTF_8));
148  }
149
150  @Test
151  public void testClearPreviewCallback() throws Exception {
152    TestPreviewCallback callback = new TestPreviewCallback();
153    assertThat(callback.camera).isNull();
154    assertThat(callback.data).isNull();
155
156    camera.setPreviewCallback(callback);
157    camera.setPreviewCallback(null);
158
159    shadowCamera.invokePreviewCallback("foobar".getBytes(UTF_8));
160    assertThat(callback.camera).isNull();
161    assertThat(callback.data).isNull();
162
163    camera.setOneShotPreviewCallback(callback);
164    camera.setOneShotPreviewCallback(null);
165
166    shadowCamera.invokePreviewCallback("foobar".getBytes(UTF_8));
167    assertThat(callback.camera).isNull();
168    assertThat(callback.data).isNull();
169
170    camera.setPreviewCallbackWithBuffer(callback);
171    camera.setPreviewCallbackWithBuffer(null);
172
173    shadowCamera.invokePreviewCallback("foobar".getBytes(UTF_8));
174    assertThat(callback.camera).isNull();
175    assertThat(callback.data).isNull();
176  }
177
178  @Test
179  public void testAddCallbackBuffer() {
180    byte[] buf1 = new byte[0];
181    byte[] buf2 = new byte[1];
182    camera.addCallbackBuffer(buf1);
183    assertThat(shadowCamera.getAddedCallbackBuffers()).containsExactly(buf1);
184    camera.addCallbackBuffer(buf2);
185    assertThat(shadowCamera.getAddedCallbackBuffers()).containsExactly(buf1, buf2);
186  }
187
188  @Test
189  public void testDisplayOrientation() {
190    camera.setDisplayOrientation(180);
191    assertThat(shadowCamera.getDisplayOrientation()).isEqualTo(180);
192  }
193
194  @Test
195  public void testSetDisplayOrientationUpdatesCameraInfos() {
196    addBackCamera();
197    addFrontCamera();
198
199    camera = Camera.open(1);
200    camera.setDisplayOrientation(180);
201
202    Camera.CameraInfo cameraQuery = new Camera.CameraInfo();
203    Camera.getCameraInfo(ShadowCamera.getLastOpenedCameraId(), cameraQuery);
204    assertThat(cameraQuery.orientation).isEqualTo(180);
205  }
206
207  @Test
208  public void testAutoFocus() {
209    assertThat(shadowCamera.hasRequestedAutoFocus()).isFalse();
210    TestAutoFocusCallback callback = new TestAutoFocusCallback();
211
212    camera.autoFocus(callback);
213
214    assertThat(shadowCamera.hasRequestedAutoFocus()).isTrue();
215    shadowCamera.invokeAutoFocusCallback(true, camera);
216    assertThat(callback.success).isEqualTo(true);
217    assertThat(callback.camera).isEqualTo(camera);
218
219    assertThat(shadowCamera.hasRequestedAutoFocus()).isFalse();
220    try {
221      shadowCamera.invokeAutoFocusCallback(true, camera);
222      fail("expected an IllegalStateException");
223    } catch (IllegalStateException e) {
224      // expected
225    }
226  }
227
228  @Test
229  public void testInvokeAutoFocusCallbackMissing() {
230    try {
231      shadowCamera.invokeAutoFocusCallback(true, camera);
232      fail("expected an IllegalStateException");
233    } catch (IllegalStateException e) {
234      // expected
235    }
236  }
237
238  @Test
239  public void testCancelAutoFocus() {
240    assertThat(shadowCamera.hasRequestedAutoFocus()).isFalse();
241    camera.autoFocus(null);
242    assertThat(shadowCamera.hasRequestedAutoFocus()).isTrue();
243    camera.cancelAutoFocus();
244    assertThat(shadowCamera.hasRequestedAutoFocus()).isFalse();
245  }
246
247  @Test
248  public void testCameraInfoNoCameras() throws Exception {
249    assertThat(Camera.getNumberOfCameras()).isEqualTo(0);
250  }
251
252  @Test
253  public void testCameraInfoBackOnly() throws Exception {
254    Camera.CameraInfo cameraQuery = new Camera.CameraInfo();
255
256    addBackCamera();
257    Camera.getCameraInfo(0, cameraQuery);
258
259    assertThat(Camera.getNumberOfCameras()).isEqualTo(1);
260    assertThat(cameraQuery.facing).isEqualTo(Camera.CameraInfo.CAMERA_FACING_BACK);
261    assertThat(cameraQuery.orientation).isEqualTo(0);
262  }
263
264  @Test
265  public void testCameraInfoBackAndFront() throws Exception {
266    Camera.CameraInfo cameraQuery = new Camera.CameraInfo();
267    addBackCamera();
268    addFrontCamera();
269
270    assertThat(Camera.getNumberOfCameras()).isEqualTo(2);
271    Camera.getCameraInfo(0, cameraQuery);
272    assertThat(cameraQuery.facing).isEqualTo(Camera.CameraInfo.CAMERA_FACING_BACK);
273    assertThat(cameraQuery.orientation).isEqualTo(0);
274    Camera.getCameraInfo(1, cameraQuery);
275    assertThat(cameraQuery.facing).isEqualTo(Camera.CameraInfo.CAMERA_FACING_FRONT);
276    assertThat(cameraQuery.orientation).isEqualTo(90);
277  }
278
279  private void addBackCamera() {
280    Camera.CameraInfo backCamera = new Camera.CameraInfo();
281    backCamera.facing = Camera.CameraInfo.CAMERA_FACING_BACK;
282    backCamera.orientation = 0;
283    ShadowCamera.addCameraInfo(0, backCamera);
284  }
285
286  private void addFrontCamera() {
287    Camera.CameraInfo frontCamera = new Camera.CameraInfo();
288    frontCamera.facing = Camera.CameraInfo.CAMERA_FACING_FRONT;
289    frontCamera.orientation = 90;
290    ShadowCamera.addCameraInfo(1, frontCamera);
291  }
292
293  private static class TestPreviewCallback implements Camera.PreviewCallback {
294    public Camera camera = null;
295    public byte[] data = null;
296
297    @Override
298    public void onPreviewFrame(byte[] data, Camera camera) {
299      this.data = data;
300      this.camera = camera;
301    }
302  }
303
304  private static class TestAutoFocusCallback implements Camera.AutoFocusCallback {
305    public boolean success;
306    public Camera camera;
307
308    @Override
309    public void onAutoFocus(boolean success, Camera camera) {
310      this.success = success;
311      this.camera = camera;
312    }
313  }
314
315  private static class TestSurfaceHolder implements SurfaceHolder {
316
317    @Override
318    public void addCallback(Callback callback) {
319    }
320
321    @Override
322    public Surface getSurface() {
323      return null;
324    }
325
326    @Override
327    public Rect getSurfaceFrame() {
328      return null;
329    }
330
331    @Override
332    public boolean isCreating() {
333      return false;
334    }
335
336    @Override
337    public Canvas lockCanvas() {
338      return null;
339    }
340
341    @Override
342    public Canvas lockCanvas(Rect dirty) {
343      return null;
344    }
345
346    @Override
347    public void removeCallback(Callback callback) {
348    }
349
350    @Override
351    public void setFixedSize(int width, int height) {
352    }
353
354    @Override
355    public void setFormat(int format) {
356    }
357
358    @Override
359    public void setKeepScreenOn(boolean screenOn) {
360    }
361
362    @Override
363    public void setSizeFromLayout() {
364    }
365
366    @Override
367    public void setType(int type) {
368    }
369
370    @Override
371    public void unlockCanvasAndPost(Canvas canvas) {
372    }
373  }
374}
375