New tests, add CameraController.STATE (#37)
* Add set/get parameters tests * CameraCallbacks tests * Nits * Nits 2 * Nits 3 * Nits 4 * CameraController integration tests * Fix some bugs * Add CameraController.STATE, fix CameraView.isStarted() * Fix old tests * Video and focus tests * Remove video test, fails on Travis * Add picture tests * Remove other video test * Add audio tests * new travis.yml * WorkerHandler changes * Better GridLinesLayoutTest * Try add logcat to travis build * Debug failing test * Add logs * Grant permissions, bump tests to N * Add wake locks * Add wake lock permission * Remove integration tests * Change view matcher * Refinementspull/43/head
parent
0a8e2f3de7
commit
cf3bfc1ed0
@ -0,0 +1,304 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.BitmapFactory; |
||||||
|
import android.graphics.Color; |
||||||
|
import android.graphics.PointF; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.graphics.YuvImage; |
||||||
|
import android.support.test.filters.MediumTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.mockito.invocation.InvocationOnMock; |
||||||
|
import org.mockito.stubbing.Answer; |
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.OutputStream; |
||||||
|
|
||||||
|
import static junit.framework.Assert.assertNotNull; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertFalse; |
||||||
|
import static org.junit.Assert.assertNull; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
import static org.mockito.Matchers.any; |
||||||
|
import static org.mockito.Matchers.anyFloat; |
||||||
|
import static org.mockito.Matchers.anyInt; |
||||||
|
import static org.mockito.Mockito.doAnswer; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
import static org.mockito.Mockito.never; |
||||||
|
import static org.mockito.Mockito.times; |
||||||
|
import static org.mockito.Mockito.verify; |
||||||
|
import static org.mockito.Mockito.when; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@MediumTest |
||||||
|
public class CameraCallbacksTest extends BaseTest { |
||||||
|
|
||||||
|
private CameraView camera; |
||||||
|
private CameraView.CameraCallbacks callbacks; |
||||||
|
private CameraListener listener; |
||||||
|
private MockCameraController mockController; |
||||||
|
private MockPreview mockPreview; |
||||||
|
private Task<Boolean> task; |
||||||
|
|
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
Context context = context(); |
||||||
|
listener = mock(CameraListener.class); |
||||||
|
camera = new CameraView(context) { |
||||||
|
@Override |
||||||
|
protected CameraController instantiateCameraController(CameraCallbacks callbacks, Preview preview) { |
||||||
|
mockController = new MockCameraController(callbacks, preview); |
||||||
|
return mockController; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Preview instantiatePreview(Context context, ViewGroup container) { |
||||||
|
mockPreview = new MockPreview(context, container); |
||||||
|
return mockPreview; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean checkPermissions(SessionType sessionType, Audio audio) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
camera.addCameraListener(listener); |
||||||
|
callbacks = camera.mCameraCallbacks; |
||||||
|
task = new Task<>(); |
||||||
|
task.listen(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void tearDown() { |
||||||
|
camera = null; |
||||||
|
mockController = null; |
||||||
|
mockPreview = null; |
||||||
|
callbacks = null; |
||||||
|
listener = null; |
||||||
|
} |
||||||
|
|
||||||
|
// Completes our task.
|
||||||
|
private Answer completeTask() { |
||||||
|
return new Answer() { |
||||||
|
@Override |
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable { |
||||||
|
task.end(true); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDontDispatchIfRemoved() { |
||||||
|
camera.removeCameraListener(listener); |
||||||
|
doAnswer(completeTask()).when(listener).onCameraOpened(null); |
||||||
|
callbacks.dispatchOnCameraOpened(null); |
||||||
|
|
||||||
|
assertNull(task.await(200)); |
||||||
|
verify(listener, never()).onCameraOpened(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDontDispatchIfCleared() { |
||||||
|
camera.clearCameraListeners(); |
||||||
|
doAnswer(completeTask()).when(listener).onCameraOpened(null); |
||||||
|
callbacks.dispatchOnCameraOpened(null); |
||||||
|
|
||||||
|
assertNull(task.await(200)); |
||||||
|
verify(listener, never()).onCameraOpened(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnCameraOpened() { |
||||||
|
doAnswer(completeTask()).when(listener).onCameraOpened(null); |
||||||
|
callbacks.dispatchOnCameraOpened(null); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onCameraOpened(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnCameraClosed() { |
||||||
|
doAnswer(completeTask()).when(listener).onCameraClosed(); |
||||||
|
callbacks.dispatchOnCameraClosed(); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onCameraClosed(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnVideoTaken() { |
||||||
|
doAnswer(completeTask()).when(listener).onVideoTaken(null); |
||||||
|
callbacks.dispatchOnVideoTaken(null); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onVideoTaken(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnZoomChanged() { |
||||||
|
doAnswer(completeTask()).when(listener).onZoomChanged(anyFloat(), any(float[].class), any(PointF[].class)); |
||||||
|
callbacks.dispatchOnZoomChanged(0f, null); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onZoomChanged(anyFloat(), any(float[].class), any(PointF[].class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnExposureCorrectionChanged() { |
||||||
|
doAnswer(completeTask()).when(listener).onExposureCorrectionChanged(0f, null, null); |
||||||
|
callbacks.dispatchOnExposureCorrectionChanged(0f, null, null); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onExposureCorrectionChanged(0f, null, null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnFocusStart() { |
||||||
|
// Enable tap gesture.
|
||||||
|
// Can't mock package protected. camera.mTapGestureLayout = mock(TapGestureLayout.class);
|
||||||
|
camera.mapGesture(Gesture.TAP, GestureAction.FOCUS_WITH_MARKER); |
||||||
|
|
||||||
|
PointF point = new PointF(); |
||||||
|
doAnswer(completeTask()).when(listener).onFocusStart(point); |
||||||
|
callbacks.dispatchOnFocusStart(Gesture.TAP, point); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onFocusStart(point); |
||||||
|
// Can't mock package protected. verify(camera.mTapGestureLayout, times(1)).onFocusStart(point);
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDispatchOnFocusEnd() { |
||||||
|
// Enable tap gesture.
|
||||||
|
// Can't mock package protected. camera.mTapGestureLayout = mock(TapGestureLayout.class);
|
||||||
|
camera.mapGesture(Gesture.TAP, GestureAction.FOCUS_WITH_MARKER); |
||||||
|
|
||||||
|
PointF point = new PointF(); |
||||||
|
boolean success = true; |
||||||
|
doAnswer(completeTask()).when(listener).onFocusEnd(success, point); |
||||||
|
callbacks.dispatchOnFocusEnd(Gesture.TAP, success, point); |
||||||
|
|
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onFocusEnd(success, point); |
||||||
|
// Can't mock package protected. verify(camera.mTapGestureLayout, times(1)).onFocusEnd(success);
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOrientationCallbacks_deviceOnly() { |
||||||
|
doAnswer(completeTask()).when(listener).onOrientationChanged(anyInt()); |
||||||
|
|
||||||
|
// Assert not called. Both methods must be called.
|
||||||
|
callbacks.onDeviceOrientationChanged(0); |
||||||
|
assertNull(task.await(200)); |
||||||
|
verify(listener, never()).onOrientationChanged(anyInt()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOrientationCallbacks_displayOnly() { |
||||||
|
doAnswer(completeTask()).when(listener).onOrientationChanged(anyInt()); |
||||||
|
|
||||||
|
// Assert not called. Both methods must be called.
|
||||||
|
callbacks.onDisplayOffsetChanged(0); |
||||||
|
assertNull(task.await(200)); |
||||||
|
verify(listener, never()).onOrientationChanged(anyInt()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOrientationCallbacks_both() { |
||||||
|
doAnswer(completeTask()).when(listener).onOrientationChanged(anyInt()); |
||||||
|
|
||||||
|
// Assert called.
|
||||||
|
callbacks.onDisplayOffsetChanged(0); |
||||||
|
callbacks.onDeviceOrientationChanged(90); |
||||||
|
assertNotNull(task.await(200)); |
||||||
|
verify(listener, times(1)).onOrientationChanged(anyInt()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void testProcessJpeg() { |
||||||
|
int[] viewDim = new int[]{ 200, 200 }; |
||||||
|
int[] imageDim = new int[]{ 1000, 1600 }; |
||||||
|
|
||||||
|
// With crop flag: expect a 1:1 ratio.
|
||||||
|
int[] output = testProcessImage(true, true, viewDim, imageDim); |
||||||
|
LOG.i("testProcessJpeg", output); |
||||||
|
assertEquals(output[0], 1000); |
||||||
|
assertEquals(output[1], 1000); |
||||||
|
|
||||||
|
// Without crop flag: expect original ratio.
|
||||||
|
output = testProcessImage(true, false, viewDim, imageDim); |
||||||
|
LOG.i("testProcessJpeg", output); |
||||||
|
assertEquals(output[0], imageDim[0]); |
||||||
|
assertEquals(output[1], imageDim[1]); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testProcessYuv() { |
||||||
|
int[] viewDim = new int[]{ 200, 200 }; |
||||||
|
int[] imageDim = new int[]{ 1000, 1600 }; |
||||||
|
|
||||||
|
// With crop flag: expect a 1:1 ratio.
|
||||||
|
int[] output = testProcessImage(false, true, viewDim, imageDim); |
||||||
|
LOG.i("testProcessYuv", output); |
||||||
|
assertEquals(output[0], 1000); |
||||||
|
assertEquals(output[1], 1000); |
||||||
|
|
||||||
|
// Without crop flag: expect original ratio.
|
||||||
|
output = testProcessImage(false, false, viewDim, imageDim); |
||||||
|
LOG.i("testProcessYuv", output); |
||||||
|
assertEquals(output[0], imageDim[0]); |
||||||
|
assertEquals(output[1], imageDim[1]); |
||||||
|
} |
||||||
|
|
||||||
|
private int[] testProcessImage(boolean jpeg, boolean crop, int[] viewDim, int[] imageDim) { |
||||||
|
// End our task when onPictureTaken is called. Take note of the result.
|
||||||
|
final Task<byte[]> jpegTask = new Task<>(); |
||||||
|
jpegTask.listen(); |
||||||
|
doAnswer(new Answer() { |
||||||
|
@Override |
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable { |
||||||
|
jpegTask.end((byte[]) invocation.getArguments()[0]); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}).when(listener).onPictureTaken(any(byte[].class)); |
||||||
|
|
||||||
|
// Fake our own dimensions.
|
||||||
|
camera.setTop(0); |
||||||
|
camera.setBottom(viewDim[1]); |
||||||
|
camera.setLeft(0); |
||||||
|
camera.setRight(viewDim[0]); |
||||||
|
|
||||||
|
// Ensure the image will (not) be cropped.
|
||||||
|
camera.setCropOutput(crop); |
||||||
|
mockPreview.setIsCropping(crop); |
||||||
|
|
||||||
|
// Create fake JPEG array and trigger the process.
|
||||||
|
if (jpeg) { |
||||||
|
callbacks.processImage(mockJpeg(imageDim[0], imageDim[1]), true, false); |
||||||
|
} else { |
||||||
|
callbacks.processSnapshot(mockYuv(imageDim[0], imageDim[1]), true, false); |
||||||
|
} |
||||||
|
|
||||||
|
// Wait for result and get out dimensions.
|
||||||
|
byte[] result = jpegTask.await(3000); |
||||||
|
assertNotNull("Image was processed", result); |
||||||
|
Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length); |
||||||
|
return new int[]{ bitmap.getWidth(), bitmap.getHeight() }; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,507 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.PointF; |
||||||
|
import android.support.test.filters.MediumTest; |
||||||
|
import android.support.test.rule.ActivityTestRule; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.BeforeClass; |
||||||
|
import org.junit.Ignore; |
||||||
|
import org.junit.Rule; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.util.concurrent.CountDownLatch; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* These tests work great on real devices, and are the only way to test actual CameraController |
||||||
|
* implementation - we really need to open the camera device. |
||||||
|
* Unfortunately they fail unreliably on emulated devices, due to some bug with the |
||||||
|
* emulated camera controller. Waiting for it to be fixed. |
||||||
|
*/ |
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@MediumTest |
||||||
|
@Ignore |
||||||
|
public class IntegrationTest extends BaseTest { |
||||||
|
|
||||||
|
@Rule |
||||||
|
public ActivityTestRule<TestActivity> rule = new ActivityTestRule<>(TestActivity.class); |
||||||
|
|
||||||
|
private CameraView camera; |
||||||
|
private Camera1 controller; |
||||||
|
private CameraListener listener; |
||||||
|
|
||||||
|
@BeforeClass |
||||||
|
public static void grant() { |
||||||
|
grantPermissions(); |
||||||
|
} |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
WorkerHandler.destroy(); |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
camera = new CameraView(rule.getActivity()) { |
||||||
|
@Override |
||||||
|
protected CameraController instantiateCameraController(CameraCallbacks callbacks, Preview preview) { |
||||||
|
controller = new Camera1(callbacks, preview); |
||||||
|
return controller; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
listener = mock(CameraListener.class); |
||||||
|
camera.addCameraListener(listener); |
||||||
|
rule.getActivity().inflate(camera); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void tearDown() throws Exception { |
||||||
|
camera.stopCapturingVideo(); |
||||||
|
camera.destroy(); |
||||||
|
WorkerHandler.destroy(); |
||||||
|
} |
||||||
|
|
||||||
|
private CameraOptions waitForOpen(boolean expectSuccess) { |
||||||
|
final Task<CameraOptions> open = new Task<>(); |
||||||
|
open.listen(); |
||||||
|
doEndTask(open, 0).when(listener).onCameraOpened(any(CameraOptions.class)); |
||||||
|
CameraOptions result = open.await(4000); |
||||||
|
if (expectSuccess) { |
||||||
|
assertNotNull("Can open", result); |
||||||
|
} else { |
||||||
|
assertNull("Should not open", result); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private Boolean waitForClose(boolean expectSuccess) { |
||||||
|
final Task<Boolean> close = new Task<>(); |
||||||
|
close.listen(); |
||||||
|
doEndTask(close, true).when(listener).onCameraClosed(); |
||||||
|
Boolean result = close.await(4000); |
||||||
|
if (expectSuccess) { |
||||||
|
assertNotNull("Can close", result); |
||||||
|
} else { |
||||||
|
assertNull("Should not close", result); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private Boolean waitForVideo(boolean expectSuccess) { |
||||||
|
final Task<Boolean> video = new Task<>(); |
||||||
|
video.listen(); |
||||||
|
doEndTask(video, true).when(listener).onVideoTaken(any(File.class)); |
||||||
|
Boolean result = video.await(2000); |
||||||
|
if (expectSuccess) { |
||||||
|
assertNotNull("Can take video", result); |
||||||
|
} else { |
||||||
|
assertNull("Should not take video", result); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private byte[] waitForPicture(boolean expectSuccess) { |
||||||
|
final Task<byte[]> pic = new Task<>(); |
||||||
|
pic.listen(); |
||||||
|
doEndTask(pic, 0).when(listener).onPictureTaken(any(byte[].class)); |
||||||
|
byte[] result = pic.await(5000); |
||||||
|
if (expectSuccess) { |
||||||
|
assertNotNull("Can take picture", result); |
||||||
|
} else { |
||||||
|
assertNull("Should not take picture", result); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
//region test open/close
|
||||||
|
|
||||||
|
//-@Test
|
||||||
|
public void testOpenClose() throws Exception { |
||||||
|
// Starting and stopping are hard to get since they happen on another thread.
|
||||||
|
assertEquals(controller.getState(), CameraController.STATE_STOPPED); |
||||||
|
|
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
assertEquals(controller.getState(), CameraController.STATE_STARTED); |
||||||
|
|
||||||
|
camera.stop(); |
||||||
|
waitForClose(true); |
||||||
|
assertEquals(controller.getState(), CameraController.STATE_STOPPED); |
||||||
|
} |
||||||
|
|
||||||
|
//-@Test
|
||||||
|
public void testOpenTwice() { |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(false); |
||||||
|
} |
||||||
|
|
||||||
|
//-@Test
|
||||||
|
public void testCloseTwice() { |
||||||
|
camera.stop(); |
||||||
|
waitForClose(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
// This works great on the device but crashes often on the emulator.
|
||||||
|
// There must be something wrong with the emulated camera...
|
||||||
|
// Like stopPreview() and release() are not really sync calls?
|
||||||
|
public void testConcurrentCalls() throws Exception { |
||||||
|
final CountDownLatch latch = new CountDownLatch(4); |
||||||
|
doCountDown(latch).when(listener).onCameraOpened(any(CameraOptions.class)); |
||||||
|
doCountDown(latch).when(listener).onCameraClosed(); |
||||||
|
|
||||||
|
camera.start(); |
||||||
|
camera.stop(); |
||||||
|
camera.start(); |
||||||
|
camera.stop(); |
||||||
|
|
||||||
|
boolean did = latch.await(10, TimeUnit.SECONDS); |
||||||
|
assertTrue("Handles concurrent calls to start & stop, " + latch.getCount(), did); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testStartInitializesOptions() { |
||||||
|
assertNull(camera.getCameraOptions()); |
||||||
|
assertNull(camera.getExtraProperties()); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
assertNotNull(camera.getCameraOptions()); |
||||||
|
assertNotNull(camera.getExtraProperties()); |
||||||
|
} |
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region test Facing/SessionType
|
||||||
|
// Test things that should reset the camera.
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetFacing() throws Exception { |
||||||
|
camera.start(); |
||||||
|
CameraOptions o = waitForOpen(true); |
||||||
|
int size = o.getSupportedFacing().size(); |
||||||
|
if (size > 1) { |
||||||
|
// set facing should call stop and start again.
|
||||||
|
final CountDownLatch latch = new CountDownLatch(2); |
||||||
|
doCountDown(latch).when(listener).onCameraOpened(any(CameraOptions.class)); |
||||||
|
doCountDown(latch).when(listener).onCameraClosed(); |
||||||
|
|
||||||
|
camera.toggleFacing(); |
||||||
|
|
||||||
|
boolean did = latch.await(2, TimeUnit.SECONDS); |
||||||
|
assertTrue("Handles setFacing while active", did); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetSessionType() throws Exception { |
||||||
|
camera.setSessionType(SessionType.PICTURE); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
|
||||||
|
// set session type should call stop and start again.
|
||||||
|
final CountDownLatch latch = new CountDownLatch(2); |
||||||
|
doCountDown(latch).when(listener).onCameraOpened(any(CameraOptions.class)); |
||||||
|
doCountDown(latch).when(listener).onCameraClosed(); |
||||||
|
|
||||||
|
camera.setSessionType(SessionType.VIDEO); |
||||||
|
|
||||||
|
boolean did = latch.await(2, TimeUnit.SECONDS); |
||||||
|
assertTrue("Handles setSessionType while active", did); |
||||||
|
assertEquals(camera.getSessionType(), SessionType.VIDEO); |
||||||
|
} |
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region test Set Parameters
|
||||||
|
// When camera is open, parameters will be set only if supported.
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetZoom() { |
||||||
|
camera.start(); |
||||||
|
CameraOptions options = waitForOpen(true); |
||||||
|
boolean can = options.isZoomSupported(); |
||||||
|
float oldValue = camera.getZoom(); |
||||||
|
float newValue = 0.65f; |
||||||
|
camera.setZoom(newValue); |
||||||
|
assertEquals(can ? newValue : oldValue, camera.getZoom(), 0f); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetExposureCorrection() { |
||||||
|
camera.start(); |
||||||
|
CameraOptions options = waitForOpen(true); |
||||||
|
boolean can = options.isExposureCorrectionSupported(); |
||||||
|
float oldValue = camera.getExposureCorrection(); |
||||||
|
float newValue = options.getExposureCorrectionMaxValue(); |
||||||
|
camera.setExposureCorrection(newValue); |
||||||
|
assertEquals(can ? newValue : oldValue, camera.getExposureCorrection(), 0f); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetFlash() { |
||||||
|
camera.start(); |
||||||
|
CameraOptions options = waitForOpen(true); |
||||||
|
Flash[] values = Flash.values(); |
||||||
|
Flash oldValue = camera.getFlash(); |
||||||
|
for (Flash value : values) { |
||||||
|
camera.setFlash(value); |
||||||
|
if (options.supports(value)) { |
||||||
|
assertEquals(camera.getFlash(), value); |
||||||
|
oldValue = value; |
||||||
|
} else { |
||||||
|
assertEquals(camera.getFlash(), oldValue); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetWhiteBalance() { |
||||||
|
camera.start(); |
||||||
|
CameraOptions options = waitForOpen(true); |
||||||
|
WhiteBalance[] values = WhiteBalance.values(); |
||||||
|
WhiteBalance oldValue = camera.getWhiteBalance(); |
||||||
|
for (WhiteBalance value : values) { |
||||||
|
camera.setWhiteBalance(value); |
||||||
|
if (options.supports(value)) { |
||||||
|
assertEquals(camera.getWhiteBalance(), value); |
||||||
|
oldValue = value; |
||||||
|
} else { |
||||||
|
assertEquals(camera.getWhiteBalance(), oldValue); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetHdr() { |
||||||
|
camera.start(); |
||||||
|
CameraOptions options = waitForOpen(true); |
||||||
|
Hdr[] values = Hdr.values(); |
||||||
|
Hdr oldValue = camera.getHdr(); |
||||||
|
for (Hdr value : values) { |
||||||
|
camera.setHdr(value); |
||||||
|
if (options.supports(value)) { |
||||||
|
assertEquals(camera.getHdr(), value); |
||||||
|
oldValue = value; |
||||||
|
} else { |
||||||
|
assertEquals(camera.getHdr(), oldValue); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetAudio() { |
||||||
|
// TODO: when permissions are managed, check that Audio.ON triggers the audio permission
|
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
Audio[] values = Audio.values(); |
||||||
|
for (Audio value : values) { |
||||||
|
camera.setAudio(value); |
||||||
|
assertEquals(camera.getAudio(), value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetLocation() { |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.setLocation(10d, 2d); |
||||||
|
assertNotNull(camera.getLocation()); |
||||||
|
assertEquals(camera.getLocation().getLatitude(), 10d, 0d); |
||||||
|
assertEquals(camera.getLocation().getLongitude(), 2d, 0d); |
||||||
|
// This also ensures there are no crashes when attaching it to camera parameters.
|
||||||
|
} |
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region testSetVideoQuality
|
||||||
|
// This can be tricky because can trigger layout changes.
|
||||||
|
|
||||||
|
// TODO: @Test(expected = IllegalStateException.class)
|
||||||
|
// Can't run on Travis, MediaRecorder not supported.
|
||||||
|
// Error while starting MediaRecorder. java.lang.RuntimeException: start failed.
|
||||||
|
public void testSetVideoQuality_whileRecording() { |
||||||
|
camera.setSessionType(SessionType.VIDEO); |
||||||
|
camera.setVideoQuality(VideoQuality.HIGHEST); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.startCapturingVideo(null); |
||||||
|
camera.setVideoQuality(VideoQuality.LOWEST); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetVideoQuality_whileInPictureSessionType() { |
||||||
|
camera.setSessionType(SessionType.PICTURE); |
||||||
|
camera.setVideoQuality(VideoQuality.HIGHEST); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.setVideoQuality(VideoQuality.LOWEST); |
||||||
|
assertEquals(camera.getVideoQuality(), VideoQuality.LOWEST); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetVideoQuality_whileNotStarted() { |
||||||
|
camera.setVideoQuality(VideoQuality.HIGHEST); |
||||||
|
assertEquals(camera.getVideoQuality(), VideoQuality.HIGHEST); |
||||||
|
camera.setVideoQuality(VideoQuality.LOWEST); |
||||||
|
assertEquals(camera.getVideoQuality(), VideoQuality.LOWEST); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetVideoQuality_shouldRecompute() { |
||||||
|
// If video quality changes bring to a new capture size,
|
||||||
|
// this might bring to a new aspect ratio,
|
||||||
|
// which might bring to a new preview size. No idea how to test.
|
||||||
|
assertTrue(true); |
||||||
|
} |
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region test startVideo
|
||||||
|
|
||||||
|
// TODO: @Test(expected = IllegalStateException.class)
|
||||||
|
// Fails on Travis. Some emulators can't deal with MediaRecorder
|
||||||
|
// Error while starting MediaRecorder. java.lang.RuntimeException: start failed.
|
||||||
|
// as documented. This works locally though.
|
||||||
|
public void testStartVideo_whileInPictureMode() { |
||||||
|
camera.setSessionType(SessionType.PICTURE); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.startCapturingVideo(null); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: @Test
|
||||||
|
// Fails on Travis. Some emulators can't deal with MediaRecorder,
|
||||||
|
// Error while starting MediaRecorder. java.lang.RuntimeException: start failed.
|
||||||
|
// as documented. This works locally though.
|
||||||
|
public void testStartEndVideo() { |
||||||
|
camera.setSessionType(SessionType.VIDEO); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.startCapturingVideo(null, 1000); |
||||||
|
waitForVideo(true); // waits 2000
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testEndVideo_withoutStarting() { |
||||||
|
camera.setSessionType(SessionType.VIDEO); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
camera.stopCapturingVideo(); |
||||||
|
waitForVideo(false); |
||||||
|
} |
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region startAutoFocus
|
||||||
|
// TODO: won't test onStopAutoFocus because that is not guaranteed to be called
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void testStartAutoFocus() { |
||||||
|
camera.start(); |
||||||
|
CameraOptions o = waitForOpen(true); |
||||||
|
camera.startAutoFocus(1, 1); |
||||||
|
if (o.isAutoFocusSupported()) { |
||||||
|
verify(listener, times(1)).onFocusStart(new PointF(1, 1)); |
||||||
|
} else { |
||||||
|
verify(listener, never()).onFocusStart(any(PointF.class)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region capture
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCapturePicture_beforeStarted() { |
||||||
|
camera.capturePicture(); |
||||||
|
waitForPicture(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCapturePicture_concurrentCalls() throws Exception { |
||||||
|
// Second take should fail.
|
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(2); |
||||||
|
doCountDown(latch).when(listener).onPictureTaken(any(byte[].class)); |
||||||
|
|
||||||
|
camera.capturePicture(); |
||||||
|
camera.capturePicture(); |
||||||
|
boolean did = latch.await(4, TimeUnit.SECONDS); |
||||||
|
assertFalse(did); |
||||||
|
assertEquals(latch.getCount(), 1); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCapturePicture_size() throws Exception { |
||||||
|
camera.setCropOutput(false); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
|
||||||
|
Size size = camera.getCaptureSize(); |
||||||
|
camera.capturePicture(); |
||||||
|
byte[] jpeg = waitForPicture(true); |
||||||
|
Bitmap b = CameraUtils.decodeBitmap(jpeg); |
||||||
|
// Result can actually have swapped dimensions
|
||||||
|
// Which one, depends on factors including device physical orientation
|
||||||
|
assertTrue(b.getWidth() == size.getHeight() || b.getWidth() == size.getWidth()); |
||||||
|
assertTrue(b.getHeight() == size.getHeight() || b.getHeight() == size.getWidth()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCaptureSnapshot_beforeStarted() { |
||||||
|
camera.captureSnapshot(); |
||||||
|
waitForPicture(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCaptureSnapshot_concurrentCalls() throws Exception { |
||||||
|
// Second take should fail.
|
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(2); |
||||||
|
doCountDown(latch).when(listener).onPictureTaken(any(byte[].class)); |
||||||
|
|
||||||
|
camera.captureSnapshot(); |
||||||
|
camera.captureSnapshot(); |
||||||
|
boolean did = latch.await(4, TimeUnit.SECONDS); |
||||||
|
assertFalse(did); |
||||||
|
assertEquals(latch.getCount(), 1); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCaptureSnapshot_size() throws Exception { |
||||||
|
camera.setCropOutput(false); |
||||||
|
camera.start(); |
||||||
|
waitForOpen(true); |
||||||
|
|
||||||
|
Size size = camera.getPreviewSize(); |
||||||
|
camera.captureSnapshot(); |
||||||
|
byte[] jpeg = waitForPicture(true); |
||||||
|
Bitmap b = CameraUtils.decodeBitmap(jpeg); |
||||||
|
// Result can actually have swapped dimensions
|
||||||
|
// Which one, depends on factors including device physical orientation
|
||||||
|
assertTrue(b.getWidth() == size.getHeight() || b.getWidth() == size.getWidth()); |
||||||
|
assertTrue(b.getHeight() == size.getHeight() || b.getHeight() == size.getWidth()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue