Add tests and changelog

pull/498/head
Mattia Iavarone 6 years ago
parent f4755eb1ce
commit 87f8f06282
  1. 9
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewCallbacksTest.java
  2. 186
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/CameraIntegrationTest.java
  3. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  4. 28
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  5. 9
      docs/_posts/2018-12-20-changelog.md

@ -155,6 +155,15 @@ public class CameraViewCallbacksTest extends BaseTest {
verify(listener, times(1)).onCameraClosed(); verify(listener, times(1)).onCameraClosed();
} }
@Test
public void testDispatchOnVideoRecordingStart() {
completeTask().when(listener).onVideoRecordingStart();
camera.mCameraCallbacks.dispatchOnVideoRecordingStart();
assertNotNull(op.await(500));
verify(listener, times(1)).onVideoRecordingStart();
}
@Test @Test
public void testDispatchOnVideoTaken() { public void testDispatchOnVideoTaken() {
VideoResult.Stub stub = new VideoResult.Stub(); VideoResult.Stub stub = new VideoResult.Stub();

@ -5,7 +5,6 @@ import android.graphics.Bitmap;
import android.graphics.PointF; import android.graphics.PointF;
import android.hardware.Camera; import android.hardware.Camera;
import android.os.Build; import android.os.Build;
import android.util.Log;
import com.otaliastudios.cameraview.BaseTest; import com.otaliastudios.cameraview.BaseTest;
import com.otaliastudios.cameraview.CameraException; import com.otaliastudios.cameraview.CameraException;
@ -13,7 +12,6 @@ import com.otaliastudios.cameraview.CameraListener;
import com.otaliastudios.cameraview.CameraOptions; import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.CameraUtils; import com.otaliastudios.cameraview.CameraUtils;
import com.otaliastudios.cameraview.CameraView; import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.DoNotRunOnTravis;
import com.otaliastudios.cameraview.PictureResult; import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.TestActivity; import com.otaliastudios.cameraview.TestActivity;
import com.otaliastudios.cameraview.VideoResult; import com.otaliastudios.cameraview.VideoResult;
@ -30,19 +28,14 @@ import com.otaliastudios.cameraview.internal.utils.WorkerHandler;
import com.otaliastudios.cameraview.size.Size; import com.otaliastudios.cameraview.size.Size;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.annotation.Nullable;
import androidx.test.filters.LargeTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.rule.ActivityTestRule; import androidx.test.rule.ActivityTestRule;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatcher;
import java.io.File; import java.io.File;
@ -130,7 +123,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
} }
} }
private CameraOptions waitForOpen(boolean expectSuccess) { private CameraOptions openSync(boolean expectSuccess) {
camera.open(); camera.open();
final Op<CameraOptions> open = new Op<>(true); final Op<CameraOptions> open = new Op<>(true);
doEndTask(open, 0).when(listener).onCameraOpened(any(CameraOptions.class)); doEndTask(open, 0).when(listener).onCameraOpened(any(CameraOptions.class));
@ -145,7 +138,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
return result; return result;
} }
private void waitForClose(boolean expectSuccess) { private void closeSync(boolean expectSuccess) {
camera.close(); camera.close();
final Op<Boolean> close = new Op<>(true); final Op<Boolean> close = new Op<>(true);
doEndTask(close, true).when(listener).onCameraClosed(); doEndTask(close, true).when(listener).onCameraClosed();
@ -157,25 +150,28 @@ public abstract class CameraIntegrationTest extends BaseTest {
} }
} }
private void waitForVideoEnd(boolean expectSuccess) { @SuppressWarnings("UnusedReturnValue")
final Op<Boolean> video = new Op<>(true); @Nullable
doEndTask(video, true).when(listener).onVideoTaken(any(VideoResult.class)); private VideoResult waitForVideoResult(boolean expectSuccess) {
doEndTask(video, false).when(listener).onCameraError(argThat(new ArgumentMatcher<CameraException>() { final Op<VideoResult> video = new Op<>(true);
doEndTask(video, 0).when(listener).onVideoTaken(any(VideoResult.class));
doEndTask(video, null).when(listener).onCameraError(argThat(new ArgumentMatcher<CameraException>() {
@Override @Override
public boolean matches(CameraException argument) { public boolean matches(CameraException argument) {
return argument.getReason() == CameraException.REASON_VIDEO_FAILED; return argument.getReason() == CameraException.REASON_VIDEO_FAILED;
} }
})); }));
Boolean result = video.await(DELAY); VideoResult result = video.await(DELAY);
if (expectSuccess) { if (expectSuccess) {
assertNotNull("Should end video", result); assertNotNull("Should end video", result);
assertTrue("Should end video without errors", result);
} else { } else {
assertNull("Should not end video", result); assertNull("Should not end video", result);
} }
return result;
} }
private PictureResult waitForPicture(boolean expectSuccess) { @Nullable
private PictureResult waitForPictureResult(boolean expectSuccess) {
final Op<PictureResult> pic = new Op<>(true); final Op<PictureResult> pic = new Op<>(true);
doEndTask(pic, 0).when(listener).onPictureTaken(any(PictureResult.class)); doEndTask(pic, 0).when(listener).onPictureTaken(any(PictureResult.class));
doEndTask(pic, null).when(listener).onCameraError(argThat(new ArgumentMatcher<CameraException>() { doEndTask(pic, null).when(listener).onCameraError(argThat(new ArgumentMatcher<CameraException>() {
@ -193,12 +189,60 @@ public abstract class CameraIntegrationTest extends BaseTest {
return result; return result;
} }
private void waitForVideoStart() { private void takeVideoSync(boolean expectSuccess) {
controller.mStartVideoOp.listen(); takeVideoSync(expectSuccess,0);
}
private void takeVideoSync(boolean expectSuccess, int duration) {
final Op<Boolean> op = new Op<>(true);
doEndTask(op, true).when(listener).onVideoRecordingStart();
doEndTask(op, false).when(listener).onCameraError(argThat(new ArgumentMatcher<CameraException>() {
@Override
public boolean matches(CameraException argument) {
return argument.getReason() == CameraException.REASON_VIDEO_FAILED;
}
}));
File file = new File(context().getFilesDir(), "video.mp4");
if (duration > 0) {
camera.takeVideo(file, duration);
} else {
camera.takeVideo(file);
}
Boolean result = op.await(DELAY);
if (expectSuccess) {
assertNotNull("should start video recording or get CameraError", result);
assertTrue("should start video recording successfully", result);
} else {
assertTrue("should not start video recording", result == null || !result);
}
}
private void takeVideoSnapshotSync(boolean expectSuccess) {
takeVideoSnapshotSync(expectSuccess,0);
}
private void takeVideoSnapshotSync(boolean expectSuccess, int duration) {
final Op<Boolean> op = new Op<>(true);
doEndTask(op, true).when(listener).onVideoRecordingStart();
doEndTask(op, false).when(listener).onCameraError(argThat(new ArgumentMatcher<CameraException>() {
@Override
public boolean matches(CameraException argument) {
return argument.getReason() == CameraException.REASON_VIDEO_FAILED;
}
}));
File file = new File(context().getFilesDir(), "video.mp4"); File file = new File(context().getFilesDir(), "video.mp4");
camera.takeVideo(file); if (duration > 0) {
controller.mStartVideoOp.await(DELAY); camera.takeVideoSnapshot(file, duration);
// TODO assert! } else {
camera.takeVideoSnapshot(file);
}
Boolean result = op.await(DELAY);
if (expectSuccess) {
assertNotNull("should start video recording or get CameraError", result);
assertTrue("should start video recording successfully", result);
} else {
assertTrue("should not start video recording", result == null || !result);
}
} }
//region test open/close //region test open/close
@ -208,22 +252,22 @@ public abstract class CameraIntegrationTest extends BaseTest {
// Starting and stopping are hard to get since they happen on another thread. // Starting and stopping are hard to get since they happen on another thread.
assertEquals(controller.getEngineState(), CameraEngine.STATE_STOPPED); assertEquals(controller.getEngineState(), CameraEngine.STATE_STOPPED);
waitForOpen(true); openSync(true);
assertEquals(controller.getEngineState(), CameraEngine.STATE_STARTED); assertEquals(controller.getEngineState(), CameraEngine.STATE_STARTED);
waitForClose(true); closeSync(true);
assertEquals(controller.getEngineState(), CameraEngine.STATE_STOPPED); assertEquals(controller.getEngineState(), CameraEngine.STATE_STOPPED);
} }
@Test @Test
public void testOpenTwice() { public void testOpenTwice() {
waitForOpen(true); openSync(true);
waitForOpen(false); openSync(false);
} }
@Test @Test
public void testCloseTwice() { public void testCloseTwice() {
waitForClose(false); closeSync(false);
} }
@Test @Test
@ -247,7 +291,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testStartInitializesOptions() { public void testStartInitializesOptions() {
assertNull(camera.getCameraOptions()); assertNull(camera.getCameraOptions());
waitForOpen(true); openSync(true);
assertNotNull(camera.getCameraOptions()); assertNotNull(camera.getCameraOptions());
} }
@ -258,7 +302,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetFacing() throws Exception { public void testSetFacing() throws Exception {
CameraOptions o = waitForOpen(true); CameraOptions o = openSync(true);
int size = o.getSupportedFacing().size(); int size = o.getSupportedFacing().size();
if (size > 1) { if (size > 1) {
// set facing should call stop and start again. // set facing should call stop and start again.
@ -276,7 +320,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetMode() throws Exception { public void testSetMode() throws Exception {
camera.setMode(Mode.PICTURE); camera.setMode(Mode.PICTURE);
waitForOpen(true); openSync(true);
// set session type should call stop and start again. // set session type should call stop and start again.
final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch latch = new CountDownLatch(2);
@ -297,7 +341,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetZoom() { public void testSetZoom() {
CameraOptions options = waitForOpen(true); CameraOptions options = openSync(true);
controller.mZoomOp.listen(); controller.mZoomOp.listen();
float oldValue = camera.getZoom(); float oldValue = camera.getZoom();
@ -314,7 +358,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetExposureCorrection() { public void testSetExposureCorrection() {
CameraOptions options = waitForOpen(true); CameraOptions options = openSync(true);
controller.mExposureCorrectionOp.listen(); controller.mExposureCorrectionOp.listen();
float oldValue = camera.getExposureCorrection(); float oldValue = camera.getExposureCorrection();
@ -331,7 +375,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetFlash() { public void testSetFlash() {
CameraOptions options = waitForOpen(true); CameraOptions options = openSync(true);
Flash[] values = Flash.values(); Flash[] values = Flash.values();
Flash oldValue = camera.getFlash(); Flash oldValue = camera.getFlash();
for (Flash value : values) { for (Flash value : values) {
@ -349,7 +393,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetWhiteBalance() { public void testSetWhiteBalance() {
CameraOptions options = waitForOpen(true); CameraOptions options = openSync(true);
WhiteBalance[] values = WhiteBalance.values(); WhiteBalance[] values = WhiteBalance.values();
WhiteBalance oldValue = camera.getWhiteBalance(); WhiteBalance oldValue = camera.getWhiteBalance();
for (WhiteBalance value : values) { for (WhiteBalance value : values) {
@ -367,7 +411,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetHdr() { public void testSetHdr() {
CameraOptions options = waitForOpen(true); CameraOptions options = openSync(true);
Hdr[] values = Hdr.values(); Hdr[] values = Hdr.values();
Hdr oldValue = camera.getHdr(); Hdr oldValue = camera.getHdr();
for (Hdr value : values) { for (Hdr value : values) {
@ -386,7 +430,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetAudio() { public void testSetAudio() {
// TODO: when permissions are managed, check that Audio.ON triggers the audio permission // TODO: when permissions are managed, check that Audio.ON triggers the audio permission
waitForOpen(true); openSync(true);
Audio[] values = Audio.values(); Audio[] values = Audio.values();
for (Audio value : values) { for (Audio value : values) {
camera.setAudio(value); camera.setAudio(value);
@ -396,7 +440,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testSetLocation() { public void testSetLocation() {
waitForOpen(true); openSync(true);
controller.mLocationOp.listen(); controller.mLocationOp.listen();
camera.setLocation(10d, 2d); camera.setLocation(10d, 2d);
controller.mLocationOp.await(300); controller.mLocationOp.await(300);
@ -440,8 +484,8 @@ public abstract class CameraIntegrationTest extends BaseTest {
// Error while starting MediaRecorder. java.lang.RuntimeException: start failed. // Error while starting MediaRecorder. java.lang.RuntimeException: start failed.
// as documented. This works locally though. // as documented. This works locally though.
camera.setMode(Mode.PICTURE); camera.setMode(Mode.PICTURE);
waitForOpen(true); openSync(true);
waitForVideoStart(); takeVideoSync(false);
waitForUiException(); waitForUiException();
} }
@ -451,35 +495,35 @@ public abstract class CameraIntegrationTest extends BaseTest {
// Error while starting MediaRecorder. java.lang.RuntimeException: start failed. // Error while starting MediaRecorder. java.lang.RuntimeException: start failed.
// as documented. This works locally though. // as documented. This works locally though.
camera.setMode(Mode.VIDEO); camera.setMode(Mode.VIDEO);
waitForOpen(true); openSync(true);
camera.takeVideo(new File(context().getFilesDir(), "video.mp4"), 4000); takeVideoSync(true, 4000);
waitForVideoEnd(true); waitForVideoResult(true);
} }
@Test @Test
public void testEndVideo_withoutStarting() { public void testEndVideo_withoutStarting() {
camera.setMode(Mode.VIDEO); camera.setMode(Mode.VIDEO);
waitForOpen(true); openSync(true);
camera.stopVideo(); camera.stopVideo();
waitForVideoEnd(false); waitForVideoResult(false);
} }
@Test @Test
public void testEndVideo_withMaxSize() { public void testEndVideo_withMaxSize() {
camera.setMode(Mode.VIDEO); camera.setMode(Mode.VIDEO);
camera.setVideoMaxSize(3000*1000); // Less is risky camera.setVideoMaxSize(3000*1000); // Less is risky
waitForOpen(true); openSync(true);
waitForVideoStart(); takeVideoSync(true);
waitForVideoEnd(true); waitForVideoResult(true);
} }
@Test @Test
public void testEndVideo_withMaxDuration() { public void testEndVideo_withMaxDuration() {
camera.setMode(Mode.VIDEO); camera.setMode(Mode.VIDEO);
camera.setVideoMaxDuration(4000); camera.setVideoMaxDuration(4000);
waitForOpen(true); openSync(true);
waitForVideoStart(); takeVideoSync(true);
waitForVideoEnd(true); waitForVideoResult(true);
} }
//endregion //endregion
@ -488,7 +532,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testStartAutoFocus() { public void testStartAutoFocus() {
CameraOptions o = waitForOpen(true); CameraOptions o = openSync(true);
final Op<PointF> focus = new Op<>(true); final Op<PointF> focus = new Op<>(true);
doEndTask(focus, 0).when(listener).onAutoFocusStart(any(PointF.class)); doEndTask(focus, 0).when(listener).onAutoFocusStart(any(PointF.class));
@ -505,7 +549,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testStopAutoFocus() { public void testStopAutoFocus() {
CameraOptions o = waitForOpen(true); CameraOptions o = openSync(true);
final Op<PointF> focus = new Op<>(true); final Op<PointF> focus = new Op<>(true);
doEndTask(focus, 1).when(listener).onAutoFocusEnd(anyBoolean(), any(PointF.class)); doEndTask(focus, 1).when(listener).onAutoFocusEnd(anyBoolean(), any(PointF.class));
@ -528,13 +572,13 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testCapturePicture_beforeStarted() { public void testCapturePicture_beforeStarted() {
camera.takePicture(); camera.takePicture();
waitForPicture(false); waitForPictureResult(false);
} }
@Test @Test
public void testCapturePicture_concurrentCalls() throws Exception { public void testCapturePicture_concurrentCalls() throws Exception {
// Second take should fail. // Second take should fail.
waitForOpen(true); openSync(true);
CountDownLatch latch = new CountDownLatch(2); CountDownLatch latch = new CountDownLatch(2);
doCountDown(latch).when(listener).onPictureTaken(any(PictureResult.class)); doCountDown(latch).when(listener).onPictureTaken(any(PictureResult.class));
@ -548,12 +592,12 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testCapturePicture_size() throws Exception { public void testCapturePicture_size() throws Exception {
waitForOpen(true); openSync(true);
// PictureSize can still be null after opened. // PictureSize can still be null after opened.
while (camera.getPictureSize() == null) {} while (camera.getPictureSize() == null) {}
Size size = camera.getPictureSize(); Size size = camera.getPictureSize();
camera.takePicture(); camera.takePicture();
PictureResult result = waitForPicture(true); PictureResult result = waitForPictureResult(true);
Bitmap bitmap = CameraUtils.decodeBitmap(result.getData(), Integer.MAX_VALUE, Integer.MAX_VALUE); Bitmap bitmap = CameraUtils.decodeBitmap(result.getData(), Integer.MAX_VALUE, Integer.MAX_VALUE);
assertEquals(result.getSize(), size); assertEquals(result.getSize(), size);
assertEquals(bitmap.getWidth(), size.getWidth()); assertEquals(bitmap.getWidth(), size.getWidth());
@ -566,7 +610,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test(expected = RuntimeException.class) @Test(expected = RuntimeException.class)
public void testCapturePicture_whileInVideoMode() throws Throwable { public void testCapturePicture_whileInVideoMode() throws Throwable {
camera.setMode(Mode.VIDEO); camera.setMode(Mode.VIDEO);
waitForOpen(true); openSync(true);
camera.takePicture(); camera.takePicture();
waitForUiException(); waitForUiException();
} }
@ -574,13 +618,13 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testCaptureSnapshot_beforeStarted() { public void testCaptureSnapshot_beforeStarted() {
camera.takePictureSnapshot(); camera.takePictureSnapshot();
waitForPicture(false); waitForPictureResult(false);
} }
@Test @Test
public void testCaptureSnapshot_concurrentCalls() throws Exception { public void testCaptureSnapshot_concurrentCalls() throws Exception {
// Second take should fail. // Second take should fail.
waitForOpen(true); openSync(true);
CountDownLatch latch = new CountDownLatch(2); CountDownLatch latch = new CountDownLatch(2);
doCountDown(latch).when(listener).onPictureTaken(any(PictureResult.class)); doCountDown(latch).when(listener).onPictureTaken(any(PictureResult.class));
@ -594,13 +638,13 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Test @Test
public void testCaptureSnapshot_size() throws Exception { public void testCaptureSnapshot_size() throws Exception {
waitForOpen(true); openSync(true);
// SnapshotSize can still be null after opened. // SnapshotSize can still be null after opened.
while (camera.getSnapshotSize() == null) {} while (camera.getSnapshotSize() == null) {}
Size size = camera.getSnapshotSize(); Size size = camera.getSnapshotSize();
camera.takePictureSnapshot(); camera.takePictureSnapshot();
PictureResult result = waitForPicture(true); PictureResult result = waitForPictureResult(true);
Bitmap bitmap = CameraUtils.decodeBitmap(result.getData(), Integer.MAX_VALUE, Integer.MAX_VALUE); Bitmap bitmap = CameraUtils.decodeBitmap(result.getData(), Integer.MAX_VALUE, Integer.MAX_VALUE);
assertEquals(result.getSize(), size); assertEquals(result.getSize(), size);
assertEquals(bitmap.getWidth(), size.getWidth()); assertEquals(bitmap.getWidth(), size.getWidth());
@ -626,7 +670,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
public void testFrameProcessing_simple() throws Exception { public void testFrameProcessing_simple() throws Exception {
FrameProcessor processor = mock(FrameProcessor.class); FrameProcessor processor = mock(FrameProcessor.class);
camera.addFrameProcessor(processor); camera.addFrameProcessor(processor);
waitForOpen(true); openSync(true);
assert30Frames(processor); assert30Frames(processor);
} }
@ -635,12 +679,12 @@ public abstract class CameraIntegrationTest extends BaseTest {
public void testFrameProcessing_afterSnapshot() throws Exception { public void testFrameProcessing_afterSnapshot() throws Exception {
FrameProcessor processor = mock(FrameProcessor.class); FrameProcessor processor = mock(FrameProcessor.class);
camera.addFrameProcessor(processor); camera.addFrameProcessor(processor);
waitForOpen(true); openSync(true);
// In Camera1, snapshots will clear the preview callback // In Camera1, snapshots will clear the preview callback
// Ensure we restore correctly // Ensure we restore correctly
camera.takePictureSnapshot(); camera.takePictureSnapshot();
waitForPicture(true); waitForPictureResult(true);
assert30Frames(processor); assert30Frames(processor);
} }
@ -649,9 +693,9 @@ public abstract class CameraIntegrationTest extends BaseTest {
public void testFrameProcessing_afterRestart() throws Exception { public void testFrameProcessing_afterRestart() throws Exception {
FrameProcessor processor = mock(FrameProcessor.class); FrameProcessor processor = mock(FrameProcessor.class);
camera.addFrameProcessor(processor); camera.addFrameProcessor(processor);
waitForOpen(true); openSync(true);
waitForClose(true); closeSync(true);
waitForOpen(true); openSync(true);
assert30Frames(processor); assert30Frames(processor);
} }
@ -662,9 +706,9 @@ public abstract class CameraIntegrationTest extends BaseTest {
FrameProcessor processor = mock(FrameProcessor.class); FrameProcessor processor = mock(FrameProcessor.class);
camera.addFrameProcessor(processor); camera.addFrameProcessor(processor);
camera.setMode(Mode.VIDEO); camera.setMode(Mode.VIDEO);
waitForOpen(true); openSync(true);
camera.takeVideo(new File(context().getFilesDir(), "video.mp4"), 4000); takeVideoSync(true,4000);
waitForVideoEnd(true); waitForVideoResult(true);
assert30Frames(processor); assert30Frames(processor);
} }
@ -676,7 +720,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
FrameProcessor source = new FreezeReleaseFrameProcessor(); FrameProcessor source = new FreezeReleaseFrameProcessor();
FrameProcessor processor = spy(source); FrameProcessor processor = spy(source);
camera.addFrameProcessor(processor); camera.addFrameProcessor(processor);
waitForOpen(true); openSync(true);
assert30Frames(processor); assert30Frames(processor);
} }

@ -2064,8 +2064,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
@Override @Override
public void onVideoRecordingStart() { public void dispatchOnVideoRecordingStart() {
mLogger.i("onVideoRecordingStart", "onVideoRecordingStart"); mLogger.i("dispatchOnVideoRecordingStart", "dispatchOnVideoRecordingStart");
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {

@ -134,7 +134,7 @@ public abstract class CameraEngine implements
void dispatchOnExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers); void dispatchOnExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers);
void dispatchFrame(Frame frame); void dispatchFrame(Frame frame);
void dispatchError(CameraException exception); void dispatchError(CameraException exception);
void onVideoRecordingStart(); void dispatchOnVideoRecordingStart();
} }
private static final String TAG = CameraEngine.class.getSimpleName(); private static final String TAG = CameraEngine.class.getSimpleName();
@ -199,7 +199,6 @@ public abstract class CameraEngine implements
private Step mAllStep = new Step("all", mStepCallback); private Step mAllStep = new Step("all", mStepCallback);
// Ops used for testing. // Ops used for testing.
@VisibleForTesting Op<Void> mStartVideoOp = new Op<>();
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) Op<Void> mZoomOp = new Op<>(); @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) Op<Void> mZoomOp = new Op<>();
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) Op<Void> mExposureCorrectionOp = new Op<>(); @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) Op<Void> mExposureCorrectionOp = new Op<>();
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) Op<Void> mFlashOp = new Op<>(); @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) Op<Void> mFlashOp = new Op<>();
@ -1121,8 +1120,8 @@ public abstract class CameraEngine implements
@Override @Override
public void run() { public void run() {
LOG.v("takeVideo", "performing. BindState:", getBindState(), "isTakingVideo:", isTakingVideo()); LOG.v("takeVideo", "performing. BindState:", getBindState(), "isTakingVideo:", isTakingVideo());
if (getBindState() < STATE_STARTED) { mStartVideoOp.end(null); return; } if (getBindState() < STATE_STARTED) return;
if (isTakingVideo()) { mStartVideoOp.end(null); return; } if (isTakingVideo()) return;
if (mMode == Mode.PICTURE) { if (mMode == Mode.PICTURE) {
throw new IllegalStateException("Can't record video while in PICTURE mode"); throw new IllegalStateException("Can't record video while in PICTURE mode");
} }
@ -1137,7 +1136,6 @@ public abstract class CameraEngine implements
stub.videoBitRate = mVideoBitRate; stub.videoBitRate = mVideoBitRate;
stub.audioBitRate = mAudioBitRate; stub.audioBitRate = mAudioBitRate;
onTakeVideo(stub); onTakeVideo(stub);
mStartVideoOp.end(null);
} }
}); });
} }
@ -1153,8 +1151,8 @@ public abstract class CameraEngine implements
@Override @Override
public void run() { public void run() {
LOG.v("takeVideoSnapshot", "performing. BindState:", getBindState(), "isTakingVideo:", isTakingVideo()); LOG.v("takeVideoSnapshot", "performing. BindState:", getBindState(), "isTakingVideo:", isTakingVideo());
if (getBindState() < STATE_STARTED) { mStartVideoOp.end(null); return; } if (getBindState() < STATE_STARTED) return;
if (isTakingVideo()) { mStartVideoOp.end(null); return; } if (isTakingVideo()) return;
stub.file = file; stub.file = file;
stub.isSnapshot = true; stub.isSnapshot = true;
stub.videoCodec = mVideoCodec; stub.videoCodec = mVideoCodec;
@ -1166,7 +1164,6 @@ public abstract class CameraEngine implements
stub.maxSize = mVideoMaxSize; stub.maxSize = mVideoMaxSize;
stub.maxDuration = mVideoMaxDuration; stub.maxDuration = mVideoMaxDuration;
onTakeVideoSnapshot(stub, viewAspectRatio); onTakeVideoSnapshot(stub, viewAspectRatio);
mStartVideoOp.end(null);
} }
}); });
} }
@ -1197,6 +1194,12 @@ public abstract class CameraEngine implements
} }
} }
@Override
public void onVideoRecordingStart() {
mCallback.dispatchOnVideoRecordingStart();
}
@WorkerThread @WorkerThread
protected abstract void onTakePicture(@NonNull PictureResult.Stub stub); protected abstract void onTakePicture(@NonNull PictureResult.Stub stub);
@ -1383,13 +1386,4 @@ public abstract class CameraEngine implements
} }
//endregion //endregion
//region callbacks
@Override
public void onVideoRecordingStart() {
mCallback.onVideoRecordingStart();
}
//endregion
} }

@ -8,9 +8,11 @@ order: 3
New versions are released through GitHub, so the reference page is the [GitHub Releases](https://github.com/natario1/CameraView/releases) page. New versions are released through GitHub, so the reference page is the [GitHub Releases](https://github.com/natario1/CameraView/releases) page.
### v2.0.0-*** (to be released) ### v2.0.0 (to be released)
- New: `cameraUseDeviceOrientation` XML attribute and `setUseDeviceOrientation()` method to disable considering the device orientation for outputs. ([#497][497]) - New: added `onVideoRecordingStart()` to be notified when video recording starts, thanks to [@agrawalsuneet][agrawalsuneet] ([#498][498])
- New: added `cameraUseDeviceOrientation` to choose whether picture and video outputs should consider the device orientation or not ([#497][497])
- Improvement: improved Camera2 stability and various bugs fixed (e.g. [#501][501])
### v2.0.0-beta06 ### v2.0.0-beta06
@ -55,6 +57,7 @@ If you were using `focusWithMarker`, you can [add back the old marker](../docs/m
This is the first beta release. For changes with respect to v1, please take a look at the [migration guide](../extra/v1-migration-guide.html). This is the first beta release. For changes with respect to v1, please take a look at the [migration guide](../extra/v1-migration-guide.html).
[cneuwirt]: https://github.com/cneuwirt [cneuwirt]: https://github.com/cneuwirt
[agrawalsuneet]: https://github.com/agrawalsuneet
[356]: https://github.com/natario1/CameraView/pull/356 [356]: https://github.com/natario1/CameraView/pull/356
[360]: https://github.com/natario1/CameraView/pull/360 [360]: https://github.com/natario1/CameraView/pull/360
@ -70,3 +73,5 @@ This is the first beta release. For changes with respect to v1, please take a lo
[484]: https://github.com/natario1/CameraView/pull/484 [484]: https://github.com/natario1/CameraView/pull/484
[490]: https://github.com/natario1/CameraView/pull/490 [490]: https://github.com/natario1/CameraView/pull/490
[497]: https://github.com/natario1/CameraView/pull/497 [497]: https://github.com/natario1/CameraView/pull/497
[498]: https://github.com/natario1/CameraView/pull/498
[501]: https://github.com/natario1/CameraView/pull/501

Loading…
Cancel
Save