diff --git a/README.md b/README.md index c4c84321..79e22f55 100644 --- a/README.md +++ b/README.md @@ -310,8 +310,8 @@ What to capture - either picture or video. This has a couple of consequences: - Permission behavior: when requesting a `video` session, the record audio permission will be requested. If this is needed, the audio permission should be added to your manifest or the app will crash. ```java -cameraView.setSessionType(CameraConstants.SESSION_TYPE_PICTURE); -cameraView.setSessionType(CameraConstants.SESSION_TYPE_VIDEO); +cameraView.setSessionType(SessionType.PICTURE); +cameraView.setSessionType(SessionType.VIDEO); ``` #### cameraFacing diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java index ac88564b..87d3ff88 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java @@ -19,8 +19,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static com.otaliastudios.cameraview.CameraConstants.SESSION_TYPE_PICTURE; -import static com.otaliastudios.cameraview.CameraConstants.SESSION_TYPE_VIDEO; @SuppressWarnings("deprecation") class Camera1 extends CameraController { @@ -146,7 +144,7 @@ class Camera1 extends CameraController { mergeFlash(params, Flash.DEFAULT); mergeLocation(params, 0d, 0d); mergeWhiteBalance(params, WhiteBalance.DEFAULT); - params.setRecordingHint(mSessionType == SESSION_TYPE_VIDEO); + params.setRecordingHint(mSessionType == SessionType.VIDEO); mCamera.setParameters(params); } @@ -202,7 +200,7 @@ class Camera1 extends CameraController { @Override - void setSessionType(@SessionType int sessionType) { + void setSessionType(SessionType sessionType) { if (sessionType != mSessionType) { mSessionType = sessionType; if (isCameraOpened()) { @@ -297,7 +295,7 @@ class Camera1 extends CameraController { private void applyDefaultFocus(Camera.Parameters params) { List modes = params.getSupportedFocusModes(); - if (mSessionType == SESSION_TYPE_VIDEO && + if (mSessionType == SessionType.VIDEO && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); return; @@ -327,7 +325,7 @@ class Camera1 extends CameraController { } mVideoQuality = videoQuality; - if (isCameraOpened() && mSessionType == CameraConstants.SESSION_TYPE_VIDEO) { + if (isCameraOpened() && mSessionType == SessionType.VIDEO) { // Change capture size to a size that fits the video aspect ratio. Size oldSize = mCaptureSize; mCaptureSize = computeCaptureSize(); @@ -350,7 +348,7 @@ class Camera1 extends CameraController { void capturePicture() { if (mIsCapturingImage) return; if (!isCameraOpened()) return; - if (mSessionType == SESSION_TYPE_VIDEO && mIsCapturingVideo) { + if (mSessionType == SessionType.VIDEO && mIsCapturingVideo) { if (!mOptions.isVideoSnapshotSupported()) return; } @@ -502,7 +500,7 @@ class Camera1 extends CameraController { */ private Size computeCaptureSize() { Camera.Parameters params = mCamera.getParameters(); - if (mSessionType == SESSION_TYPE_PICTURE) { + if (mSessionType == SessionType.PICTURE) { // Choose the max size. List captureSizes = sizesFromList(params.getSupportedPictureSizes()); return Collections.max(captureSizes); @@ -536,7 +534,7 @@ class Camera1 extends CameraController { if (!isCameraOpened()) return false; Camera.Parameters params = mCamera.getParameters(); params.setVideoStabilization(false); - if (mSessionType == SESSION_TYPE_VIDEO) { + if (mSessionType == SessionType.VIDEO) { mIsCapturingVideo = true; initMediaRecorder(); try { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera2.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera2.java index a67a46d8..283b7c37 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera2.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera2.java @@ -142,7 +142,7 @@ class Camera2 extends CameraController { } @Override - void setSessionType(@SessionType int sessionType) { + void setSessionType(SessionType sessionType) { } @@ -157,7 +157,7 @@ class Camera2 extends CameraController { } @Override - void setVideoQuality(int videoQuality) { + void setVideoQuality(VideoQuality videoQuality) { } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraConstants.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraConstants.java deleted file mode 100644 index 2c8c677c..00000000 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraConstants.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.otaliastudios.cameraview; - - -import android.hardware.Camera; - -public class CameraConstants { - - public static final int PERMISSION_REQUEST_CODE = 16; - - public static final int SESSION_TYPE_PICTURE = 0; - public static final int SESSION_TYPE_VIDEO = 1; - - - static class Defaults { - - static final int DEFAULT_SESSION_TYPE = SESSION_TYPE_PICTURE; - static final int DEFAULT_JPEG_QUALITY = 100; - static final boolean DEFAULT_CROP_OUTPUT = false; - - - } -} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java index 527ee11b..b95b352a 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java @@ -15,7 +15,7 @@ abstract class CameraController implements Preview.SurfaceCallback { protected Flash mFlash; protected WhiteBalance mWhiteBalance; protected VideoQuality mVideoQuality; - @SessionType protected int mSessionType; + protected SessionType mSessionType; CameraController(CameraView.CameraCallbacks callback, Preview preview) { mCameraCallbacks = callback; @@ -35,7 +35,7 @@ abstract class CameraController implements Preview.SurfaceCallback { abstract void setFlash(Flash flash); abstract void setWhiteBalance(WhiteBalance whiteBalance); abstract void setVideoQuality(VideoQuality videoQuality); - abstract void setSessionType(@SessionType int sessionType); + abstract void setSessionType(SessionType sessionType); abstract void setLocation(double latitude, double longitude); abstract void capturePicture(); @@ -57,9 +57,5 @@ abstract class CameraController implements Preview.SurfaceCallback { final Flash getFlash() { return mFlash; } final WhiteBalance getWhiteBalance() { return mWhiteBalance; } final VideoQuality getVideoQuality() { return mVideoQuality; } - - @SessionType - final int getSessionType() { - return mSessionType; - } + final SessionType getSessionType() { return mSessionType; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index 2748c825..e288d413 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -30,8 +30,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import static com.otaliastudios.cameraview.CameraConstants.*; - import static android.view.View.MeasureSpec.AT_MOST; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.UNSPECIFIED; @@ -42,6 +40,10 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; public class CameraView extends FrameLayout { private final static String TAG = CameraView.class.getSimpleName(); + public final static int PERMISSION_REQUEST_CODE = 16; + + private final static int DEFAULT_JPEG_QUALITY = 100; + private final static boolean DEFAULT_CROP_OUTPUT = false; private Handler mWorkerHandler; @@ -92,14 +94,14 @@ public class CameraView extends FrameLayout { @SuppressWarnings("WrongConstant") private void init(@NonNull Context context, @Nullable AttributeSet attrs) { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CameraView, 0, 0); + mJpegQuality = a.getInteger(R.styleable.CameraView_cameraJpegQuality, DEFAULT_JPEG_QUALITY); + mCropOutput = a.getBoolean(R.styleable.CameraView_cameraCropOutput, DEFAULT_CROP_OUTPUT); Facing facing = Facing.fromValue(a.getInteger(R.styleable.CameraView_cameraFacing, Facing.DEFAULT.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())); WhiteBalance whiteBalance = WhiteBalance.fromValue(a.getInteger(R.styleable.CameraView_cameraWhiteBalance, WhiteBalance.DEFAULT.value())); VideoQuality videoQuality = VideoQuality.fromValue(a.getInteger(R.styleable.CameraView_cameraVideoQuality, VideoQuality.DEFAULT.value())); - int sessionType = a.getInteger(R.styleable.CameraView_cameraSessionType, Defaults.DEFAULT_SESSION_TYPE); - mJpegQuality = a.getInteger(R.styleable.CameraView_cameraJpegQuality, Defaults.DEFAULT_JPEG_QUALITY); - mCropOutput = a.getBoolean(R.styleable.CameraView_cameraCropOutput, Defaults.DEFAULT_CROP_OUTPUT); + SessionType sessionType = SessionType.fromValue(a.getInteger(R.styleable.CameraView_cameraSessionType, SessionType.DEFAULT.value())); GestureAction tapGesture = GestureAction.fromValue(a.getInteger(R.styleable.CameraView_cameraGestureTap, GestureAction.DEFAULT_TAP.value())); GestureAction longTapGesture = GestureAction.fromValue(a.getInteger(R.styleable.CameraView_cameraGestureLongTap, GestureAction.DEFAULT_LONG_TAP.value())); GestureAction pinchGesture = GestureAction.fromValue(a.getInteger(R.styleable.CameraView_cameraGesturePinch, GestureAction.DEFAULT_PINCH.value())); @@ -310,7 +312,7 @@ public class CameraView extends FrameLayout { * Maps a {@link Gesture} to a certain gesture action. * For example, you can assign zoom control to the pinch gesture by just calling: * - * cameraView.mapGesture(Gesture.PINCH, CameraConstants.GESTURE_ACTION_ZOOM); + * cameraView.mapGesture(Gesture.PINCH, GestureAction.ZOOM); * * * Not all actions can be assigned to a certain gesture. For example, zoom control can't be @@ -447,7 +449,7 @@ public class CameraView extends FrameLayout { * Throws if session = audio and manifest did not add the microphone permissions. * @return true if we can go on, false otherwise. */ - private boolean checkPermissions(@SessionType int sessionType) { + private boolean checkPermissions(SessionType sessionType) { checkPermissionsManifestOrThrow(sessionType); boolean api23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; int cameraCheck, audioCheck; @@ -461,14 +463,14 @@ public class CameraView extends FrameLayout { audioCheck = getContext().checkSelfPermission(Manifest.permission.RECORD_AUDIO); } switch (sessionType) { - case SESSION_TYPE_VIDEO: + case VIDEO: if (cameraCheck != PackageManager.PERMISSION_GRANTED || audioCheck != PackageManager.PERMISSION_GRANTED) { requestPermissions(true, true); return false; } break; - case SESSION_TYPE_PICTURE: + case PICTURE: if (cameraCheck != PackageManager.PERMISSION_GRANTED) { requestPermissions(true, false); return false; @@ -484,8 +486,8 @@ public class CameraView extends FrameLayout { * If the developer did not add this to its manifest, throw and fire warnings. * (Hoping this is not cought elsewhere... we should test). */ - private void checkPermissionsManifestOrThrow(@SessionType int sessionType) { - if (sessionType == SESSION_TYPE_VIDEO) { + private void checkPermissionsManifestOrThrow(SessionType sessionType) { + if (sessionType == SessionType.VIDEO) { try { PackageManager manager = getContext().getPackageManager(); PackageInfo info = manager.getPackageInfo(getContext().getPackageName(), PackageManager.GET_PERMISSIONS); @@ -796,14 +798,14 @@ public class CameraView extends FrameLayout { * Set the current session type to either picture or video. * When sessionType is video, * - {@link #startCapturingVideo(File)} will not throw any exception - * - {@link #capturePicture()} will fallback to {@link #captureSnapshot()} + * - {@link #capturePicture()} might fallback to {@link #captureSnapshot()} or might not work * - * @see CameraConstants#SESSION_TYPE_PICTURE - * @see CameraConstants#SESSION_TYPE_VIDEO + * @see SessionType#PICTURE + * @see SessionType#VIDEO * * @param sessionType desired session type. */ - public void setSessionType(@SessionType int sessionType) { + public void setSessionType(SessionType sessionType) { if (sessionType == getSessionType() || !mIsStarted) { // Check did took place, or will happen on start(). @@ -827,8 +829,7 @@ public class CameraView extends FrameLayout { * Gets the current session type. * @return the current session type */ - @SessionType - public int getSessionType() { + public SessionType getSessionType() { return mCameraController.getSessionType(); } @@ -943,7 +944,7 @@ public class CameraView extends FrameLayout { * This will trigger {@link CameraListener#onPictureTaken(byte[])} if a listener * was registered. * - * Note that if sessionType is {@link CameraConstants#SESSION_TYPE_VIDEO}, this + * Note that if sessionType is {@link SessionType#VIDEO}, this * might fall back to {@link #captureSnapshot()} (that is, we might capture a preview frame). * * @see #captureSnapshot() diff --git a/cameraview/src/main/options/com/otaliastudios/cameraview/SessionType.java b/cameraview/src/main/options/com/otaliastudios/cameraview/SessionType.java index ea7c9938..d40d9a39 100644 --- a/cameraview/src/main/options/com/otaliastudios/cameraview/SessionType.java +++ b/cameraview/src/main/options/com/otaliastudios/cameraview/SessionType.java @@ -1,14 +1,56 @@ package com.otaliastudios.cameraview; -import android.support.annotation.IntDef; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import static com.otaliastudios.cameraview.CameraConstants.SESSION_TYPE_PICTURE; -import static com.otaliastudios.cameraview.CameraConstants.SESSION_TYPE_VIDEO; +/** + * Type of the session to be opened or to move to. + * Session types have influence over the capture and preview size, ability to shoot pictures, + * focus modes, runtime permissions needed. + * + * @see CameraView#setSessionType(SessionType) + */ +public enum SessionType { -@Retention(RetentionPolicy.SOURCE) -@IntDef({SESSION_TYPE_PICTURE, SESSION_TYPE_VIDEO}) -public @interface SessionType { + /** + * Session optimized to capture pictures. + * + * - Trying to take videos in this session will throw an exception + * - Only the camera permission is requested + * - Preview and capture size is chosen as the max available size + */ + PICTURE(0), + + /** + * Session optimized to capture videos. + * + * - Trying to take pictures in this session will work, though with lower quality + * - Trying to take pictures while recording a video will work if supported + * - Camera and audio record permissions are requested + * - Preview and capture size are chosen to respect the {@link VideoQuality} aspect ratio + * + * @see CameraOptions#isVideoSnapshotSupported() + */ + VIDEO(1); + + static final SessionType DEFAULT = PICTURE; + + private int value; + + SessionType(int value) { + this.value = value; + } + + int value() { + return value; + } + + static SessionType fromValue(int value) { + SessionType[] list = SessionType.values(); + for (SessionType action : list) { + if (action.value() == value) { + return action; + } + } + return null; + } } diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java index ad3f1b65..55f29c79 100644 --- a/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java @@ -13,11 +13,10 @@ import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; -import com.otaliastudios.cameraview.CameraConstants; import com.otaliastudios.cameraview.CameraListener; import com.otaliastudios.cameraview.CameraView; -import com.otaliastudios.cameraview.Facing; import com.otaliastudios.cameraview.Grid; +import com.otaliastudios.cameraview.SessionType; import com.otaliastudios.cameraview.Size; import com.otaliastudios.cameraview.VideoQuality; @@ -165,7 +164,7 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan @OnClick(R.id.captureVideo) void captureVideo() { - if (camera.getSessionType() != CameraConstants.SESSION_TYPE_VIDEO) { + if (camera.getSessionType() != SessionType.VIDEO) { message("Can't record video while session type is 'picture'.", false); return; } @@ -217,12 +216,9 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if (mCapturingPicture) return; - camera.setSessionType( - checkedId == R.id.sessionTypePicture ? - CameraConstants.SESSION_TYPE_PICTURE : - CameraConstants.SESSION_TYPE_VIDEO - ); - message("Session type set to" + (checkedId == R.id.sessionTypePicture ? " picture!" : " video!"), true); + boolean pic = checkedId == R.id.sessionTypePicture; + camera.setSessionType(pic ? SessionType.PICTURE : SessionType.VIDEO); + message("Session type set to" + (pic ? " picture!" : " video!"), true); } };