Refactor cameraview package

pull/482/head
Mattia Iavarone 6 years ago
parent ec5210cd08
commit 2264f3f5a6
  1. 3
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewCallbacksTest.java
  2. 3
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  3. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraException.java
  4. 46
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraListener.java
  5. 1
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraLogger.java
  6. 11
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java
  7. 20
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraUtils.java
  8. 82
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  9. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/FileCallback.java
  10. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/PictureResult.java
  11. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/VideoResult.java
  12. 37
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  13. 137
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  14. 60
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Mapper.java
  15. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/utils/OrientationHelper.java
  16. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/CameraPreview.java
  17. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java
  18. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/SurfaceCameraPreview.java
  19. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/TextureCameraPreview.java

@ -64,8 +64,9 @@ public class CameraViewCallbacksTest extends BaseTest {
return mockController; return mockController;
} }
@NonNull
@Override @Override
protected CameraPreview instantiatePreview(Context context, ViewGroup container) { protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
mockPreview = new MockCameraPreview(context, container); mockPreview = new MockCameraPreview(context, container);
return mockPreview; return mockPreview;
} }

@ -67,8 +67,9 @@ public class CameraViewTest extends BaseTest {
return mockController; return mockController;
} }
@NonNull
@Override @Override
protected CameraPreview instantiatePreview(Context context, ViewGroup container) { protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
mockPreview = spy(new MockCameraPreview(context, container)); mockPreview = spy(new MockCameraPreview(context, container));
return mockPreview; return mockPreview;
} }

@ -53,6 +53,7 @@ public class CameraException extends RuntimeException {
private int reason = REASON_UNKNOWN; private int reason = REASON_UNKNOWN;
@SuppressWarnings("WeakerAccess")
public CameraException(Throwable cause) { public CameraException(Throwable cause) {
super(cause); super(cause);
} }
@ -78,6 +79,7 @@ public class CameraException extends RuntimeException {
* *
* @return true if this error is unrecoverable * @return true if this error is unrecoverable
*/ */
@SuppressWarnings("unused")
public boolean isUnrecoverable() { public boolean isUnrecoverable() {
switch (getReason()) { switch (getReason()) {
case REASON_FAILED_TO_CONNECT: return true; case REASON_FAILED_TO_CONNECT: return true;

@ -5,6 +5,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
/**
* The base class for receiving updates from a {@link CameraView} instance.
* You can add and remove listeners using {@link CameraView#addCameraListener(CameraListener)}
* and {@link CameraView#removeCameraListener(CameraListener)}.
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class CameraListener { public abstract class CameraListener {
@ -15,18 +21,14 @@ public abstract class CameraListener {
* @param options camera supported options * @param options camera supported options
*/ */
@UiThread @UiThread
public void onCameraOpened(@NonNull CameraOptions options) { public void onCameraOpened(@NonNull CameraOptions options) { }
}
/** /**
* Notifies that the camera session was closed. * Notifies that the camera session was closed.
*/ */
@UiThread @UiThread
public void onCameraClosed() { public void onCameraClosed() { }
}
/** /**
@ -39,9 +41,7 @@ public abstract class CameraListener {
* @param exception the error * @param exception the error
*/ */
@UiThread @UiThread
public void onCameraError(@NonNull CameraException exception) { public void onCameraError(@NonNull CameraException exception) { }
}
/** /**
@ -54,9 +54,7 @@ public abstract class CameraListener {
* @param result captured picture * @param result captured picture
*/ */
@UiThread @UiThread
public void onPictureTaken(@NonNull PictureResult result) { public void onPictureTaken(@NonNull PictureResult result) { }
}
/** /**
@ -65,9 +63,7 @@ public abstract class CameraListener {
* @param result the video result * @param result the video result
*/ */
@UiThread @UiThread
public void onVideoTaken(@NonNull VideoResult result) { public void onVideoTaken(@NonNull VideoResult result) { }
}
/** /**
@ -81,9 +77,7 @@ public abstract class CameraListener {
* @param orientation either 0, 90, 180 or 270 * @param orientation either 0, 90, 180 or 270
*/ */
@UiThread @UiThread
public void onOrientationChanged(int orientation) { public void onOrientationChanged(int orientation) { }
}
/** /**
@ -94,9 +88,7 @@ public abstract class CameraListener {
* @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight() * @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight()
*/ */
@UiThread @UiThread
public void onFocusStart(@NonNull PointF point) { public void onFocusStart(@NonNull PointF point) { }
}
/** /**
@ -109,9 +101,7 @@ public abstract class CameraListener {
* @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight() * @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight()
*/ */
@UiThread @UiThread
public void onFocusEnd(boolean successful, @NonNull PointF point) { public void onFocusEnd(boolean successful, @NonNull PointF point) { }
}
/** /**
@ -123,9 +113,7 @@ public abstract class CameraListener {
* @param fingers finger positions that caused the event, null if not caused by touch * @param fingers finger positions that caused the event, null if not caused by touch
*/ */
@UiThread @UiThread
public void onZoomChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) { public void onZoomChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) { }
}
/** /**
@ -137,8 +125,6 @@ public abstract class CameraListener {
* @param fingers finger positions that caused the event, null if not caused by touch * @param fingers finger positions that caused the event, null if not caused by touch
*/ */
@UiThread @UiThread
public void onExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) { public void onExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) { }
}
} }

@ -15,6 +15,7 @@ import java.util.List;
/** /**
* Utility class that can log traces and info. * Utility class that can log traces and info.
*/ */
@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})
public final class CameraLogger { public final class CameraLogger {
public final static int LEVEL_VERBOSE = 0; public final static int LEVEL_VERBOSE = 0;

@ -1,16 +1,13 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.annotation.TargetApi;
import android.hardware.Camera; import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import com.otaliastudios.cameraview.controls.Audio; import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Control; import com.otaliastudios.cameraview.controls.Control;
import com.otaliastudios.cameraview.controls.Facing; import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash; import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.engine.Mapper; import com.otaliastudios.cameraview.engine.Mapper;
import com.otaliastudios.cameraview.engine.Mapper1;
import com.otaliastudios.cameraview.gesture.GestureAction; import com.otaliastudios.cameraview.gesture.GestureAction;
import com.otaliastudios.cameraview.controls.Grid; import com.otaliastudios.cameraview.controls.Grid;
import com.otaliastudios.cameraview.controls.Hdr; import com.otaliastudios.cameraview.controls.Hdr;
@ -54,7 +51,7 @@ public class CameraOptions {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public CameraOptions(@NonNull Camera.Parameters params, boolean flipSizes) { public CameraOptions(@NonNull Camera.Parameters params, boolean flipSizes) {
List<String> strings; List<String> strings;
Mapper mapper = new Mapper1(); Mapper mapper = Mapper.get();
// Facing // Facing
Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
@ -133,12 +130,6 @@ public class CameraOptions {
} }
} }
// Camera2 constructor.
@TargetApi(21)
CameraOptions(@NonNull CameraCharacteristics params) {}
/** /**
* Shorthand for getSupported*().contains(value). * Shorthand for getSupported*().contains(value).
* *

@ -1,5 +1,6 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -9,7 +10,7 @@ import android.hardware.Camera;
import android.os.Handler; import android.os.Handler;
import com.otaliastudios.cameraview.controls.Facing; import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.engine.Mapper1; import com.otaliastudios.cameraview.engine.Mapper;
import com.otaliastudios.cameraview.internal.utils.WorkerHandler; import com.otaliastudios.cameraview.internal.utils.WorkerHandler;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -28,6 +29,7 @@ import java.io.OutputStream;
/** /**
* Static utilities for dealing with camera I/O, orientations, etc. * Static utilities for dealing with camera I/O, orientations, etc.
*/ */
@SuppressWarnings("unused")
public class CameraUtils { public class CameraUtils {
@ -55,8 +57,9 @@ public class CameraUtils {
* @param facing either {@link Facing#BACK} or {@link Facing#FRONT} * @param facing either {@link Facing#BACK} or {@link Facing#FRONT}
* @return true if such sensor exists * @return true if such sensor exists
*/ */
public static boolean hasCameraFacing(@NonNull Context context, @NonNull Facing facing) { public static boolean hasCameraFacing(@SuppressWarnings("unused") @NonNull Context context,
int internal = new Mapper1().map(facing); @NonNull Facing facing) {
int internal = Mapper.get().map(facing);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) { for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo); Camera.getCameraInfo(i, cameraInfo);
@ -80,6 +83,7 @@ public class CameraUtils {
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@Nullable @Nullable
@WorkerThread @WorkerThread
@SuppressLint("NewApi")
public static File writeToFile(@NonNull final byte[] data, @NonNull File file) { public static File writeToFile(@NonNull final byte[] data, @NonNull File file) {
if (file.exists() && !file.delete()) return null; if (file.exists() && !file.delete()) return null;
try (OutputStream stream = new BufferedOutputStream(new FileOutputStream(file))) { try (OutputStream stream = new BufferedOutputStream(new FileOutputStream(file))) {
@ -213,6 +217,7 @@ public class CameraUtils {
* @param maxWidth the max allowed width * @param maxWidth the max allowed width
* @param maxHeight the max allowed height * @param maxHeight the max allowed height
*/ */
@SuppressWarnings("SameParameterValue")
static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight) { static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight) {
return decodeBitmap(source, maxWidth, maxHeight, new BitmapFactory.Options()); return decodeBitmap(source, maxWidth, maxHeight, new BitmapFactory.Options());
} }
@ -237,10 +242,11 @@ public class CameraUtils {
return decodeBitmap(source, maxWidth, maxHeight, options, -1); return decodeBitmap(source, maxWidth, maxHeight, options, -1);
} }
// Null: got OOM // Null means we got OOM
// TODO ignores flipping. but it should be super rare. // Ignores flipping, but it should be super rare.
@SuppressWarnings("TryFinallyCanBeTryWithResources")
@Nullable @Nullable
static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options, int rotation) { private static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options, int rotation) {
if (maxWidth <= 0) maxWidth = Integer.MAX_VALUE; if (maxWidth <= 0) maxWidth = Integer.MAX_VALUE;
if (maxHeight <= 0) maxHeight = Integer.MAX_VALUE; if (maxHeight <= 0) maxHeight = Integer.MAX_VALUE;
int orientation; int orientation;
@ -309,7 +315,7 @@ public class CameraUtils {
return bitmap; return bitmap;
} }
static int readExifOrientation(int exifOrientation) { private static int readExifOrientation(int exifOrientation) {
int orientation; int orientation;
switch (exifOrientation) { switch (exifOrientation) {
case ExifInterface.ORIENTATION_NORMAL: case ExifInterface.ORIENTATION_NORMAL:

@ -4,6 +4,8 @@ import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
@ -76,7 +78,10 @@ import static android.view.View.MeasureSpec.UNSPECIFIED;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
/**
* Entry point for the whole library.
* Please read documentation for usage and full set of features.
*/
public class CameraView extends FrameLayout implements LifecycleObserver { public class CameraView extends FrameLayout implements LifecycleObserver {
private final static String TAG = CameraView.class.getSimpleName(); private final static String TAG = CameraView.class.getSimpleName();
@ -93,13 +98,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
private Preview mPreview; private Preview mPreview;
// Components // Components
/* for tests */ CameraCallbacks mCameraCallbacks; @VisibleForTesting CameraCallbacks mCameraCallbacks;
private CameraPreview mCameraPreview; private CameraPreview mCameraPreview;
private OrientationHelper mOrientationHelper; private OrientationHelper mOrientationHelper;
private CameraEngine mCameraEngine; private CameraEngine mCameraEngine;
private MediaActionSound mSound; private MediaActionSound mSound;
/* for tests */ List<CameraListener> mListeners = new CopyOnWriteArrayList<>(); @VisibleForTesting List<CameraListener> mListeners = new CopyOnWriteArrayList<>();
/* for tests */ List<FrameProcessor> mFrameProcessors = new CopyOnWriteArrayList<>(); @VisibleForTesting List<FrameProcessor> mFrameProcessors = new CopyOnWriteArrayList<>();
private Lifecycle mLifecycle; private Lifecycle mLifecycle;
// Views // Views
@ -108,6 +113,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
TapGestureLayout mTapGestureLayout; TapGestureLayout mTapGestureLayout;
ScrollGestureLayout mScrollGestureLayout; ScrollGestureLayout mScrollGestureLayout;
private boolean mKeepScreenOn; private boolean mKeepScreenOn;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private boolean mExperimental; private boolean mExperimental;
// Threading // Threading
@ -138,15 +144,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mPreview = controls.getPreview(); mPreview = controls.getPreview();
// Camera controller params // Camera controller params
Facing facing = Facing.fromValue(a.getInteger(R.styleable.CameraView_cameraFacing, Facing.DEFAULT(context).value()));
Flash flash = Flash.fromValue(a.getInteger(R.styleable.CameraView_cameraFlash, Flash.DEFAULT.value()));
Grid grid = Grid.fromValue(a.getInteger(R.styleable.CameraView_cameraGrid, Grid.DEFAULT.value()));
int gridColor = a.getColor(R.styleable.CameraView_cameraGridColor, GridLinesLayout.DEFAULT_COLOR); int gridColor = a.getColor(R.styleable.CameraView_cameraGridColor, GridLinesLayout.DEFAULT_COLOR);
WhiteBalance whiteBalance = WhiteBalance.fromValue(a.getInteger(R.styleable.CameraView_cameraWhiteBalance, WhiteBalance.DEFAULT.value()));
Mode mode = Mode.fromValue(a.getInteger(R.styleable.CameraView_cameraMode, Mode.DEFAULT.value()));
Hdr hdr = Hdr.fromValue(a.getInteger(R.styleable.CameraView_cameraHdr, Hdr.DEFAULT.value()));
Audio audio = Audio.fromValue(a.getInteger(R.styleable.CameraView_cameraAudio, Audio.DEFAULT.value()));
VideoCodec codec = VideoCodec.fromValue(a.getInteger(R.styleable.CameraView_cameraVideoCodec, VideoCodec.DEFAULT.value()));
long videoMaxSize = (long) a.getFloat(R.styleable.CameraView_cameraVideoMaxSize, 0); long videoMaxSize = (long) a.getFloat(R.styleable.CameraView_cameraVideoMaxSize, 0);
int videoMaxDuration = a.getInteger(R.styleable.CameraView_cameraVideoMaxDuration, 0); int videoMaxDuration = a.getInteger(R.styleable.CameraView_cameraVideoMaxDuration, 0);
int videoBitRate = a.getInteger(R.styleable.CameraView_cameraVideoBitRate, 0); int videoBitRate = a.getInteger(R.styleable.CameraView_cameraVideoBitRate, 0);
@ -160,7 +158,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
a.recycle(); a.recycle();
// Components // Components
mCameraCallbacks = new Callbacks(); mCameraCallbacks = new CameraCallbacks();
mCameraEngine = instantiateCameraController(mCameraCallbacks); mCameraEngine = instantiateCameraController(mCameraCallbacks);
mUiHandler = new Handler(Looper.getMainLooper()); mUiHandler = new Handler(Looper.getMainLooper());
mFrameProcessorsHandler = WorkerHandler.get("FrameProcessorsWorker"); mFrameProcessorsHandler = WorkerHandler.get("FrameProcessorsWorker");
@ -208,11 +206,24 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
} }
protected CameraEngine instantiateCameraController(CameraCallbacks callbacks) { /**
return new Camera1Engine(callbacks); * Instantiates the camera engine.
* @param callback the engine callback
* @return the engine
*/
@NonNull
protected CameraEngine instantiateCameraController(@NonNull CameraEngine.Callback callback) {
return new Camera1Engine(callback);
} }
protected CameraPreview instantiatePreview(Context context, ViewGroup container) { /**
* Instantiates the camera preview.
* @param context a context
* @param container the container
* @return the preview
*/
@NonNull
protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
LOG.w("preview:", "isHardwareAccelerated:", isHardwareAccelerated()); LOG.w("preview:", "isHardwareAccelerated:", isHardwareAccelerated());
switch (mPreview) { switch (mPreview) {
case SURFACE: case SURFACE:
@ -230,7 +241,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
} }
/* for tests */ void instantiatePreview() { @VisibleForTesting
void instantiatePreview() {
mCameraPreview = instantiatePreview(getContext(), this); mCameraPreview = instantiatePreview(getContext(), this);
mCameraEngine.setPreview(mCameraPreview); mCameraEngine.setPreview(mCameraPreview);
} }
@ -471,6 +483,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
*/ */
@NonNull @NonNull
public GestureAction getGestureAction(@NonNull Gesture gesture) { public GestureAction getGestureAction(@NonNull Gesture gesture) {
//noinspection ConstantConditions
return mGestureMap.get(gesture); return mGestureMap.get(gesture);
} }
@ -481,12 +494,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
if (!isOpened()) return true; if (!isOpened()) return true;
// Pass to our own GestureLayouts // Pass to our own GestureLayouts
CameraOptions options = mCameraEngine.getCameraOptions(); // Non null CameraOptions options = mCameraEngine.getCameraOptions(); // Non null
if (options == null) throw new IllegalStateException("Options should not be null here.");
if (mPinchGestureLayout.onTouchEvent(event)) { if (mPinchGestureLayout.onTouchEvent(event)) {
LOG.i("onTouchEvent", "pinch!"); LOG.i("onTouchEvent", "pinch!");
onGesture(mPinchGestureLayout, options); onGesture(mPinchGestureLayout, options);
@ -509,10 +524,11 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
GestureAction action = mGestureMap.get(gesture); GestureAction action = mGestureMap.get(gesture);
PointF[] points = source.getPoints(); PointF[] points = source.getPoints();
float oldValue, newValue; float oldValue, newValue;
//noinspection ConstantConditions
switch (action) { switch (action) {
case CAPTURE: case CAPTURE:
mCameraEngine.takePicture(); takePicture();
break; break;
case FOCUS: case FOCUS:
@ -629,9 +645,9 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
return; return;
} }
} }
LOG.e("Permission error:", "When audio is enabled (Audio.ON),", String message = LOG.e("Permission error:", "When audio is enabled (Audio.ON),",
"the RECORD_AUDIO permission should be added to the app manifest file."); "the RECORD_AUDIO permission should be added to the app manifest file.");
throw new IllegalStateException(CameraLogger.lastMessage); throw new IllegalStateException(message);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
// Not possible. // Not possible.
} }
@ -1040,6 +1056,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* Returns the current delay in milliseconds to reset the focus after an autofocus process. * Returns the current delay in milliseconds to reset the focus after an autofocus process.
* @return the current autofocus reset delay in milliseconds. * @return the current autofocus reset delay in milliseconds.
*/ */
@SuppressWarnings("unused")
public long getAutoFocusResetDelay() { return mCameraEngine.getAutoFocusResetDelay(); } public long getAutoFocusResetDelay() { return mCameraEngine.getAutoFocusResetDelay(); }
@ -1141,6 +1158,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* Returns the current video bit rate. * Returns the current video bit rate.
* @return current bit rate * @return current bit rate
*/ */
@SuppressWarnings("unused")
public int getVideoBitRate() { public int getVideoBitRate() {
return mCameraEngine.getVideoBitRate(); return mCameraEngine.getVideoBitRate();
} }
@ -1159,6 +1177,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* Returns the current audio bit rate. * Returns the current audio bit rate.
* @return current bit rate * @return current bit rate
*/ */
@SuppressWarnings("unused")
public int getAudioBitRate() { public int getAudioBitRate() {
return mCameraEngine.getAudioBitRate(); return mCameraEngine.getAudioBitRate();
} }
@ -1422,6 +1441,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
// Get the preview size and crop according to the current view size. // Get the preview size and crop according to the current view size.
// It's better to do calculations in the REF_VIEW reference, and then flip if needed. // It's better to do calculations in the REF_VIEW reference, and then flip if needed.
Size preview = mCameraEngine.getUncroppedSnapshotSize(CameraEngine.REF_VIEW); Size preview = mCameraEngine.getUncroppedSnapshotSize(CameraEngine.REF_VIEW);
if (preview == null) return null; // Should never happen.
AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight()); AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight());
Rect crop = CropHelper.computeCrop(preview, viewRatio); Rect crop = CropHelper.computeCrop(preview, viewRatio);
Size cropSize = new Size(crop.width(), crop.height()); Size cropSize = new Size(crop.width(), crop.height());
@ -1479,7 +1499,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
if (requestCamera) permissions.add(Manifest.permission.CAMERA); if (requestCamera) permissions.add(Manifest.permission.CAMERA);
if (requestAudio) permissions.add(Manifest.permission.RECORD_AUDIO); if (requestAudio) permissions.add(Manifest.permission.RECORD_AUDIO);
if (activity != null) { if (activity != null) {
activity.requestPermissions(permissions.toArray(new String[permissions.size()]), activity.requestPermissions(permissions.toArray(new String[0]),
PERMISSION_REQUEST_CODE); PERMISSION_REQUEST_CODE);
} }
} }
@ -1614,12 +1634,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
//region Callbacks and dispatching //region Callbacks and dispatching
private class Callbacks implements CameraCallbacks { private class CameraCallbacks implements CameraEngine.Callback, OrientationHelper.Callback {
private CameraLogger mLogger = CameraLogger.create(CameraCallbacks.class.getSimpleName()); private CameraLogger mLogger = CameraLogger.create(CameraCallbacks.class.getSimpleName());
Callbacks() {}
@Override @Override
public void dispatchOnCameraOpened(final CameraOptions options) { public void dispatchOnCameraOpened(final CameraOptions options) {
mLogger.i("dispatchOnCameraOpened", options); mLogger.i("dispatchOnCameraOpened", options);
@ -1670,11 +1688,12 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
@Override @Override
public void dispatchOnPictureTaken(final PictureResult result) { public void dispatchOnPictureTaken(final PictureResult.Stub stub) {
mLogger.i("dispatchOnPictureTaken"); mLogger.i("dispatchOnPictureTaken", stub);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
PictureResult result = new PictureResult(stub);
for (CameraListener listener : mListeners) { for (CameraListener listener : mListeners) {
listener.onPictureTaken(result); listener.onPictureTaken(result);
} }
@ -1683,13 +1702,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
@Override @Override
public void dispatchOnVideoTaken(final VideoResult video) { public void dispatchOnVideoTaken(final VideoResult.Stub stub) {
mLogger.i("dispatchOnVideoTaken", video); mLogger.i("dispatchOnVideoTaken", stub);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
VideoResult result = new VideoResult(stub);
for (CameraListener listener : mListeners) { for (CameraListener listener : mListeners) {
listener.onVideoTaken(video); listener.onVideoTaken(result);
} }
} }
}); });
@ -1813,8 +1833,4 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
//endregion //endregion
//region deprecated APIs
//endregion
} }

@ -1,7 +1,5 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.graphics.Bitmap;
import java.io.File; import java.io.File;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;

@ -15,8 +15,12 @@ import androidx.annotation.Nullable;
* Wraps the picture captured by {@link CameraView#takePicture()} or * Wraps the picture captured by {@link CameraView#takePicture()} or
* {@link CameraView#takePictureSnapshot()}. * {@link CameraView#takePictureSnapshot()}.
*/ */
@SuppressWarnings("unused")
public class PictureResult { public class PictureResult {
/**
* A result stub, for internal use only.
*/
public static class Stub { public static class Stub {
Stub() {} Stub() {}

@ -15,8 +15,12 @@ import java.io.File;
/** /**
* Wraps the result of a video recording started by {@link CameraView#takeVideo(File)}. * Wraps the result of a video recording started by {@link CameraView#takeVideo(File)}.
*/ */
@SuppressWarnings("WeakerAccess")
public class VideoResult { public class VideoResult {
/**
* A result stub, for internal use only.
*/
public static class Stub { public static class Stub {
Stub() {} Stub() {}

@ -46,7 +46,7 @@ import java.util.List;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Camera.ErrorCallback, public class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Camera.ErrorCallback,
VideoRecorder.VideoResultListener, VideoRecorder.VideoResultListener,
PictureRecorder.PictureResultListener { PictureRecorder.PictureResultListener {
@ -71,7 +71,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
}; };
Camera1Engine(@NonNull Callback callback) { public Camera1Engine(@NonNull Callback callback) {
super(callback); super(callback);
mMapper = Mapper.get(); mMapper = Mapper.get();
} }
@ -376,7 +376,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setMode(@NonNull Mode mode) { public void setMode(@NonNull Mode mode) {
if (mode != mMode) { if (mode != mMode) {
mMode = mode; mMode = mode;
schedule(null, true, new Runnable() { schedule(null, true, new Runnable() {
@ -389,7 +389,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setLocation(@Nullable Location location) { public void setLocation(@Nullable Location location) {
final Location oldLocation = mLocation; final Location oldLocation = mLocation;
mLocation = location; mLocation = location;
schedule(mLocationTask, true, new Runnable() { schedule(mLocationTask, true, new Runnable() {
@ -414,7 +414,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setFacing(@NonNull Facing facing) { public void setFacing(@NonNull Facing facing) {
final Facing old = mFacing; final Facing old = mFacing;
if (facing != old) { if (facing != old) {
mFacing = facing; mFacing = facing;
@ -432,7 +432,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setWhiteBalance(@NonNull WhiteBalance whiteBalance) { public void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
final WhiteBalance old = mWhiteBalance; final WhiteBalance old = mWhiteBalance;
mWhiteBalance = whiteBalance; mWhiteBalance = whiteBalance;
schedule(mWhiteBalanceTask, true, new Runnable() { schedule(mWhiteBalanceTask, true, new Runnable() {
@ -454,7 +454,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setHdr(@NonNull Hdr hdr) { public void setHdr(@NonNull Hdr hdr) {
final Hdr old = mHdr; final Hdr old = mHdr;
mHdr = hdr; mHdr = hdr;
schedule(mHdrTask, true, new Runnable() { schedule(mHdrTask, true, new Runnable() {
@ -475,6 +475,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
return false; return false;
} }
@SuppressWarnings("UnusedReturnValue")
@TargetApi(17) @TargetApi(17)
private boolean applyPlaySounds(boolean oldPlaySound) { private boolean applyPlaySounds(boolean oldPlaySound) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
@ -498,7 +499,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
@Override @Override
void setAudio(@NonNull Audio audio) { public void setAudio(@NonNull Audio audio) {
if (mAudio != audio) { if (mAudio != audio) {
if (isTakingVideo()) { if (isTakingVideo()) {
LOG.w("Audio setting was changed while recording. " + LOG.w("Audio setting was changed while recording. " +
@ -509,7 +510,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setFlash(@NonNull Flash flash) { public void setFlash(@NonNull Flash flash) {
final Flash old = mFlash; final Flash old = mFlash;
mFlash = flash; mFlash = flash;
schedule(mFlashTask, true, new Runnable() { schedule(mFlashTask, true, new Runnable() {
@ -581,7 +582,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void takePicture(final @NonNull PictureResult.Stub stub) { public void takePicture(final @NonNull PictureResult.Stub stub) {
LOG.v("takePicture: scheduling"); LOG.v("takePicture: scheduling");
schedule(null, true, new Runnable() { schedule(null, true, new Runnable() {
@Override @Override
@ -610,7 +611,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
* @param viewAspectRatio the view aspect ratio * @param viewAspectRatio the view aspect ratio
*/ */
@Override @Override
void takePictureSnapshot(final @NonNull PictureResult.Stub stub, @NonNull final AspectRatio viewAspectRatio) { public void takePictureSnapshot(final @NonNull PictureResult.Stub stub, @NonNull final AspectRatio viewAspectRatio) {
LOG.v("takePictureSnapshot: scheduling"); LOG.v("takePictureSnapshot: scheduling");
schedule(null, true, new Runnable() { schedule(null, true, new Runnable() {
@Override @Override
@ -685,7 +686,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void takeVideo(final @NonNull VideoResult.Stub stub, @NonNull final File videoFile) { public void takeVideo(final @NonNull VideoResult.Stub stub, @NonNull final File videoFile) {
schedule(mStartVideoTask, true, new Runnable() { schedule(mStartVideoTask, true, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -731,7 +732,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Override @Override
void takeVideoSnapshot(final @NonNull VideoResult.Stub stub, @NonNull final File file, @NonNull final AspectRatio viewAspectRatio) { public void takeVideoSnapshot(final @NonNull VideoResult.Stub stub, @NonNull final File file, @NonNull final AspectRatio viewAspectRatio) {
if (!(mPreview instanceof GlCameraPreview)) { if (!(mPreview instanceof GlCameraPreview)) {
throw new IllegalStateException("Video snapshots are only supported with GlCameraPreview."); throw new IllegalStateException("Video snapshots are only supported with GlCameraPreview.");
} }
@ -815,7 +816,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void stopVideo() { public void stopVideo() {
schedule(null, false, new Runnable() { schedule(null, false, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -833,7 +834,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
@Override @Override
void setZoom(final float zoom, @Nullable final PointF[] points, final boolean notify) { public void setZoom(final float zoom, @Nullable final PointF[] points, final boolean notify) {
schedule(mZoomTask, true, new Runnable() { schedule(mZoomTask, true, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -853,7 +854,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setExposureCorrection(final float EVvalue, @NonNull final float[] bounds, public void setExposureCorrection(final float EVvalue, @NonNull final float[] bounds,
@Nullable final PointF[] points, final boolean notify) { @Nullable final PointF[] points, final boolean notify) {
schedule(mExposureCorrectionTask, true, new Runnable() { schedule(mExposureCorrectionTask, true, new Runnable() {
@Override @Override
@ -882,7 +883,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
@Override @Override
void startAutoFocus(@Nullable final Gesture gesture, @NonNull final PointF point) { public void startAutoFocus(@Nullable final Gesture gesture, @NonNull final PointF point) {
// Must get width and height from the UI thread. // Must get width and height from the UI thread.
int viewWidth = 0, viewHeight = 0; int viewWidth = 0, viewHeight = 0;
if (mPreview != null && mPreview.hasSurface()) { if (mPreview != null && mPreview.hasSurface()) {
@ -992,7 +993,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
} }
@Override @Override
void setPlaySounds(boolean playSounds) { public void setPlaySounds(boolean playSounds) {
final boolean old = mPlaySounds; final boolean old = mPlaySounds;
mPlaySounds = playSounds; mPlaySounds = playSounds;
schedule(mPlaySoundsTask, true, new Runnable() { schedule(mPlaySoundsTask, true, new Runnable() {

@ -52,8 +52,8 @@ public abstract class CameraEngine implements
void dispatchOnCameraClosed(); void dispatchOnCameraClosed();
void onCameraPreviewStreamSizeChanged(); void onCameraPreviewStreamSizeChanged();
void onShutter(boolean shouldPlaySound); void onShutter(boolean shouldPlaySound);
void dispatchOnVideoTaken(VideoResult.Stub result); void dispatchOnVideoTaken(VideoResult.Stub stub);
void dispatchOnPictureTaken(PictureResult.Stub result); void dispatchOnPictureTaken(PictureResult.Stub stub);
void dispatchOnFocusStart(@Nullable Gesture trigger, @NonNull PointF where); void dispatchOnFocusStart(@Nullable Gesture trigger, @NonNull PointF where);
void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, @NonNull PointF where); void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, @NonNull PointF where);
void dispatchOnZoomChanged(final float newValue, @Nullable final PointF[] fingers); void dispatchOnZoomChanged(final float newValue, @Nullable final PointF[] fingers);
@ -66,13 +66,13 @@ public abstract class CameraEngine implements
private static final CameraLogger LOG = CameraLogger.create(TAG); private static final CameraLogger LOG = CameraLogger.create(TAG);
static final int STATE_STOPPING = -1; // Camera is about to be stopped. static final int STATE_STOPPING = -1; // Camera is about to be stopped.
static final int STATE_STOPPED = 0; // Camera is stopped. public static final int STATE_STOPPED = 0; // Camera is stopped.
static final int STATE_STARTING = 1; // Camera is about to start. static final int STATE_STARTING = 1; // Camera is about to start.
static final int STATE_STARTED = 2; // Camera is available and we can set parameters. public static final int STATE_STARTED = 2; // Camera is available and we can set parameters.
static final int REF_SENSOR = 0; public static final int REF_SENSOR = 0;
static final int REF_VIEW = 1; public static final int REF_VIEW = 1;
static final int REF_OUTPUT = 2; public static final int REF_OUTPUT = 2;
protected final Callback mCallback; protected final Callback mCallback;
protected CameraPreview mPreview; protected CameraPreview mPreview;
@ -137,7 +137,7 @@ public abstract class CameraEngine implements
mFrameManager = new FrameManager(2, this); mFrameManager = new FrameManager(2, this);
} }
void setPreview(@NonNull CameraPreview cameraPreview) { public void setPreview(@NonNull CameraPreview cameraPreview) {
mPreview = cameraPreview; mPreview = cameraPreview;
mPreview.setSurfaceCallback(this); mPreview.setSurfaceCallback(this);
} }
@ -217,7 +217,7 @@ public abstract class CameraEngine implements
} }
// Starts the preview asynchronously. // Starts the preview asynchronously.
final void start() { public final void start() {
LOG.i("Start:", "posting runnable. State:", ss()); LOG.i("Start:", "posting runnable. State:", ss());
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
@ -307,7 +307,7 @@ public abstract class CameraEngine implements
abstract void onStop(); abstract void onStop();
// Returns current state. // Returns current state.
final int getState() { public final int getState() {
return mState; return mState;
} }
@ -316,198 +316,204 @@ public abstract class CameraEngine implements
//region Simple setters //region Simple setters
// This is called before start() and never again. // This is called before start() and never again.
final void setDisplayOffset(int displayOffset) { public final void setDisplayOffset(int displayOffset) {
mDisplayOffset = displayOffset; mDisplayOffset = displayOffset;
} }
// This can be called multiple times. // This can be called multiple times.
final void setDeviceOrientation(int deviceOrientation) { public final void setDeviceOrientation(int deviceOrientation) {
mDeviceOrientation = deviceOrientation; mDeviceOrientation = deviceOrientation;
} }
final void setPreviewStreamSizeSelector(@Nullable SizeSelector selector) { public final void setPreviewStreamSizeSelector(@Nullable SizeSelector selector) {
mPreviewStreamSizeSelector = selector; mPreviewStreamSizeSelector = selector;
} }
final void setPictureSizeSelector(@NonNull SizeSelector selector) { public final void setPictureSizeSelector(@NonNull SizeSelector selector) {
mPictureSizeSelector = selector; mPictureSizeSelector = selector;
} }
final void setVideoSizeSelector(@NonNull SizeSelector selector) { public final void setVideoSizeSelector(@NonNull SizeSelector selector) {
mVideoSizeSelector = selector; mVideoSizeSelector = selector;
} }
final void setVideoMaxSize(long videoMaxSizeBytes) { public final void setVideoMaxSize(long videoMaxSizeBytes) {
mVideoMaxSize = videoMaxSizeBytes; mVideoMaxSize = videoMaxSizeBytes;
} }
final void setVideoMaxDuration(int videoMaxDurationMillis) { public final void setVideoMaxDuration(int videoMaxDurationMillis) {
mVideoMaxDuration = videoMaxDurationMillis; mVideoMaxDuration = videoMaxDurationMillis;
} }
final void setVideoCodec(@NonNull VideoCodec codec) { public final void setVideoCodec(@NonNull VideoCodec codec) {
mVideoCodec = codec; mVideoCodec = codec;
} }
final void setVideoBitRate(int videoBitRate) { public final void setVideoBitRate(int videoBitRate) {
mVideoBitRate = videoBitRate; mVideoBitRate = videoBitRate;
} }
final void setAudioBitRate(int audioBitRate) { public final void setAudioBitRate(int audioBitRate) {
mAudioBitRate = audioBitRate; mAudioBitRate = audioBitRate;
} }
final void setSnapshotMaxWidth(int maxWidth) { public final void setSnapshotMaxWidth(int maxWidth) {
mSnapshotMaxWidth = maxWidth; mSnapshotMaxWidth = maxWidth;
} }
final void setSnapshotMaxHeight(int maxHeight) { public final void setSnapshotMaxHeight(int maxHeight) {
mSnapshotMaxHeight = maxHeight; mSnapshotMaxHeight = maxHeight;
} }
final void setAutoFocusResetDelay(long delayMillis) { mAutoFocusResetDelayMillis = delayMillis; } public final void setAutoFocusResetDelay(long delayMillis) { mAutoFocusResetDelayMillis = delayMillis; }
//endregion //endregion
//region Abstract setters and APIs //region Abstract setters and APIs
// Should restart the session if active. // Should restart the session if active.
abstract void setMode(@NonNull Mode mode); public abstract void setMode(@NonNull Mode mode);
// Should restart the session if active. // Should restart the session if active.
abstract void setFacing(@NonNull Facing facing); public abstract void setFacing(@NonNull Facing facing);
// If closed, no-op. If opened, check supported and apply. // If closed, no-op. If opened, check supported and apply.
abstract void setZoom(float zoom, @Nullable PointF[] points, boolean notify); public abstract void setZoom(float zoom, @Nullable PointF[] points, boolean notify);
// If closed, no-op. If opened, check supported and apply. // If closed, no-op. If opened, check supported and apply.
abstract void setExposureCorrection(float EVvalue, @NonNull float[] bounds, @Nullable PointF[] points, boolean notify); public abstract void setExposureCorrection(float EVvalue, @NonNull float[] bounds, @Nullable PointF[] points, boolean notify);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setFlash(@NonNull Flash flash); public abstract void setFlash(@NonNull Flash flash);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setWhiteBalance(@NonNull WhiteBalance whiteBalance); public abstract void setWhiteBalance(@NonNull WhiteBalance whiteBalance);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setHdr(@NonNull Hdr hdr); public abstract void setHdr(@NonNull Hdr hdr);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setLocation(@Nullable Location location); public abstract void setLocation(@Nullable Location location);
// Just set. // Just set.
abstract void setAudio(@NonNull Audio audio); public abstract void setAudio(@NonNull Audio audio);
abstract void takePicture(@NonNull PictureResult.Stub stub); public abstract void takePicture(@NonNull PictureResult.Stub stub);
abstract void takePictureSnapshot(@NonNull PictureResult.Stub stub, @NonNull AspectRatio viewAspectRatio); public abstract void takePictureSnapshot(@NonNull PictureResult.Stub stub, @NonNull AspectRatio viewAspectRatio);
abstract void takeVideo(@NonNull VideoResult.Stub stub, @NonNull File file); public abstract void takeVideo(@NonNull VideoResult.Stub stub, @NonNull File file);
abstract void takeVideoSnapshot(@NonNull VideoResult.Stub stub, @NonNull File file, @NonNull AspectRatio viewAspectRatio); public abstract void takeVideoSnapshot(@NonNull VideoResult.Stub stub, @NonNull File file, @NonNull AspectRatio viewAspectRatio);
abstract void stopVideo(); public abstract void stopVideo();
abstract void startAutoFocus(@Nullable Gesture gesture, @NonNull PointF point); public abstract void startAutoFocus(@Nullable Gesture gesture, @NonNull PointF point);
abstract void setPlaySounds(boolean playSounds); public abstract void setPlaySounds(boolean playSounds);
//endregion //endregion
//region final getters //region final getters
@Nullable @Nullable
final CameraOptions getCameraOptions() { public final CameraOptions getCameraOptions() {
return mCameraOptions; return mCameraOptions;
} }
@NonNull @NonNull
final Facing getFacing() { public final Facing getFacing() {
return mFacing; return mFacing;
} }
@NonNull @NonNull
final Flash getFlash() { public final Flash getFlash() {
return mFlash; return mFlash;
} }
@NonNull @NonNull
final WhiteBalance getWhiteBalance() { public final WhiteBalance getWhiteBalance() {
return mWhiteBalance; return mWhiteBalance;
} }
final VideoCodec getVideoCodec() { public final VideoCodec getVideoCodec() {
return mVideoCodec; return mVideoCodec;
} }
final int getVideoBitRate() { public final int getVideoBitRate() {
return mVideoBitRate; return mVideoBitRate;
} }
final long getVideoMaxSize() { public final long getVideoMaxSize() {
return mVideoMaxSize; return mVideoMaxSize;
} }
final int getVideoMaxDuration() { public final int getVideoMaxDuration() {
return mVideoMaxDuration; return mVideoMaxDuration;
} }
@NonNull @NonNull
final Mode getMode() { public final Mode getMode() {
return mMode; return mMode;
} }
@NonNull @NonNull
final Hdr getHdr() { public final Hdr getHdr() {
return mHdr; return mHdr;
} }
@Nullable @Nullable
final Location getLocation() { public final Location getLocation() {
return mLocation; return mLocation;
} }
@NonNull @NonNull
final Audio getAudio() { public final Audio getAudio() {
return mAudio; return mAudio;
} }
final int getAudioBitRate() { public final int getAudioBitRate() {
return mAudioBitRate; return mAudioBitRate;
} }
@SuppressWarnings("unused")
@Nullable @Nullable
/* for tests */ final SizeSelector getPreviewStreamSizeSelector() { @VisibleForTesting
final SizeSelector getPreviewStreamSizeSelector() {
return mPreviewStreamSizeSelector; return mPreviewStreamSizeSelector;
} }
@SuppressWarnings("unused")
@NonNull @NonNull
/* for tests */ final SizeSelector getPictureSizeSelector() { @VisibleForTesting
final SizeSelector getPictureSizeSelector() {
return mPictureSizeSelector; return mPictureSizeSelector;
} }
@SuppressWarnings("unused")
@NonNull @NonNull
/* for tests */ final SizeSelector getVideoSizeSelector() { @VisibleForTesting
final SizeSelector getVideoSizeSelector() {
return mVideoSizeSelector; return mVideoSizeSelector;
} }
final float getZoomValue() { public final float getZoomValue() {
return mZoomValue; return mZoomValue;
} }
final float getExposureCorrectionValue() { public final float getExposureCorrectionValue() {
return mExposureCorrectionValue; return mExposureCorrectionValue;
} }
final boolean isTakingVideo() { public final boolean isTakingVideo() {
return mVideoRecorder != null; return mVideoRecorder != null;
} }
final boolean isTakingPicture() { public final boolean isTakingPicture() {
return mPictureRecorder != null; return mPictureRecorder != null;
} }
final long getAutoFocusResetDelay() { return mAutoFocusResetDelayMillis; } public final long getAutoFocusResetDelay() { return mAutoFocusResetDelayMillis; }
final boolean shouldResetAutoFocus() { final boolean shouldResetAutoFocus() {
return mAutoFocusResetDelayMillis > 0 && mAutoFocusResetDelayMillis != Long.MAX_VALUE; return mAutoFocusResetDelayMillis > 0 && mAutoFocusResetDelayMillis != Long.MAX_VALUE;
@ -551,24 +557,24 @@ public abstract class CameraEngine implements
return (offset(REF_SENSOR, toReference) - offset(REF_SENSOR, fromReference) + 360) % 360; return (offset(REF_SENSOR, toReference) - offset(REF_SENSOR, fromReference) + 360) % 360;
} }
final boolean flip(int reference1, int reference2) { public final boolean flip(int reference1, int reference2) {
return offset(reference1, reference2) % 180 != 0; return offset(reference1, reference2) % 180 != 0;
} }
@Nullable @Nullable
final Size getPictureSize(@SuppressWarnings("SameParameterValue") int reference) { public final Size getPictureSize(@SuppressWarnings("SameParameterValue") int reference) {
if (mCaptureSize == null || mMode == Mode.VIDEO) return null; if (mCaptureSize == null || mMode == Mode.VIDEO) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize; return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
} }
@Nullable @Nullable
final Size getVideoSize(@SuppressWarnings("SameParameterValue") int reference) { public final Size getVideoSize(@SuppressWarnings("SameParameterValue") int reference) {
if (mCaptureSize == null || mMode == Mode.PICTURE) return null; if (mCaptureSize == null || mMode == Mode.PICTURE) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize; return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
} }
@Nullable @Nullable
final Size getPreviewStreamSize(int reference) { public final Size getPreviewStreamSize(int reference) {
if (mPreviewStreamSize == null) return null; if (mPreviewStreamSize == null) return null;
return flip(REF_SENSOR, reference) ? mPreviewStreamSize.flip() : mPreviewStreamSize; return flip(REF_SENSOR, reference) ? mPreviewStreamSize.flip() : mPreviewStreamSize;
} }
@ -601,7 +607,7 @@ public abstract class CameraEngine implements
* apply, despite the capturing mechanism being different. * apply, despite the capturing mechanism being different.
*/ */
@Nullable @Nullable
final Size getUncroppedSnapshotSize(int reference) { public final Size getUncroppedSnapshotSize(int reference) {
Size baseSize = getPreviewStreamSize(reference); Size baseSize = getPreviewStreamSize(reference);
if (baseSize == null) return null; if (baseSize == null) return null;
boolean flip = flip(reference, REF_VIEW); boolean flip = flip(reference, REF_VIEW);
@ -679,6 +685,7 @@ public abstract class CameraEngine implements
// Create our own default selector, which will be used if the external mPreviewStreamSizeSelector // Create our own default selector, which will be used if the external mPreviewStreamSizeSelector
// is null, or if it fails in finding a size. // is null, or if it fails in finding a size.
Size targetMinSize = getPreviewSurfaceSize(REF_VIEW); Size targetMinSize = getPreviewSurfaceSize(REF_VIEW);
if (targetMinSize == null) throw new IllegalStateException("targetMinSize should not be null here.");
AspectRatio targetRatio = AspectRatio.of(mCaptureSize.getWidth(), mCaptureSize.getHeight()); AspectRatio targetRatio = AspectRatio.of(mCaptureSize.getWidth(), mCaptureSize.getHeight());
if (flip) targetRatio = targetRatio.flip(); if (flip) targetRatio = targetRatio.flip();
LOG.i("size:", "computePreviewStreamSize:", "targetRatio:", targetRatio, "targetMinSize:", targetMinSize); LOG.i("size:", "computePreviewStreamSize:", "targetRatio:", targetRatio, "targetMinSize:", targetMinSize);

@ -17,18 +17,35 @@ public abstract class Mapper {
private Mapper() {} private Mapper() {}
abstract <T> T map(Flash flash); public abstract <T> T map(Flash flash);
abstract <T> T map(Facing facing);
abstract <T> T map(WhiteBalance whiteBalance); public abstract <T> T map(Facing facing);
abstract <T> T map(Hdr hdr);
abstract <T> Flash unmapFlash(T cameraConstant); public abstract <T> T map(WhiteBalance whiteBalance);
abstract <T> Facing unmapFacing(T cameraConstant);
abstract <T> WhiteBalance unmapWhiteBalance(T cameraConstant); public abstract <T> T map(Hdr hdr);
abstract <T> Hdr unmapHdr(T cameraConstant);
public abstract <T> Flash unmapFlash(T cameraConstant);
public abstract <T> Facing unmapFacing(T cameraConstant);
public abstract <T> WhiteBalance unmapWhiteBalance(T cameraConstant);
public abstract <T> Hdr unmapHdr(T cameraConstant);
@SuppressWarnings("WeakerAccess")
protected <T> T reverseLookup(HashMap<T, ?> map, Object object) {
for (T value : map.keySet()) {
if (object.equals(map.get(value))) {
return value;
}
}
return null;
}
private static Mapper CAMERA1; private static Mapper CAMERA1;
static Mapper get() { public static Mapper get() {
if (CAMERA1 == null) { if (CAMERA1 == null) {
CAMERA1 = new Camera1Mapper(); CAMERA1 = new Camera1Mapper();
} }
@ -64,51 +81,42 @@ public abstract class Mapper {
} }
@Override @Override
<T> T map(Flash flash) { public <T> T map(Flash flash) {
return (T) FLASH.get(flash); return (T) FLASH.get(flash);
} }
@Override @Override
<T> T map(Facing facing) { public <T> T map(Facing facing) {
return (T) FACING.get(facing); return (T) FACING.get(facing);
} }
@Override @Override
<T> T map(WhiteBalance whiteBalance) { public <T> T map(WhiteBalance whiteBalance) {
return (T) WB.get(whiteBalance); return (T) WB.get(whiteBalance);
} }
@Override @Override
<T> T map(Hdr hdr) { public <T> T map(Hdr hdr) {
return (T) HDR.get(hdr); return (T) HDR.get(hdr);
} }
private <T> T reverseLookup(HashMap<T, ?> map, Object object) {
for (T value : map.keySet()) {
if (object.equals(map.get(value))) {
return value;
}
}
return null;
}
@Override @Override
<T> Flash unmapFlash(T cameraConstant) { public <T> Flash unmapFlash(T cameraConstant) {
return reverseLookup(FLASH, cameraConstant); return reverseLookup(FLASH, cameraConstant);
} }
@Override @Override
<T> Facing unmapFacing(T cameraConstant) { public <T> Facing unmapFacing(T cameraConstant) {
return reverseLookup(FACING, cameraConstant); return reverseLookup(FACING, cameraConstant);
} }
@Override @Override
<T> WhiteBalance unmapWhiteBalance(T cameraConstant) { public <T> WhiteBalance unmapWhiteBalance(T cameraConstant) {
return reverseLookup(WB, cameraConstant); return reverseLookup(WB, cameraConstant);
} }
@Override @Override
<T> Hdr unmapHdr(T cameraConstant) { public <T> Hdr unmapHdr(T cameraConstant) {
return reverseLookup(HDR, cameraConstant); return reverseLookup(HDR, cameraConstant);
} }
} }

@ -90,7 +90,7 @@ public class OrientationHelper {
* Returns the current device orientation. * Returns the current device orientation.
* @return device orientation * @return device orientation
*/ */
int getDeviceOrientation() { public int getDeviceOrientation() {
return mDeviceOrientation; return mDeviceOrientation;
} }
@ -98,7 +98,7 @@ public class OrientationHelper {
* Returns the current display offset. * Returns the current display offset.
* @return display offset * @return display offset
*/ */
int getDisplayOffset() { public int getDisplayOffset() {
return mDisplayOffset; return mDisplayOffset;
} }
} }

@ -162,7 +162,7 @@ public abstract class CameraPreview<T extends View, Output> {
mCropTask.end(null); mCropTask.end(null);
} }
boolean supportsCropping() { public boolean supportsCropping() {
return false; return false;
} }

@ -70,7 +70,7 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
private View mRootView; private View mRootView;
GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) { public GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }

@ -16,14 +16,14 @@ import com.otaliastudios.cameraview.R;
// Currently this does NOT support cropping (e. g. the crop inside behavior), // Currently this does NOT support cropping (e. g. the crop inside behavior),
// so we return false in supportsCropping() in order to have proper measuring. // so we return false in supportsCropping() in order to have proper measuring.
// This means that CameraView is forced to be wrap_content. // This means that CameraView is forced to be wrap_content.
class SurfaceCameraPreview extends CameraPreview<SurfaceView, SurfaceHolder> { public class SurfaceCameraPreview extends CameraPreview<SurfaceView, SurfaceHolder> {
private final static CameraLogger LOG = CameraLogger.create(SurfaceCameraPreview.class.getSimpleName()); private final static CameraLogger LOG = CameraLogger.create(SurfaceCameraPreview.class.getSimpleName());
private boolean mDispatched; private boolean mDispatched;
private View mRootView; private View mRootView;
SurfaceCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) { public SurfaceCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }

@ -14,11 +14,11 @@ import com.otaliastudios.cameraview.R;
import com.otaliastudios.cameraview.preview.CameraPreview; import com.otaliastudios.cameraview.preview.CameraPreview;
import com.otaliastudios.cameraview.size.AspectRatio; import com.otaliastudios.cameraview.size.AspectRatio;
class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> { public class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> {
private View mRootView; private View mRootView;
TextureCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) { public TextureCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }

Loading…
Cancel
Save