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;
}
@NonNull
@Override
protected CameraPreview instantiatePreview(Context context, ViewGroup container) {
protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
mockPreview = new MockCameraPreview(context, container);
return mockPreview;
}

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

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

@ -5,6 +5,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 {
@ -15,18 +21,14 @@ public abstract class CameraListener {
* @param options camera supported options
*/
@UiThread
public void onCameraOpened(@NonNull CameraOptions options) {
}
public void onCameraOpened(@NonNull CameraOptions options) { }
/**
* Notifies that the camera session was closed.
*/
@UiThread
public void onCameraClosed() {
}
public void onCameraClosed() { }
/**
@ -39,9 +41,7 @@ public abstract class CameraListener {
* @param exception the error
*/
@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
*/
@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
*/
@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
*/
@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()
*/
@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()
*/
@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
*/
@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
*/
@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.
*/
@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})
public final class CameraLogger {
public final static int LEVEL_VERBOSE = 0;

@ -1,16 +1,13 @@
package com.otaliastudios.cameraview;
import android.annotation.TargetApi;
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Control;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.engine.Mapper;
import com.otaliastudios.cameraview.engine.Mapper1;
import com.otaliastudios.cameraview.gesture.GestureAction;
import com.otaliastudios.cameraview.controls.Grid;
import com.otaliastudios.cameraview.controls.Hdr;
@ -54,7 +51,7 @@ public class CameraOptions {
@SuppressWarnings("deprecation")
public CameraOptions(@NonNull Camera.Parameters params, boolean flipSizes) {
List<String> strings;
Mapper mapper = new Mapper1();
Mapper mapper = Mapper.get();
// Facing
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).
*

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

@ -4,6 +4,8 @@ import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
@ -76,7 +78,10 @@ import static android.view.View.MeasureSpec.UNSPECIFIED;
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 {
private final static String TAG = CameraView.class.getSimpleName();
@ -93,13 +98,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
private Preview mPreview;
// Components
/* for tests */ CameraCallbacks mCameraCallbacks;
@VisibleForTesting CameraCallbacks mCameraCallbacks;
private CameraPreview mCameraPreview;
private OrientationHelper mOrientationHelper;
private CameraEngine mCameraEngine;
private MediaActionSound mSound;
/* for tests */ List<CameraListener> mListeners = new CopyOnWriteArrayList<>();
/* for tests */ List<FrameProcessor> mFrameProcessors = new CopyOnWriteArrayList<>();
@VisibleForTesting List<CameraListener> mListeners = new CopyOnWriteArrayList<>();
@VisibleForTesting List<FrameProcessor> mFrameProcessors = new CopyOnWriteArrayList<>();
private Lifecycle mLifecycle;
// Views
@ -108,6 +113,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
TapGestureLayout mTapGestureLayout;
ScrollGestureLayout mScrollGestureLayout;
private boolean mKeepScreenOn;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private boolean mExperimental;
// Threading
@ -138,15 +144,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mPreview = controls.getPreview();
// 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);
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);
int videoMaxDuration = a.getInteger(R.styleable.CameraView_cameraVideoMaxDuration, 0);
int videoBitRate = a.getInteger(R.styleable.CameraView_cameraVideoBitRate, 0);
@ -160,7 +158,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
a.recycle();
// Components
mCameraCallbacks = new Callbacks();
mCameraCallbacks = new CameraCallbacks();
mCameraEngine = instantiateCameraController(mCameraCallbacks);
mUiHandler = new Handler(Looper.getMainLooper());
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());
switch (mPreview) {
case SURFACE:
@ -230,7 +241,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
}
/* for tests */ void instantiatePreview() {
@VisibleForTesting
void instantiatePreview() {
mCameraPreview = instantiatePreview(getContext(), this);
mCameraEngine.setPreview(mCameraPreview);
}
@ -471,6 +483,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
*/
@NonNull
public GestureAction getGestureAction(@NonNull Gesture gesture) {
//noinspection ConstantConditions
return mGestureMap.get(gesture);
}
@ -481,12 +494,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isOpened()) return true;
// Pass to our own GestureLayouts
CameraOptions options = mCameraEngine.getCameraOptions(); // Non null
if (options == null) throw new IllegalStateException("Options should not be null here.");
if (mPinchGestureLayout.onTouchEvent(event)) {
LOG.i("onTouchEvent", "pinch!");
onGesture(mPinchGestureLayout, options);
@ -509,10 +524,11 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
GestureAction action = mGestureMap.get(gesture);
PointF[] points = source.getPoints();
float oldValue, newValue;
//noinspection ConstantConditions
switch (action) {
case CAPTURE:
mCameraEngine.takePicture();
takePicture();
break;
case FOCUS:
@ -629,9 +645,9 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
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.");
throw new IllegalStateException(CameraLogger.lastMessage);
throw new IllegalStateException(message);
} catch (PackageManager.NameNotFoundException e) {
// 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.
* @return the current autofocus reset delay in milliseconds.
*/
@SuppressWarnings("unused")
public long getAutoFocusResetDelay() { return mCameraEngine.getAutoFocusResetDelay(); }
@ -1141,6 +1158,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* Returns the current video bit rate.
* @return current bit rate
*/
@SuppressWarnings("unused")
public int getVideoBitRate() {
return mCameraEngine.getVideoBitRate();
}
@ -1159,6 +1177,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* Returns the current audio bit rate.
* @return current bit rate
*/
@SuppressWarnings("unused")
public int 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.
// It's better to do calculations in the REF_VIEW reference, and then flip if needed.
Size preview = mCameraEngine.getUncroppedSnapshotSize(CameraEngine.REF_VIEW);
if (preview == null) return null; // Should never happen.
AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight());
Rect crop = CropHelper.computeCrop(preview, viewRatio);
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 (requestAudio) permissions.add(Manifest.permission.RECORD_AUDIO);
if (activity != null) {
activity.requestPermissions(permissions.toArray(new String[permissions.size()]),
activity.requestPermissions(permissions.toArray(new String[0]),
PERMISSION_REQUEST_CODE);
}
}
@ -1614,12 +1634,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
//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());
Callbacks() {}
@Override
public void dispatchOnCameraOpened(final CameraOptions options) {
mLogger.i("dispatchOnCameraOpened", options);
@ -1670,11 +1688,12 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
@Override
public void dispatchOnPictureTaken(final PictureResult result) {
mLogger.i("dispatchOnPictureTaken");
public void dispatchOnPictureTaken(final PictureResult.Stub stub) {
mLogger.i("dispatchOnPictureTaken", stub);
mUiHandler.post(new Runnable() {
@Override
public void run() {
PictureResult result = new PictureResult(stub);
for (CameraListener listener : mListeners) {
listener.onPictureTaken(result);
}
@ -1683,13 +1702,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
@Override
public void dispatchOnVideoTaken(final VideoResult video) {
mLogger.i("dispatchOnVideoTaken", video);
public void dispatchOnVideoTaken(final VideoResult.Stub stub) {
mLogger.i("dispatchOnVideoTaken", stub);
mUiHandler.post(new Runnable() {
@Override
public void run() {
VideoResult result = new VideoResult(stub);
for (CameraListener listener : mListeners) {
listener.onVideoTaken(video);
listener.onVideoTaken(result);
}
}
});
@ -1813,8 +1833,4 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
//endregion
//region deprecated APIs
//endregion
}

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

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

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

@ -46,7 +46,7 @@ import java.util.List;
@SuppressWarnings("deprecation")
class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Camera.ErrorCallback,
public class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Camera.ErrorCallback,
VideoRecorder.VideoResultListener,
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);
mMapper = Mapper.get();
}
@ -376,7 +376,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setMode(@NonNull Mode mode) {
public void setMode(@NonNull Mode mode) {
if (mode != mMode) {
mMode = mode;
schedule(null, true, new Runnable() {
@ -389,7 +389,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setLocation(@Nullable Location location) {
public void setLocation(@Nullable Location location) {
final Location oldLocation = mLocation;
mLocation = location;
schedule(mLocationTask, true, new Runnable() {
@ -414,7 +414,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setFacing(@NonNull Facing facing) {
public void setFacing(@NonNull Facing facing) {
final Facing old = mFacing;
if (facing != old) {
mFacing = facing;
@ -432,7 +432,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
public void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
final WhiteBalance old = mWhiteBalance;
mWhiteBalance = whiteBalance;
schedule(mWhiteBalanceTask, true, new Runnable() {
@ -454,7 +454,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setHdr(@NonNull Hdr hdr) {
public void setHdr(@NonNull Hdr hdr) {
final Hdr old = mHdr;
mHdr = hdr;
schedule(mHdrTask, true, new Runnable() {
@ -475,6 +475,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
return false;
}
@SuppressWarnings("UnusedReturnValue")
@TargetApi(17)
private boolean applyPlaySounds(boolean oldPlaySound) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
@ -498,7 +499,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
@Override
void setAudio(@NonNull Audio audio) {
public void setAudio(@NonNull Audio audio) {
if (mAudio != audio) {
if (isTakingVideo()) {
LOG.w("Audio setting was changed while recording. " +
@ -509,7 +510,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setFlash(@NonNull Flash flash) {
public void setFlash(@NonNull Flash flash) {
final Flash old = mFlash;
mFlash = flash;
schedule(mFlashTask, true, new Runnable() {
@ -581,7 +582,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void takePicture(final @NonNull PictureResult.Stub stub) {
public void takePicture(final @NonNull PictureResult.Stub stub) {
LOG.v("takePicture: scheduling");
schedule(null, true, new Runnable() {
@Override
@ -610,7 +611,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
* @param viewAspectRatio the view aspect ratio
*/
@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");
schedule(null, true, new Runnable() {
@Override
@ -685,7 +686,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@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() {
@Override
public void run() {
@ -731,7 +732,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
*/
@SuppressLint("NewApi")
@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)) {
throw new IllegalStateException("Video snapshots are only supported with GlCameraPreview.");
}
@ -815,7 +816,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void stopVideo() {
public void stopVideo() {
schedule(null, false, new Runnable() {
@Override
public void run() {
@ -833,7 +834,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
@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() {
@Override
public void run() {
@ -853,7 +854,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@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) {
schedule(mExposureCorrectionTask, true, new Runnable() {
@Override
@ -882,7 +883,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
@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.
int viewWidth = 0, viewHeight = 0;
if (mPreview != null && mPreview.hasSurface()) {
@ -992,7 +993,7 @@ class Camera1Engine extends CameraEngine implements Camera.PreviewCallback, Came
}
@Override
void setPlaySounds(boolean playSounds) {
public void setPlaySounds(boolean playSounds) {
final boolean old = mPlaySounds;
mPlaySounds = playSounds;
schedule(mPlaySoundsTask, true, new Runnable() {

@ -52,8 +52,8 @@ public abstract class CameraEngine implements
void dispatchOnCameraClosed();
void onCameraPreviewStreamSizeChanged();
void onShutter(boolean shouldPlaySound);
void dispatchOnVideoTaken(VideoResult.Stub result);
void dispatchOnPictureTaken(PictureResult.Stub result);
void dispatchOnVideoTaken(VideoResult.Stub stub);
void dispatchOnPictureTaken(PictureResult.Stub stub);
void dispatchOnFocusStart(@Nullable Gesture trigger, @NonNull PointF where);
void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, @NonNull PointF where);
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);
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_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;
static final int REF_VIEW = 1;
static final int REF_OUTPUT = 2;
public static final int REF_SENSOR = 0;
public static final int REF_VIEW = 1;
public static final int REF_OUTPUT = 2;
protected final Callback mCallback;
protected CameraPreview mPreview;
@ -137,7 +137,7 @@ public abstract class CameraEngine implements
mFrameManager = new FrameManager(2, this);
}
void setPreview(@NonNull CameraPreview cameraPreview) {
public void setPreview(@NonNull CameraPreview cameraPreview) {
mPreview = cameraPreview;
mPreview.setSurfaceCallback(this);
}
@ -217,7 +217,7 @@ public abstract class CameraEngine implements
}
// Starts the preview asynchronously.
final void start() {
public final void start() {
LOG.i("Start:", "posting runnable. State:", ss());
mHandler.post(new Runnable() {
@Override
@ -307,7 +307,7 @@ public abstract class CameraEngine implements
abstract void onStop();
// Returns current state.
final int getState() {
public final int getState() {
return mState;
}
@ -316,198 +316,204 @@ public abstract class CameraEngine implements
//region Simple setters
// This is called before start() and never again.
final void setDisplayOffset(int displayOffset) {
public final void setDisplayOffset(int displayOffset) {
mDisplayOffset = displayOffset;
}
// This can be called multiple times.
final void setDeviceOrientation(int deviceOrientation) {
public final void setDeviceOrientation(int deviceOrientation) {
mDeviceOrientation = deviceOrientation;
}
final void setPreviewStreamSizeSelector(@Nullable SizeSelector selector) {
public final void setPreviewStreamSizeSelector(@Nullable SizeSelector selector) {
mPreviewStreamSizeSelector = selector;
}
final void setPictureSizeSelector(@NonNull SizeSelector selector) {
public final void setPictureSizeSelector(@NonNull SizeSelector selector) {
mPictureSizeSelector = selector;
}
final void setVideoSizeSelector(@NonNull SizeSelector selector) {
public final void setVideoSizeSelector(@NonNull SizeSelector selector) {
mVideoSizeSelector = selector;
}
final void setVideoMaxSize(long videoMaxSizeBytes) {
public final void setVideoMaxSize(long videoMaxSizeBytes) {
mVideoMaxSize = videoMaxSizeBytes;
}
final void setVideoMaxDuration(int videoMaxDurationMillis) {
public final void setVideoMaxDuration(int videoMaxDurationMillis) {
mVideoMaxDuration = videoMaxDurationMillis;
}
final void setVideoCodec(@NonNull VideoCodec codec) {
public final void setVideoCodec(@NonNull VideoCodec codec) {
mVideoCodec = codec;
}
final void setVideoBitRate(int videoBitRate) {
public final void setVideoBitRate(int videoBitRate) {
mVideoBitRate = videoBitRate;
}
final void setAudioBitRate(int audioBitRate) {
public final void setAudioBitRate(int audioBitRate) {
mAudioBitRate = audioBitRate;
}
final void setSnapshotMaxWidth(int maxWidth) {
public final void setSnapshotMaxWidth(int maxWidth) {
mSnapshotMaxWidth = maxWidth;
}
final void setSnapshotMaxHeight(int maxHeight) {
public final void setSnapshotMaxHeight(int maxHeight) {
mSnapshotMaxHeight = maxHeight;
}
final void setAutoFocusResetDelay(long delayMillis) { mAutoFocusResetDelayMillis = delayMillis; }
public final void setAutoFocusResetDelay(long delayMillis) { mAutoFocusResetDelayMillis = delayMillis; }
//endregion
//region Abstract setters and APIs
// 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.
abstract void setFacing(@NonNull Facing facing);
public abstract void setFacing(@NonNull Facing facing);
// 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.
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.
abstract void setFlash(@NonNull Flash flash);
public abstract void setFlash(@NonNull Flash flash);
// 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.
abstract void setHdr(@NonNull Hdr hdr);
public abstract void setHdr(@NonNull Hdr hdr);
// If closed, keep. If opened, check supported and apply.
abstract void setLocation(@Nullable Location location);
public abstract void setLocation(@Nullable Location location);
// 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
//region final getters
@Nullable
final CameraOptions getCameraOptions() {
public final CameraOptions getCameraOptions() {
return mCameraOptions;
}
@NonNull
final Facing getFacing() {
public final Facing getFacing() {
return mFacing;
}
@NonNull
final Flash getFlash() {
public final Flash getFlash() {
return mFlash;
}
@NonNull
final WhiteBalance getWhiteBalance() {
public final WhiteBalance getWhiteBalance() {
return mWhiteBalance;
}
final VideoCodec getVideoCodec() {
public final VideoCodec getVideoCodec() {
return mVideoCodec;
}
final int getVideoBitRate() {
public final int getVideoBitRate() {
return mVideoBitRate;
}
final long getVideoMaxSize() {
public final long getVideoMaxSize() {
return mVideoMaxSize;
}
final int getVideoMaxDuration() {
public final int getVideoMaxDuration() {
return mVideoMaxDuration;
}
@NonNull
final Mode getMode() {
public final Mode getMode() {
return mMode;
}
@NonNull
final Hdr getHdr() {
public final Hdr getHdr() {
return mHdr;
}
@Nullable
final Location getLocation() {
public final Location getLocation() {
return mLocation;
}
@NonNull
final Audio getAudio() {
public final Audio getAudio() {
return mAudio;
}
final int getAudioBitRate() {
public final int getAudioBitRate() {
return mAudioBitRate;
}
@SuppressWarnings("unused")
@Nullable
/* for tests */ final SizeSelector getPreviewStreamSizeSelector() {
@VisibleForTesting
final SizeSelector getPreviewStreamSizeSelector() {
return mPreviewStreamSizeSelector;
}
@SuppressWarnings("unused")
@NonNull
/* for tests */ final SizeSelector getPictureSizeSelector() {
@VisibleForTesting
final SizeSelector getPictureSizeSelector() {
return mPictureSizeSelector;
}
@SuppressWarnings("unused")
@NonNull
/* for tests */ final SizeSelector getVideoSizeSelector() {
@VisibleForTesting
final SizeSelector getVideoSizeSelector() {
return mVideoSizeSelector;
}
final float getZoomValue() {
public final float getZoomValue() {
return mZoomValue;
}
final float getExposureCorrectionValue() {
public final float getExposureCorrectionValue() {
return mExposureCorrectionValue;
}
final boolean isTakingVideo() {
public final boolean isTakingVideo() {
return mVideoRecorder != null;
}
final boolean isTakingPicture() {
public final boolean isTakingPicture() {
return mPictureRecorder != null;
}
final long getAutoFocusResetDelay() { return mAutoFocusResetDelayMillis; }
public final long getAutoFocusResetDelay() { return mAutoFocusResetDelayMillis; }
final boolean shouldResetAutoFocus() {
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;
}
final boolean flip(int reference1, int reference2) {
public final boolean flip(int reference1, int reference2) {
return offset(reference1, reference2) % 180 != 0;
}
@Nullable
final Size getPictureSize(@SuppressWarnings("SameParameterValue") int reference) {
public final Size getPictureSize(@SuppressWarnings("SameParameterValue") int reference) {
if (mCaptureSize == null || mMode == Mode.VIDEO) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
}
@Nullable
final Size getVideoSize(@SuppressWarnings("SameParameterValue") int reference) {
public final Size getVideoSize(@SuppressWarnings("SameParameterValue") int reference) {
if (mCaptureSize == null || mMode == Mode.PICTURE) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
}
@Nullable
final Size getPreviewStreamSize(int reference) {
public final Size getPreviewStreamSize(int reference) {
if (mPreviewStreamSize == null) return null;
return flip(REF_SENSOR, reference) ? mPreviewStreamSize.flip() : mPreviewStreamSize;
}
@ -601,7 +607,7 @@ public abstract class CameraEngine implements
* apply, despite the capturing mechanism being different.
*/
@Nullable
final Size getUncroppedSnapshotSize(int reference) {
public final Size getUncroppedSnapshotSize(int reference) {
Size baseSize = getPreviewStreamSize(reference);
if (baseSize == null) return null;
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
// is null, or if it fails in finding a size.
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());
if (flip) targetRatio = targetRatio.flip();
LOG.i("size:", "computePreviewStreamSize:", "targetRatio:", targetRatio, "targetMinSize:", targetMinSize);

@ -17,18 +17,35 @@ public abstract class Mapper {
private Mapper() {}
abstract <T> T map(Flash flash);
abstract <T> T map(Facing facing);
abstract <T> T map(WhiteBalance whiteBalance);
abstract <T> T map(Hdr hdr);
abstract <T> Flash unmapFlash(T cameraConstant);
abstract <T> Facing unmapFacing(T cameraConstant);
abstract <T> WhiteBalance unmapWhiteBalance(T cameraConstant);
abstract <T> Hdr unmapHdr(T cameraConstant);
public abstract <T> T map(Flash flash);
public abstract <T> T map(Facing facing);
public abstract <T> T map(WhiteBalance whiteBalance);
public abstract <T> T map(Hdr hdr);
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;
static Mapper get() {
public static Mapper get() {
if (CAMERA1 == null) {
CAMERA1 = new Camera1Mapper();
}
@ -64,51 +81,42 @@ public abstract class Mapper {
}
@Override
<T> T map(Flash flash) {
public <T> T map(Flash flash) {
return (T) FLASH.get(flash);
}
@Override
<T> T map(Facing facing) {
public <T> T map(Facing facing) {
return (T) FACING.get(facing);
}
@Override
<T> T map(WhiteBalance whiteBalance) {
public <T> T map(WhiteBalance whiteBalance) {
return (T) WB.get(whiteBalance);
}
@Override
<T> T map(Hdr hdr) {
public <T> T map(Hdr 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
<T> Flash unmapFlash(T cameraConstant) {
public <T> Flash unmapFlash(T cameraConstant) {
return reverseLookup(FLASH, cameraConstant);
}
@Override
<T> Facing unmapFacing(T cameraConstant) {
public <T> Facing unmapFacing(T cameraConstant) {
return reverseLookup(FACING, cameraConstant);
}
@Override
<T> WhiteBalance unmapWhiteBalance(T cameraConstant) {
public <T> WhiteBalance unmapWhiteBalance(T cameraConstant) {
return reverseLookup(WB, cameraConstant);
}
@Override
<T> Hdr unmapHdr(T cameraConstant) {
public <T> Hdr unmapHdr(T cameraConstant) {
return reverseLookup(HDR, cameraConstant);
}
}

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

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

@ -70,7 +70,7 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
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);
}

@ -16,14 +16,14 @@ import com.otaliastudios.cameraview.R;
// Currently this does NOT support cropping (e. g. the crop inside behavior),
// so we return false in supportsCropping() in order to have proper measuring.
// 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 boolean mDispatched;
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);
}

@ -14,11 +14,11 @@ import com.otaliastudios.cameraview.R;
import com.otaliastudios.cameraview.preview.CameraPreview;
import com.otaliastudios.cameraview.size.AspectRatio;
class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> {
public class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> {
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);
}

Loading…
Cancel
Save