diff --git a/cameraview/src/androidTest/AndroidManifest.xml b/cameraview/src/androidTest/AndroidManifest.xml
index 90600623..36b84bf2 100644
--- a/cameraview/src/androidTest/AndroidManifest.xml
+++ b/cameraview/src/androidTest/AndroidManifest.xml
@@ -4,4 +4,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockPreview.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockPreview.java
index eb2b1b8c..a0afd571 100644
--- a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockPreview.java
+++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockPreview.java
@@ -2,28 +2,35 @@ package com.otaliastudios.cameraview;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
-public class MockPreview extends Preview {
+public class MockPreview extends Preview {
- public MockPreview(Context context, ViewGroup parent) {
+ MockPreview(Context context, ViewGroup parent) {
super(context, parent);
}
+ @NonNull
+ @Override
+ protected View onCreateView(Context context, ViewGroup parent) {
+ return new View(context);
+ }
+
@Override
Surface getSurface() {
return null;
}
@Override
- View getView() {
+ Class getOutputClass() {
return null;
}
@Override
- Class getOutputClass() {
+ Void getOutput() {
return null;
}
diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/PreviewTest.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/PreviewTest.java
new file mode 100644
index 00000000..ea515d20
--- /dev/null
+++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/PreviewTest.java
@@ -0,0 +1,137 @@
+package com.otaliastudios.cameraview;
+
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static org.junit.Assert.*;
+
+import static org.mockito.Mockito.*;
+
+public abstract class PreviewTest {
+
+ protected abstract Preview createPreview(Context context, ViewGroup parent);
+
+ private Preview preview;
+ private ViewGroup parent;
+ private Preview.SurfaceCallback callback;
+ private final Semaphore lock = new Semaphore(1, true);
+
+ @Rule
+ public ActivityTestRule rule = new ActivityTestRule<>(TestActivity.class);
+
+ @Before
+ public void setUp() {
+ Context context = rule.getActivity();
+ parent = new FrameLayout(context);
+ preview = createPreview(context, parent);
+ callback = mock(Preview.SurfaceCallback.class);
+ preview.setSurfaceCallback(callback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ rule.getActivity().setContentView(parent);
+ }
+ });
+ }
+
+ @Test
+ public void testDefaults() {
+ assertNotNull(preview.getView());
+ assertEquals(parent.getChildAt(0), preview.getView());
+ assertNotNull(preview.getOutputClass());
+ }
+
+ @Test
+ public void testDesiredSize() {
+ preview.setDesiredSize(160, 90);
+ assertEquals(160, preview.getDesiredSize().getWidth());
+ assertEquals(90, preview.getDesiredSize().getHeight());
+ }
+
+ @Test
+ public void testSurfaceSize() {
+ preview.onSurfaceAvailable(500, 1000);
+ assertEquals(500, preview.getSurfaceSize().getWidth());
+ assertEquals(1000, preview.getSurfaceSize().getHeight());
+
+ preview.onSurfaceSizeChanged(50, 100);
+ assertEquals(50, preview.getSurfaceSize().getWidth());
+ assertEquals(100, preview.getSurfaceSize().getHeight());
+
+ preview.onSurfaceDestroyed();
+ assertEquals(0, preview.getSurfaceSize().getWidth());
+ assertEquals(0, preview.getSurfaceSize().getHeight());
+ }
+
+ @Test
+ public void testCallbacks() {
+ preview.onSurfaceAvailable(500, 1000);
+ verify(callback, times(1)).onSurfaceAvailable();
+
+ preview.onSurfaceSizeChanged(50, 100);
+ verify(callback, times(1)).onSurfaceChanged();
+ }
+
+ @Test
+ public void testCropCenter() throws Exception {
+ preview.setCropListener(new Preview.CropListener() {
+ @Override
+ public void onPreCrop() {
+ try {
+ lock.acquire();
+ } catch (Exception e) {
+ e.printStackTrace();
+ };
+ }
+
+ @Override
+ public void onPostCrop() {
+ lock.release();
+ }
+ });
+
+ // If aspect ratio is different, there should be a crop.
+ Size s = new Size(1000, 1000);
+ preview.onSurfaceAvailable(s.getWidth(), s.getHeight());
+
+ // Not cropping.
+ preview.setDesiredSize(100, 100); // Wait...
+ lock.acquire();
+ assertEquals(AspectRatio.of(100, 100), getScaledAspectRatio());
+ assertFalse(preview.isCropping());
+ lock.release();
+
+ // Cropping.
+ preview.setDesiredSize(160, 50); // Wait...
+ lock.acquire();
+ assertEquals(AspectRatio.of(160, 50), getScaledAspectRatio());
+ assertTrue(preview.isCropping());
+ lock.release();
+
+ // Not cropping.
+ preview.onSurfaceSizeChanged(1600, 500); // Wait...
+ lock.acquire();
+ assertEquals(AspectRatio.of(160, 50), getScaledAspectRatio());
+ assertFalse(preview.isCropping());
+ lock.release();
+ }
+
+ private AspectRatio getScaledAspectRatio() {
+ Size size = preview.getSurfaceSize();
+ int newWidth = (int) ((float) size.getWidth() * preview.getView().getScaleX());
+ int newHeight = (int) ((float) size.getHeight() * preview.getView().getScaleY());
+ return AspectRatio.of(newWidth, newHeight);
+ }
+}
diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/SurfaceViewPreviewTest.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/SurfaceViewPreviewTest.java
new file mode 100644
index 00000000..4e47e9a2
--- /dev/null
+++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/SurfaceViewPreviewTest.java
@@ -0,0 +1,19 @@
+package com.otaliastudios.cameraview;
+
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
+
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SurfaceViewPreviewTest extends PreviewTest {
+
+ @Override
+ protected Preview createPreview(Context context, ViewGroup parent) {
+ return new SurfaceViewPreview(context, parent);
+ }
+}
diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/TestActivity.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/TestActivity.java
new file mode 100644
index 00000000..8108c7d3
--- /dev/null
+++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/TestActivity.java
@@ -0,0 +1,7 @@
+package com.otaliastudios.cameraview;
+
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+}
diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/TextureViewPreviewTest.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/TextureViewPreviewTest.java
new file mode 100644
index 00000000..a18143a4
--- /dev/null
+++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/TextureViewPreviewTest.java
@@ -0,0 +1,19 @@
+package com.otaliastudios.cameraview;
+
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
+
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TextureViewPreviewTest extends PreviewTest {
+
+ @Override
+ protected Preview createPreview(Context context, ViewGroup parent) {
+ return new TextureViewPreview(context, parent);
+ }
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
index 3f8c79d7..a039ada2 100644
--- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
@@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.location.Location;
@@ -110,12 +111,14 @@ class Camera1 extends CameraController {
// These can happen at different times but we want to end up here.
private void setup() {
try {
+ Object output = mPreview.getOutput();
if (mPreview.getOutputClass() == SurfaceHolder.class) {
- mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
+ mCamera.setPreviewDisplay((SurfaceHolder) output);
} else {
- mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
+ mCamera.setPreviewTexture((SurfaceTexture) output);
}
} catch (IOException e) {
+ LOG.e("Error while trying to setup Camera1.", e);
throw new RuntimeException(e);
}
@@ -450,8 +453,10 @@ class Camera1 extends CameraController {
@Override
boolean shouldFlipSizes() {
+ int offset = computeSensorToDisplayOffset();
LOG.i("shouldFlip:", "mDeviceOrientation=", mDeviceOrientation, "mSensorOffset=", mSensorOffset);
- return (mDeviceOrientation + mSensorOffset) % 180 != 0;
+ LOG.i("shouldFlip:", "sensorToDisplay=", offset);
+ return offset % 180 != 0;
}
@Override
diff --git a/cameraview/src/main/views/com/otaliastudios/cameraview/Preview.java b/cameraview/src/main/views/com/otaliastudios/cameraview/Preview.java
index 6e0c94bb..2cd9fdc0 100644
--- a/cameraview/src/main/views/com/otaliastudios/cameraview/Preview.java
+++ b/cameraview/src/main/views/com/otaliastudios/cameraview/Preview.java
@@ -1,15 +1,14 @@
package com.otaliastudios.cameraview;
import android.content.Context;
-import android.graphics.SurfaceTexture;
+import android.support.annotation.NonNull;
import android.view.Surface;
-import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
-abstract class Preview {
+abstract class Preview {
- private final static CameraLogger LOG = CameraLogger.create(Preview.class.getSimpleName());
+ protected final static CameraLogger LOG = CameraLogger.create(Preview.class.getSimpleName());
// This is used to notify CameraImpl to recompute its camera Preview size.
// After that, CameraView will need a new layout pass to adapt to the Preview size.
@@ -19,6 +18,7 @@ abstract class Preview {
}
private SurfaceCallback mSurfaceCallback;
+ private T mView;
// As far as I can see, these are the view/surface dimensions.
// This live in the 'View' orientation.
@@ -29,19 +29,25 @@ abstract class Preview {
private int mDesiredWidth;
private int mDesiredHeight;
- Preview(Context context, ViewGroup parent) {}
+ Preview(Context context, ViewGroup parent) {
+ mView = onCreateView(context, parent);
+ }
+
+ @NonNull
+ protected abstract T onCreateView(Context context, ViewGroup parent);
abstract Surface getSurface();
- abstract View getView();
- abstract Class getOutputClass();
- abstract boolean isReady();
- SurfaceHolder getSurfaceHolder() {
- return null;
- }
- SurfaceTexture getSurfaceTexture() {
- return null;
+
+ @NonNull
+ final T getView() {
+ return mView;
}
+ abstract Class