diff --git a/README.md b/README.md index 41a58be3..908bcf19 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ #####Originally a fork of [Google's CameraView library](https://github.com/google/cameraview). -CameraKit is an extraordinarily easy to use utility to work with the infamous Android Camera and Camera2 APIs. Built by [Dylan McIntyre](https://github.com/dwillmc). +CameraKit is an extraordinarily easy to use utility to work with the infamous Android Camera and Camera2 APIs. Built by [Dylan McIntyre](https://github.com/dwillmc). Try out all the unique features using the CameraKit Demo from the Google Play store! @@ -20,26 +20,24 @@ Try out all the unique features using the CameraKit Demo from the Google Play st - [Usage](#usage) - [Events](#events) - [Extra Attributes](#extra-attributes) - - [`ckCropOutput`](#ckcropoutput) - [`ckFacing`](#ckfacing) - [`ckFlash`](#ckflash) - - [`ckCaptureMode`](#ckcapturemode) - - [`ckPinchToZoom`](#ckpinchtozoom) - - [`ckTapToFocus`](#cktaptofocus) - - [`ckAutoFocus`](#ckautofocus) - - [`ckCaptureSize`](#ckcapturesize) - - [`ckJpegCompression`](#ckjpegcompression) + - [`ckFocus`](#ckfocus) + - [`ckMethod`](#ckmethod) + - [`ckZoom`](#ckzoom) + - [`ckCropOutput`](#ckcropoutput) + - [`ckJpegQuality`](#ckjpegquality) - [Capturing Images](#capturing-images) - [Capturing Video](#capturing-video) - [Automatic Permissions Behavior](#automatic-permissions-behavior) - [Dynamic Sizing Behavior](#dynamic-sizing-behavior) - [Output Cropping](#output-cropping) - [`adjustViewBounds`](#adjustviewbounds) -- [Capture Mode Behavior](#capture-mode-behavior) - - [Quality](#quality) - - [Speed](#speed) +- [Capture Methods](#capture-methods) + - [Standard](#standard) + - [Still](#still) - [Auto](#auto) -- [Tap To Focus](#tap-to-focus) +- [Focus](#focus) - [Credits](#credits) - [License](#license) @@ -51,9 +49,9 @@ Try out all the unique features using the CameraKit Demo from the Google Play st - Automatic preview scaling. - Create a `CameraView` of any size (not just presets!). - Automatic output cropping to match your `CameraView` bounds. -- Multiple capture modes. - - `PICTURE_MODE_STANDARD`: an image captured normally using the camera APIs. - - `PICTURE_MODE_STILL`: a freeze frame of the `CameraView` preview (similar to SnapChat and Instagram) for devices with slower cameras. +- Multiple capture methods. + - `METHOD_STANDARD`: an image captured normally using the camera APIs. + - `METHOD_STILL`: a freeze frame of the `CameraView` preview (similar to SnapChat and Instagram) for devices with slower cameras. - Automatic picture mode determination based on measured speed. - Built-in tap to focus and auto focus. - Built-in pinch to zoom. @@ -74,7 +72,8 @@ To use CameraKit, simply add a `CameraView` to your layout: + android:layout_height="wrap_content" + android:adjustViewBounds="true" /> ``` Make sure you override `onResume` and `onPause` in your activity, and make calls respectively to `CameraView.start()` and `CameraView.stop()`. @@ -119,7 +118,7 @@ camera.setCameraListener(new CameraListener() { public void onVideoTaken(File video) { super.onVideoTaken(video); } - + }); ``` @@ -129,25 +128,17 @@ camera.setCameraListener(new CameraListener() { + camerakit:ckFocus="continuous" + camerakit:ckMethod="standard" + camerakit:ckZoom="pinch" + camerakit:ckCropOutput="true" + camerakit:ckJpegQuality="100" + android:adjustViewBounds="true" /> ``` -#### `ckCropOutput` - -| Value | Description | -| --------------| -------------| -| `true` | Crop the output image or video to only contain what can be seen on the `CameraView` preview. | -| `false` | Output the full image or video regardless of what is visible on the `CameraView` preview. | - #### `ckFacing` | Value | Description | @@ -163,44 +154,37 @@ camera.setCameraListener(new CameraListener() { | `on` | Default `CameraView` flash to on. | | `auto` | Default `CameraView` flash to automatic. | -#### `ckCaptureMode` - -| Value | Description | -| --------------| -------------| -| `standard` | Use normal Android Camera API image capturing. | -| `still` | Freeze the `CameraView` preview and grab a `Bitmap` of the frame. | -| `auto` (coming soon) | Default picture mode to `standard`, but fallback to `still` if capturing is determined to be too slow. | - -#### `ckPinchToZoom` +#### `ckFocus` | Value | Description | | --------------| -------------| -| `true` | User can zoom using pinching gestures with their fingers. | -| `false` | Default pinch to zoom behavior disabled. | +| `off` | Tap to focus is enabled and a visible focus circle appears when tapped, similar to the Android built-in camera. | +| `continuous` | Tap to focus is enabled, but no focus circle appears. | +| `tap` | Tap to focus is off. | -#### `ckTapToFocus` +#### `ckMethod` | Value | Description | | --------------| -------------| -| `visible` | Tap to focus is enabled and a visible focus circle appears when tapped, similar to the Android built-in camera. | -| `invisible` | Tap to focus is enabled, but no focus circle appears. | -| `off` | Tap to focus is off. | +| `standard` | Use normal Android Camera API image capturing. | +| `still` | Freeze the `CameraView` preview and grab a `Bitmap` of the frame. | +| `auto` (coming soon) | Default picture mode to `standard`, but fallback to `still` if capturing is determined to be too slow. | -#### `ckAutoFocus` +#### `ckZoom` | Value | Description | | --------------| -------------| -| `true` | Continuously allow the `CameraView` preview to adjust focus automatically. | -| `false` | Never adjust focus during preview. | +| `off` | User can zoom using pinching gestures with their fingers. | +| `pinch` | User can zoom in and out using pinching gestures on the `CameraView`. | -#### `ckCaptureSize` +#### `ckCropOutput` | Value | Description | | --------------| -------------| -| `n <= 0` | Capture at the highest quality possible. | -| `n > 0` | Capture at a size of approximately `n` megapixels. | +| `true` | Crop the output image or video to only contain what can be seen on the `CameraView` preview. | +| `false` | Output the full image or video regardless of what is visible on the `CameraView` preview. | -#### `ckJpegCompression` +#### `ckJpegQuality` | Value | Description | | --------------| -------------| @@ -209,20 +193,20 @@ camera.setCameraListener(new CameraListener() { ### Capturing Images -To capture an image just call `CameraView.capturePicture()`. Make sure you setup a `CameraListener` to handle the image callback. +To capture an image just call `CameraView.captureImage()`. Make sure you setup a `CameraListener` to handle the image callback. ```java camera.setCameraListener(new CameraListener() { @Override public void onPictureTaken(byte[] picture) { super.onPictureTaken(picture); - + // Create a bitmap Bitmap result = BitmapFactory.decodeByteArray(picture, 0, picture.length); } }); -camera.takePicture(); +camera.captureImage(); ``` ### Capturing Video @@ -234,7 +218,7 @@ camera.setCameraListener(new CameraListener() { @Override public void onVideoTaken(File video) { super.onVideoTaken(video); - // The File parameter is an MP4 file. + // The File parameter is an MP4 file. } }); @@ -251,7 +235,7 @@ camera.postDelayed(new Runnable() { You can handle permissions yourself in whatever way you want, but if you make a call to `CameraView.start()` without the `android.permission.CAMERA` permission, an exception would normally be thrown and your app would crash. -With CameraKit, we will automatically prompt for the `android.permission.CAMERA` permission if it's not available. If you want to handle it yourself, just make sure you dont call `CameraView.start()` until you acquire the permissions. +With CameraKit, we will automatically prompt for the `android.permission.CAMERA` permission if it's not available. If you want to handle it yourself, just make sure you don't call `CameraView.start()` until you acquire the permissions. ![Permissions behavior gif](.repo/permissions.gif) @@ -271,35 +255,35 @@ When you capture output you can either capture everything - even what is not vis You can use a mix of a fixed dimension (a set value or `match_parent`) as well as `wrap_content`. When you do this make sure you set `android:adjustViewBounds="true"` on the `CameraView`. -When you do this the dimension set to `wrap_content` will automatically align with the true aspect ratio of the preview surface. In this case the whole preview will be visible. +When you do this the dimension set to `wrap_content` will automatically align with the true aspect ratio of the preview surface. In this case the whole preview will be visible with no cropping. -## Capture Mode Behavior +## Capture Methods We decided to add multiple capture modes to CameraKit to allow you to give a better image capturing experience to users with slower cameras when appropriate. -See [`ckPictureMode`](#ckpicturemode) above for usage. +See [`ckMethod`](#ckmethod) above for usage. -### Quality +### Standard -When you use `PICTURE_MODE_QUALITY` (`camerakit:ckPictureMode="quality"`), images will be captured using the normal camera API capture method using the shutter. +When you use `METHOD_STANDARD` (`camerakit:ckMethod="standard"`), images will be captured using the normal camera API capture method using the shutter. [Insert GIF] -### Speed +### Still -When you use `PICTURE_MODE_SPEED` (`camerakit:ckPictureMode="speed"`), images will be captured by grabbing a single frame from the preview. This behavior is the same as SnapChat and Instagram. This method has a higher rate of motion blur but can be a better experience for users with slower cameras. +When you use `METHOD_STILL` (`camerakit:ckMethod="still"`), images will be captured by grabbing a single frame from the preview. This behavior is the same as SnapChat and Instagram. This method has a higher rate of motion blur but can be a better experience for users with slower cameras. [Insert GIF] ### Auto -When you use `PICTURE_MODE_AUTO` (`camerakit:ckPictureMode="speed"`), images will be first be captured using the [quality](#quality) method. If capture consistently takes a long amount of time, the picture mode will fallback to [speed](#speed). +When you use `METHOD_AUTO` (`camerakit:ckMethod="auto"`), images will be first be captured using the [standard](#standard) method. If capture consistently takes a long amount of time, the picture mode will fallback to [still](#still) capture. [Insert GIF] -## Tap To Focus +## Focus -Along with the always on auto-focus, you can enable tap to focus in your `CameraView`. See [`ckTapToFocus`](#cktaptofocus) for usage. You have the option of having it on with a visible focus marker, on with no marker, or off. +Along with the always on auto-focus, you can enable tap to focus in your `CameraView`. See [`ckFocus`](#ckFocus) for usage. You have the option of having it on with a visible focus marker, on with no marker, or off. [Insert GIF] diff --git a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java index 9e48cc94..0cab6593 100644 --- a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java +++ b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java @@ -11,6 +11,13 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import static com.flurgle.camerakit.CameraKit.Constants.FLASH_OFF; +import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_CONTINUOUS; +import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_OFF; +import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP; +import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STANDARD; +import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STILL; + @SuppressWarnings("deprecation") public class Camera1 extends CameraImpl { @@ -21,10 +28,22 @@ public class Camera1 extends CameraImpl { private Size mPreviewSize; private Size mCaptureSize; + private int mDisplayOrientation; + + @Facing private int mFacing; + + @Flash private int mFlash; - private boolean mContinuousFocus; - private int mDisplayOrientation; + + @Focus + private int mFocus; + + @Method + private int mMethod; + + @Zoom + private int mZoom; Camera1(CameraListener callback, PreviewImpl preview) { super(callback, preview); @@ -57,6 +76,11 @@ public class Camera1 extends CameraImpl { releaseCamera(); } + @Override + void setDisplayOrientation(int displayOrientation) { + this.mDisplayOrientation = displayOrientation; + } + @Override void setFacing(@Facing int facing) { int internalFacing = new ConstantMapper.Facing(facing).map(); @@ -81,7 +105,7 @@ public class Camera1 extends CameraImpl { @Override void setFlash(@Flash int flash) { - if (isCameraOpened()) { + if (mCameraParameters != null) { List flashes = mCameraParameters.getSupportedFlashModes(); String internalFlash = new ConstantMapper.Flash(flash).map(); if (flashes != null && flashes.contains(internalFlash)) { @@ -91,7 +115,7 @@ public class Camera1 extends CameraImpl { String currentFlash = new ConstantMapper.Flash(mFlash).map(); if (flashes == null || !flashes.contains(currentFlash)) { mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); - mFlash = CameraKit.Constants.FLASH_OFF; + mFlash = FLASH_OFF; } } @@ -102,61 +126,76 @@ public class Camera1 extends CameraImpl { } @Override - void setContinuousFocus(boolean continuousFocus) { - this.mContinuousFocus = continuousFocus; - if (mCameraParameters != null) { - final List modes = mCameraParameters.getSupportedFocusModes(); - if (mContinuousFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { - mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); - } else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { - mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); - } else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) { - mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); - } else { - mCameraParameters.setFocusMode(modes.get(0)); - } - } - } + void setFocus(@Focus int focus) { + this.mFocus = focus; + switch (focus) { + case FOCUS_CONTINUOUS: + if (mCameraParameters != null) { + final List modes = mCameraParameters.getSupportedFocusModes(); + if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { + mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + } else { + setFocus(FOCUS_OFF); + } + } + break; - @Override - void setDisplayOrientation(int displayOrientation) { - this.mDisplayOrientation = displayOrientation; - } + case FOCUS_TAP: + setFocus(FOCUS_CONTINUOUS); + break; - @Override - void focus() { - mCamera.autoFocus(null); + case FOCUS_OFF: + if (mCameraParameters != null) { + final List modes = mCameraParameters.getSupportedFocusModes(); + if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { + mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); + } else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) { + mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); + } else { + mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); + } + } + break; + } } @Override - void zoom(float percentZoom) { - + void setMethod(@Method int method) { + this.mMethod = method; } @Override - void captureStandard() { - mCamera.takePicture(null, null, null, new Camera.PictureCallback() { - @Override - public void onPictureTaken(byte[] data, Camera camera) { - mCameraListener.onPictureTaken(data); - camera.startPreview(); - } - }); + void setZoom(@Zoom int zoom) { + this.mZoom = zoom; } @Override - void captureStill() { - mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() { - @Override - public void onPreviewFrame(byte[] data, Camera camera) { - new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() { + void captureImage() { + switch (mMethod) { + case METHOD_STANDARD: + mCamera.takePicture(null, null, null, new Camera.PictureCallback() { @Override - public void onStillProcessed(final YuvImage yuv) { - mCameraListener.onPictureTaken(yuv); + public void onPictureTaken(byte[] data, Camera camera) { + mCameraListener.onPictureTaken(data); + camera.startPreview(); } - })).start(); - } - }); + }); + break; + + case METHOD_STILL: + mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() { + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() { + @Override + public void onStillProcessed(final YuvImage yuv) { + mCameraListener.onPictureTaken(yuv); + } + })).start(); + } + }); + break; + } } @Override @@ -297,7 +336,7 @@ public class Camera1 extends CameraImpl { + (mFacing == CameraKit.Constants.FACING_FRONT ? 180 : 0) ); - setContinuousFocus(mContinuousFocus); + setFocus(mFocus); setFlash(mFlash); mCamera.setParameters(mCameraParameters); diff --git a/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java b/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java index 3d01c0d3..419852f4 100644 --- a/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java +++ b/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java @@ -17,42 +17,37 @@ class Camera2 extends CameraImpl { } @Override - void setFacing(@Facing int facing) { - - } - - @Override - void setFlash(@Flash int flash) { + void setDisplayOrientation(int displayOrientation) { } @Override - void setContinuousFocus(boolean autoFocus) { + void setFacing(@Facing int facing) { } @Override - void setDisplayOrientation(int displayOrientation) { + void setFlash(@Flash int flash) { } @Override - void focus() { + void setFocus(@Focus int focus) { } @Override - void zoom(float percentZoom) { + void setMethod(@Method int method) { } @Override - void captureStandard() { + void setZoom(@Zoom int zoom) { } @Override - void captureStill() { + void captureImage() { } diff --git a/camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java b/camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java index ade7ca15..80e6b8c5 100644 --- a/camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java +++ b/camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java @@ -13,17 +13,15 @@ abstract class CameraImpl { abstract void start(); abstract void stop(); - abstract void setFacing(@Facing int facing); - abstract void setFlash(@Flash int flash); - abstract void setContinuousFocus(boolean autoFocus); - abstract void setDisplayOrientation(int displayOrientation); - abstract void focus(); - abstract void zoom(float percentZoom); - abstract void captureStandard(); - abstract void captureStill(); + abstract void setFacing(@Facing int facing); + abstract void setFlash(@Flash int flash); + abstract void setFocus(@Focus int focus); + abstract void setMethod(@Method int method); + abstract void setZoom(@Zoom int zoom); + abstract void captureImage(); abstract void startVideo(); abstract void endVideo(); diff --git a/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java b/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java index c08abbab..a580eb92 100644 --- a/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java +++ b/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java @@ -13,6 +13,8 @@ public class CameraKit { public static class Constants { + public static final int PERMISSION_REQUEST_CAMERA = 16; + public static final int FACING_BACK = 0; public static final int FACING_FRONT = 1; @@ -20,15 +22,31 @@ public class CameraKit { public static final int FLASH_ON = 1; public static final int FLASH_AUTO = 2; - public static final int CAPTURE_MODE_STANDARD = 0; - public static final int CAPTURE_MODE_STILL = 1; - public static final int PICTURE_MODE_AUTO = 2; + public static final int METHOD_STANDARD = 0; + public static final int METHOD_STILL = 1; + public static final int METHOD_AUTO = 2; + + public static final int FOCUS_OFF = 0; + public static final int FOCUS_CONTINUOUS = 1; + public static final int FOCUS_TAP = 2; - public static final int TAP_TO_FOCUS_VISIBLE = 0; - public static final int TAP_TO_FOCUS_INVISIBLE = 1; - public static final int TAP_TO_FOCUS_OFF = 2; + public static final int ZOOM_OFF = 0; + public static final int ZOOM_PINCH = 1; } + static class Defaults { + + static final int DEFAULT_FACING = Constants.FACING_BACK; + static final int DEFAULT_FLASH = Constants.FLASH_OFF; + static final int DEFAULT_FOCUS = Constants.FOCUS_OFF; + static final int DEFAULT_METHOD = Constants.METHOD_STANDARD; + static final int DEFAULT_ZOOM = Constants.ZOOM_OFF; + + static final int DEFAULT_JPEG_QUALITY = 100; + static final boolean DEFAULT_CROP_OUTPUT = false; + static final boolean DEFAULT_ADJUST_VIEW_BOUNDS = false; + + } } diff --git a/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java b/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java index a749b2a4..4ddae2d1 100644 --- a/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java +++ b/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java @@ -8,64 +8,47 @@ import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.YuvImage; -import android.os.Parcel; -import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.hardware.display.DisplayManagerCompat; -import android.support.v4.os.ParcelableCompat; -import android.support.v4.os.ParcelableCompatCreatorCallbacks; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.Display; -import android.view.MotionEvent; -import android.view.View; import android.widget.FrameLayout; import java.io.ByteArrayOutputStream; import java.io.File; -import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STANDARD; -import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STILL; import static com.flurgle.camerakit.CameraKit.Constants.FACING_BACK; import static com.flurgle.camerakit.CameraKit.Constants.FACING_FRONT; import static com.flurgle.camerakit.CameraKit.Constants.FLASH_AUTO; import static com.flurgle.camerakit.CameraKit.Constants.FLASH_OFF; import static com.flurgle.camerakit.CameraKit.Constants.FLASH_ON; -import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_VISIBLE; +import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STANDARD; public class CameraView extends FrameLayout { - private static final int PERMISSION_REQUEST_CAMERA = 16; - private static final int DEFAULT_CAPTURE_SIZE = -1; - private static final int DEFAULT_JPEG_COMPRESSION = 100; - @Facing private int mFacing; @Flash private int mFlash; - @TapToFocus - private int mTapToFocus; - - @CaptureMode - private int mCaptureMode; - - private boolean mCropOutput; - - private boolean mContinuousFocus; + @Focus + private int mFocus; - private float mCaptureSize; + @Method + private int mMethod; - private int mJpegCompression; + @Zoom + private int mZoom; + private int mJpegQuality; + private boolean mCropOutput; private boolean mAdjustViewBounds; - private boolean mWaitingForPermission; - private CameraListenerMiddleWare mCameraListener; private DisplayOrientationDetector mDisplayOrientationDetector; @@ -79,8 +62,6 @@ public class CameraView extends FrameLayout { @SuppressWarnings("all") public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); - - if (attrs != null) { TypedArray a = context.getTheme().obtainStyledAttributes( attrs, @@ -88,15 +69,15 @@ public class CameraView extends FrameLayout { 0, 0); try { - mFacing = a.getInteger(R.styleable.CameraView_ckFacing, FACING_BACK); - mFlash = a.getInteger(R.styleable.CameraView_ckFlash, FLASH_OFF); - mTapToFocus = a.getInteger(R.styleable.CameraView_ckTapToFocus, TAP_TO_FOCUS_VISIBLE); - mCaptureMode = a.getInteger(R.styleable.CameraView_ckCaptureMode, CAPTURE_MODE_STANDARD); - mCropOutput = a.getBoolean(R.styleable.CameraView_ckCropOutput, false); - mContinuousFocus = a.getBoolean(R.styleable.CameraView_ckContinuousFocus, true); - mCaptureSize = a.getFloat(R.styleable.CameraView_ckCaptureSize, DEFAULT_CAPTURE_SIZE); - mJpegCompression = a.getInteger(R.styleable.CameraView_ckJpegCompression, DEFAULT_JPEG_COMPRESSION); - mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false); + mFacing = a.getInteger(R.styleable.CameraView_ckFacing, CameraKit.Defaults.DEFAULT_FACING); + mFlash = a.getInteger(R.styleable.CameraView_ckFlash, CameraKit.Defaults.DEFAULT_FLASH); + mFocus = a.getInteger(R.styleable.CameraView_ckFocus, CameraKit.Defaults.DEFAULT_FOCUS); + mMethod = a.getInteger(R.styleable.CameraView_ckMethod, CameraKit.Defaults.DEFAULT_METHOD); + mZoom = a.getInteger(R.styleable.CameraView_ckZoom, CameraKit.Defaults.DEFAULT_ZOOM); + + mJpegQuality = a.getInteger(R.styleable.CameraView_ckJpegQuality, CameraKit.Defaults.DEFAULT_JPEG_QUALITY); + mCropOutput = a.getBoolean(R.styleable.CameraView_ckCropOutput, CameraKit.Defaults.DEFAULT_CROP_OUTPUT); + mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, CameraKit.Defaults.DEFAULT_ADJUST_VIEW_BOUNDS); } finally { a.recycle(); } @@ -109,11 +90,9 @@ public class CameraView extends FrameLayout { setFacing(mFacing); setFlash(mFlash); - setCaptureMode(mCaptureMode); - setCropOutput(mCropOutput); - setTapToFocus(mTapToFocus); - setContinuousFocus(mContinuousFocus); - setCaptureSize(mCaptureSize); + setFocus(mFocus); + setMethod(mMethod); + setZoom(mZoom); mDisplayOrientationDetector = new DisplayOrientationDetector(context) { @Override @@ -140,30 +119,34 @@ public class CameraView extends FrameLayout { } @Override - protected Parcelable onSaveInstanceState() { - SavedState state = new SavedState(super.onSaveInstanceState()); - state.facing = mFacing; - state.flash = mFlash; - return state; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (!(state instanceof SavedState)) { - super.onRestoreInstanceState(state); - return; + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mAdjustViewBounds) { + Size previewSize = getPreviewSize(); + if (getLayoutParams().width == LayoutParams.WRAP_CONTENT) { + int height = MeasureSpec.getSize(heightMeasureSpec); + float ratio = (float) height / (float) previewSize.getWidth(); + int width = (int) (previewSize.getHeight() * ratio); + super.onMeasure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + heightMeasureSpec + ); + } else if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) { + int width = MeasureSpec.getSize(widthMeasureSpec); + float ratio = (float) width / (float) previewSize.getHeight(); + int height = (int) (previewSize.getWidth() * ratio); + super.onMeasure( + widthMeasureSpec, + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + } + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - - SavedState ss = (SavedState) state; - super.onRestoreInstanceState(ss.getSuperState()); - setFacing(ss.facing); - setFlash(ss.flash); } public void start() { int permissionCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { - mWaitingForPermission = false; mCameraImpl.start(); } else { requestCameraPermission(); @@ -179,6 +162,34 @@ public class CameraView extends FrameLayout { mCameraImpl.setFacing(facing); } + public void setFlash(@Flash int flash) { + this.mFlash = flash; + mCameraImpl.setFlash(flash); + } + + public void setFocus(@Focus int focus) { + this.mFocus = focus; + mCameraImpl.setFocus(mFocus); + } + + public void setMethod(@Method int method) { + this.mMethod = method; + mCameraImpl.setMethod(mMethod); + } + + public void setZoom(@Zoom int zoom) { + this.mZoom = zoom; + mCameraImpl.setZoom(mZoom); + } + + public void setJpegQuality(int jpegQuality) { + this.mJpegQuality = jpegQuality; + } + + public void setCropOutput(boolean cropOutput) { + this.mCropOutput = cropOutput; + } + @Facing public int toggleFacing() { switch (mFacing) { @@ -194,11 +205,6 @@ public class CameraView extends FrameLayout { return mFacing; } - public void setFlash(@Flash int flash) { - this.mFlash = flash; - mCameraImpl.setFlash(flash); - } - @Flash public int toggleFlash() { switch (mFlash) { @@ -218,50 +224,12 @@ public class CameraView extends FrameLayout { return mFlash; } - public void setCaptureMode(@CaptureMode int captureMode) { - this.mCaptureMode = captureMode; - } - - @CaptureMode - public int getCaptureMode() { - return mCaptureMode; - } - - public void setCropOutput(boolean cropOutput) { - this.mCropOutput = cropOutput; - } - - public void setTapToFocus(@TapToFocus int tapToFocus) { - this.mTapToFocus = tapToFocus; - if (tapToFocus == CameraKit.Constants.TAP_TO_FOCUS_OFF) { - mPreviewImpl.getView().setOnTouchListener(null); - } else { - mPreviewImpl.getView().setOnTouchListener(mTapToFocusOnTouchListener); - } - } - - public void setContinuousFocus(boolean continuousFocus) { - this.mContinuousFocus = continuousFocus; - mCameraImpl.setContinuousFocus(continuousFocus); - } - - public void setCaptureSize(float captureSize) { - this.mCaptureSize = captureSize; - } - public void setCameraListener(CameraListener cameraListener) { this.mCameraListener.setCameraListener(cameraListener); } - public void capturePicture() { - switch (mCaptureMode) { - case CAPTURE_MODE_STANDARD: - mCameraImpl.captureStandard(); - break; - case CAPTURE_MODE_STILL: - mCameraImpl.captureStill(); - break; - } + public void captureImage() { + mCameraImpl.captureImage(); } public void startRecordingVideo() { @@ -291,74 +259,11 @@ public class CameraView extends FrameLayout { } if (activity != null) { - ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, PERMISSION_REQUEST_CAMERA); - mWaitingForPermission = true; - } - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - if (mWaitingForPermission) { - if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { - start(); - } - } - } - - private OnTouchListener mTapToFocusOnTouchListener = new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - mCameraImpl.focus(); - } - - return false; - } - - }; - - - protected static class SavedState extends BaseSavedState { - - @Facing - private int facing; - - @Flash - private int flash; - - @SuppressWarnings("WrongConstant") - public SavedState(Parcel source, ClassLoader loader) { - super(source); - facing = source.readInt(); - flash = source.readInt(); - } - - public SavedState(Parcelable superState) { - super(superState); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(facing); - out.writeInt(flash); + ActivityCompat.requestPermissions( + activity, + new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, + CameraKit.Constants.PERMISSION_REQUEST_CAMERA); } - - public static final Parcelable.Creator CREATOR = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() { - - @Override - public SavedState createFromParcel(Parcel in, ClassLoader loader) { - return new SavedState(in, loader); - } - - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - - }); - } private class CameraListenerMiddleWare extends CameraListener { @@ -381,10 +286,10 @@ public class CameraView extends FrameLayout { public void onPictureTaken(byte[] jpeg) { super.onPictureTaken(jpeg); if (mCropOutput) { - int width = mCaptureMode == CAPTURE_MODE_STANDARD ? mCameraImpl.getCaptureResolution().getWidth() : mCameraImpl.getPreviewResolution().getWidth(); - int height = mCaptureMode == CAPTURE_MODE_STANDARD ? mCameraImpl.getCaptureResolution().getHeight() : mCameraImpl.getPreviewResolution().getHeight(); + int width = mMethod == METHOD_STANDARD ? mCameraImpl.getCaptureResolution().getWidth() : mCameraImpl.getPreviewResolution().getWidth(); + int height = mMethod == METHOD_STANDARD ? mCameraImpl.getCaptureResolution().getHeight() : mCameraImpl.getPreviewResolution().getHeight(); AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight()); - getCameraListener().onPictureTaken(new CenterCrop(jpeg, outputRatio, mJpegCompression).getJpeg()); + getCameraListener().onPictureTaken(new CenterCrop(jpeg, outputRatio, mJpegQuality).getJpeg()); } else { getCameraListener().onPictureTaken(jpeg); } @@ -395,10 +300,10 @@ public class CameraView extends FrameLayout { super.onPictureTaken(yuv); if (mCropOutput) { AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight()); - getCameraListener().onPictureTaken(new CenterCrop(yuv, outputRatio, mJpegCompression).getJpeg()); + getCameraListener().onPictureTaken(new CenterCrop(yuv, outputRatio, mJpegQuality).getJpeg()); } else { ByteArrayOutputStream out = new ByteArrayOutputStream(); - yuv.compressToJpeg(new Rect(0, 0, yuv.getWidth(), yuv.getHeight()), mJpegCompression, out); + yuv.compressToJpeg(new Rect(0, 0, yuv.getWidth(), yuv.getHeight()), mJpegQuality, out); getCameraListener().onPictureTaken(out.toByteArray()); } } diff --git a/camerakit/src/main/res/values/attrs.xml b/camerakit/src/main/res/values/attrs.xml index c16347e0..a1029817 100644 --- a/camerakit/src/main/res/values/attrs.xml +++ b/camerakit/src/main/res/values/attrs.xml @@ -14,27 +14,33 @@ - - - - - + + + - + + + - + + - - - - + + - - + + + - + + + + + + + diff --git a/camerakit/src/main/types/com/flurgle/camerakit/Focus.java b/camerakit/src/main/types/com/flurgle/camerakit/Focus.java index 790932fc..e186fcd2 100644 --- a/camerakit/src/main/types/com/flurgle/camerakit/Focus.java +++ b/camerakit/src/main/types/com/flurgle/camerakit/Focus.java @@ -5,11 +5,11 @@ import android.support.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_INVISIBLE; -import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_OFF; -import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_VISIBLE; +import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP; +import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_OFF; +import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_CONTINUOUS; @Retention(RetentionPolicy.SOURCE) -@IntDef({TAP_TO_FOCUS_VISIBLE, TAP_TO_FOCUS_INVISIBLE, TAP_TO_FOCUS_OFF}) +@IntDef({FOCUS_CONTINUOUS, FOCUS_TAP, FOCUS_OFF}) public @interface Focus { } \ No newline at end of file diff --git a/camerakit/src/main/types/com/flurgle/camerakit/Method.java b/camerakit/src/main/types/com/flurgle/camerakit/Method.java index e340286c..ba6d85b1 100644 --- a/camerakit/src/main/types/com/flurgle/camerakit/Method.java +++ b/camerakit/src/main/types/com/flurgle/camerakit/Method.java @@ -5,10 +5,10 @@ import android.support.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STANDARD; -import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STILL; +import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STANDARD; +import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STILL; @Retention(RetentionPolicy.SOURCE) -@IntDef({CAPTURE_MODE_STANDARD, CAPTURE_MODE_STILL}) +@IntDef({METHOD_STANDARD, METHOD_STILL}) public @interface Method { } diff --git a/camerakit/src/main/types/com/flurgle/camerakit/Zoom.java b/camerakit/src/main/types/com/flurgle/camerakit/Zoom.java index 5bb16513..57f77116 100644 --- a/camerakit/src/main/types/com/flurgle/camerakit/Zoom.java +++ b/camerakit/src/main/types/com/flurgle/camerakit/Zoom.java @@ -1,8 +1,14 @@ package com.flurgle.camerakit; -/** - * Created by dylanmcintyre on 2/21/17. - */ +import android.support.annotation.IntDef; -public class Zoom { +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import static com.flurgle.camerakit.CameraKit.Constants.ZOOM_OFF; +import static com.flurgle.camerakit.CameraKit.Constants.ZOOM_PINCH; + +@Retention(RetentionPolicy.SOURCE) +@IntDef({ZOOM_OFF, ZOOM_PINCH}) +public @interface Zoom { } diff --git a/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java b/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java index 0dabfaf8..59d1cc3c 100644 --- a/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java +++ b/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java @@ -136,7 +136,7 @@ public class MainActivity extends AppCompatActivity { startActivity(intent); } }); - camera.capturePicture(); + camera.captureImage(); } @OnClick(R.id.captureVideo) @@ -191,10 +191,10 @@ public class MainActivity extends AppCompatActivity { RadioGroup.OnCheckedChangeListener captureModeChangedListener = new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { - camera.setCaptureMode( + camera.setMethod( checkedId == R.id.modeCaptureQuality ? - CameraKit.Constants.CAPTURE_MODE_STANDARD : - CameraKit.Constants.CAPTURE_MODE_STILL + CameraKit.Constants.METHOD_STANDARD : + CameraKit.Constants.METHOD_STILL ); Toast.makeText(MainActivity.this, "Picture capture set to" + (checkedId == R.id.modeCaptureQuality ? " quality!" : " speed!"), Toast.LENGTH_SHORT).show(); @@ -215,12 +215,12 @@ public class MainActivity extends AppCompatActivity { RadioGroup.OnCheckedChangeListener tapToFocusModeChangedListener = new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { - camera.setTapToFocus( + camera.setFocus( checkedId == R.id.modeTapToFocusVisible ? - CameraKit.Constants.TAP_TO_FOCUS_VISIBLE : + CameraKit.Constants.FOCUS_CONTINUOUS : checkedId == R.id.modeTapToFocusInvisible ? - CameraKit.Constants.TAP_TO_FOCUS_INVISIBLE : - CameraKit.Constants.TAP_TO_FOCUS_OFF + CameraKit.Constants.FOCUS_TAP : + CameraKit.Constants.FOCUS_OFF ); Toast.makeText(MainActivity.this, "Tap to focus is" + (checkedId == R.id.modeTapToFocusOff ? " off!" : (checkedId == R.id.modeTapToFocusVisible) ? " on and visible!" : " on and invisible!"), Toast.LENGTH_SHORT).show(); diff --git a/demo/src/main/res/layout/activity_main.xml b/demo/src/main/res/layout/activity_main.xml index 6643a168..bb4e82c7 100644 --- a/demo/src/main/res/layout/activity_main.xml +++ b/demo/src/main/res/layout/activity_main.xml @@ -19,11 +19,11 @@ android:layout_height="500dp" android:layout_gravity="center_horizontal" app:ckCaptureMode="standard" - app:ckContinuousFocus="true" app:ckCropOutput="false" app:ckFacing="back" app:ckFlash="off" - app:ckTapToFocus="visible" /> + app:ckFocus="continuous" + app:ckJpegQuality="100" />