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