diff --git a/README.md b/README.md index 810a66e4..1b65d4b0 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Try out all the unique features using the CameraKit Demo from the Google Play st - [`ckFacing`](#ckfacing) - [`ckFlash`](#ckflash) - [`ckPictureMode`](#ckpicturemode) + - [`ckTapToFocus`](#cktaptofocus) - [Capturing Images](#capturing-images) - [Capturing Video](#capturing-video) - [Automatic Permissions Behavior](#automatic-permissions-behavior) @@ -43,6 +44,7 @@ Try out all the unique features using the CameraKit Demo from the Google Play st - `PICTURE_MODE_QUALITY`: an image captured normally using the camera APIs. - `PICTURE_MODE_SPEED`: 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. ## Setup @@ -119,7 +121,8 @@ camera.setCameraListener(new CameraListener() { camerakit:ckCropOutput="true" camerakit:ckFacing="back" camerakit:ckFlash="off" - camerakit:ckPictureMode="quality" /> + camerakit:ckPictureMode="quality" + camerakit:ckTapToFocus="on" /> ``` #### `ckCropOutput` @@ -148,6 +151,14 @@ camera.setCameraListener(new CameraListener() { #### `ckPictureMode` +| Value | Description | +| --------------| -------------| +| `on` | 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. | + +#### `ckTapToFocus` + | Value | Description | | --------------| -------------| | `quality` | Use normal Android Camera API image capturing. | @@ -238,12 +249,18 @@ When you use `PICTURE_MODE_SPEED` (`camerakit:ckPictureMode="speed"`), images wi [Insert GIF] -## Auto +### 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). [Insert GIF] +## Tap To 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. + +[Insert GIF] + ## Credits Dylan McIntyre diff --git a/camerakit/src/main/java/com/flurgle/camerakit/Camera2.java b/camerakit/src/main/java/com/flurgle/camerakit/Camera2.java index 437c41c1..11d74271 100644 --- a/camerakit/src/main/java/com/flurgle/camerakit/Camera2.java +++ b/camerakit/src/main/java/com/flurgle/camerakit/Camera2.java @@ -22,7 +22,6 @@ import android.util.SparseIntArray; import android.view.Surface; import android.view.View; -import java.nio.ByteBuffer; import java.util.Arrays; import java.util.SortedSet; import java.util.TreeSet; @@ -37,8 +36,8 @@ public class Camera2 extends CameraViewImpl { private static final SparseIntArray INTERNAL_FACINGS = new SparseIntArray(); static { - INTERNAL_FACINGS.put(Constants.FACING_BACK, CameraCharacteristics.LENS_FACING_BACK); - INTERNAL_FACINGS.put(Constants.FACING_FRONT, CameraCharacteristics.LENS_FACING_FRONT); + INTERNAL_FACINGS.put(CameraKit.Constants.FACING_BACK, CameraCharacteristics.LENS_FACING_BACK); + INTERNAL_FACINGS.put(CameraKit.Constants.FACING_FRONT, CameraCharacteristics.LENS_FACING_FRONT); } private CameraManager mCameraManager; @@ -166,7 +165,7 @@ public class Camera2 extends CameraViewImpl { @Override void capturePicture() { - if (mFacing == INTERNAL_FACINGS.get(Constants.FACING_BACK)) { + if (mFacing == INTERNAL_FACINGS.get(CameraKit.Constants.FACING_BACK)) { lockFocus(); } else { captureStillPicture(); @@ -198,15 +197,15 @@ public class Camera2 extends CameraViewImpl { void updateFlash(CaptureRequest.Builder builder) { switch (mFlash) { - case Constants.FLASH_OFF: + case CameraKit.Constants.FLASH_OFF: builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; - case Constants.FLASH_ON: + case CameraKit.Constants.FLASH_ON: builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; - case Constants.FLASH_AUTO: + case CameraKit.Constants.FLASH_AUTO: builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; @@ -259,7 +258,7 @@ public class Camera2 extends CameraViewImpl { } // The operation can reach here when the only camera device is an external one. // We treat it as facing back. - mFacing = Constants.FACING_BACK; + mFacing = CameraKit.Constants.FACING_BACK; return true; } catch (CameraAccessException e) { throw new RuntimeException("Failed to get a list of camera devices", e); @@ -308,7 +307,7 @@ public class Camera2 extends CameraViewImpl { Size previewSize = getOptimalPreviewSize(); AspectRatio aspectRatio = AspectRatio.of(previewSize.getWidth(), previewSize.getHeight()); Size bestSize = findSizeClosestTo(1500000, aspectRatio, mCaptureSizes); - mImageReader = ImageReader.newInstance(bestSize.getWidth(), bestSize.getHeight(), ImageFormat.JPEG, 1); + mImageReader = ImageReader.newInstance(bestSize.getWidth(), bestSize.getHeight(), ImageFormat.YUV_420_888, 3); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); } @@ -377,6 +376,7 @@ public class Camera2 extends CameraViewImpl { try { mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); + mPreviewRequestBuilder.addTarget(mImageReader.getSurface()); mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), mSessionCallback, mBackgroundHandler); } catch (CameraAccessException e) { throw new RuntimeException("Failed to start camera session"); @@ -406,7 +406,7 @@ public class Camera2 extends CameraViewImpl { int sensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, (sensorOrientation + - mDisplayOrientation * (mFacing == Constants.FACING_FRONT ? 1 : -1) + + mDisplayOrientation * (mFacing == CameraKit.Constants.FACING_FRONT ? 1 : -1) + 360) % 360); // Stop preview and capture a still picture. mCaptureSession.stopRepeating(); @@ -524,15 +524,20 @@ public class Camera2 extends CameraViewImpl { @Override public void onImageAvailable(ImageReader reader) { - try (Image image = reader.acquireNextImage()) { - Image.Plane[] planes = image.getPlanes(); - if (planes.length > 0) { - ByteBuffer buffer = planes[0].getBuffer(); - byte[] data = new byte[buffer.remaining()]; - buffer.get(data); - getCameraListener().onPictureTaken(data); - } - } + Image image = reader.acquireLatestImage(); + // Process the image + image.close(); + +// try (Image image = reader.acquireNextImage()) { +// image.close(); +// Image.Plane[] planes = image.getPlanes(); +// if (planes.length > 0) { +// ByteBuffer buffer = planes[0].getBuffer(); +// byte[] data = new byte[buffer.remaining()]; +// buffer.get(data); +// //getCameraListener().onPictureTaken(data); +// } +// } } }; diff --git a/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java b/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java new file mode 100644 index 00000000..69674ab3 --- /dev/null +++ b/camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java @@ -0,0 +1,25 @@ +package com.flurgle.camerakit; + +public class CameraKit { + + public static class Constants { + + public static final int FACING_BACK = 0; + public static final int FACING_FRONT = 1; + + public static final int FLASH_OFF = 0; + public static final int FLASH_ON = 1; + public static final int FLASH_AUTO = 2; + + public static final int PICTURE_MODE_QUALITY = 0; + public static final int PICTURE_MODE_SPEED = 1; + public static final int PICTURE_MODE_AUTO = 2; + + public static final int TAP_TO_FOCUS_ON = 0; + public static final int TAP_TO_FOCUS_INVISIBLE = 1; + public static final int TAP_TO_FOCUS_OFF = 2; + + } + + +} diff --git a/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java b/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java index ad213461..2bc6278b 100644 --- a/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java +++ b/camerakit/src/main/java/com/flurgle/camerakit/CameraView.java @@ -27,33 +27,30 @@ import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import static com.flurgle.camerakit.CameraKit.Constants.*; + public class CameraView extends FrameLayout { private static final int PERMISSION_REQUEST_CAMERA = 16; - public static final int FACING_BACK = Constants.FACING_BACK; - public static final int FACING_FRONT = Constants.FACING_FRONT; - @IntDef({FACING_BACK, FACING_FRONT}) @Retention(RetentionPolicy.SOURCE) - public @interface Facing { + @interface Facing { } - public static final int FLASH_OFF = Constants.FLASH_OFF; - public static final int FLASH_ON = Constants.FLASH_ON; - public static final int FLASH_AUTO = Constants.FLASH_AUTO; - @Retention(RetentionPolicy.SOURCE) @IntDef({FLASH_OFF, FLASH_ON, FLASH_AUTO}) - public @interface Flash { + @interface Flash { } - public static final int PICTURE_MODE_QUALITY = Constants.PICTURE_MODE_QUALITY; - public static final int PICTURE_MODE_SPEED = Constants.PICTURE_MODE_SPEED; - @Retention(RetentionPolicy.SOURCE) @IntDef({PICTURE_MODE_QUALITY, PICTURE_MODE_SPEED}) - public @interface PictureMode { + @interface PictureMode { + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({TAP_TO_FOCUS_ON, TAP_TO_FOCUS_INVISIBLE, TAP_TO_FOCUS_OFF}) + @interface TapToFocus { } private int mFacing; @@ -66,6 +63,8 @@ public class CameraView extends FrameLayout { private boolean mCropOutput; + private int mTapToFocus; + private boolean mAdjustViewBounds; private boolean mWaitingForPermission; @@ -90,21 +89,25 @@ public class CameraView extends FrameLayout { int attr = a.getIndex(i); if (attr == R.styleable.CameraView_ckFacing) { - mFacing = a.getInteger(R.styleable.CameraView_ckFacing, 0); + mFacing = a.getInteger(R.styleable.CameraView_ckFacing, FACING_BACK); } if (attr == R.styleable.CameraView_ckFlash) { - mFlash = a.getInteger(R.styleable.CameraView_ckFlash, 0); + mFlash = a.getInteger(R.styleable.CameraView_ckFlash, FLASH_OFF); } if (attr == R.styleable.CameraView_ckPictureMode) { - mPictureMode = a.getInteger(R.styleable.CameraView_ckPictureMode, 0); + mPictureMode = a.getInteger(R.styleable.CameraView_ckPictureMode, PICTURE_MODE_QUALITY); } if (attr == R.styleable.CameraView_ckCropOutput) { mCropOutput = a.getBoolean(R.styleable.CameraView_ckCropOutput, false); } + if (attr == R.styleable.CameraView_ckTapToFocus) { + mTapToFocus = a.getInteger(R.styleable.CameraView_ckTapToFocus, TAP_TO_FOCUS_ON); + } + if (attr == R.styleable.CameraView_android_adjustViewBounds) { mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false); } @@ -229,6 +232,10 @@ public class CameraView extends FrameLayout { this.mCropOutput = cropOutput; } + public void setTapToFocus(@TapToFocus int tapToFocus) { + this.mTapToFocus = tapToFocus; + } + public void setCameraListener(CameraListener cameraListener) { this.mCameraListener = new CameraListenerMiddleWare(cameraListener); mCameraImpl.setCameraListener(mCameraListener); @@ -348,6 +355,10 @@ public class CameraView extends FrameLayout { Bitmap bitmap = BitmapFactory.decodeByteArray(picture, 0, picture.length); int previewWidth = mCameraImpl.mPreview.getWidth(); int previewHeight = mCameraImpl.mPreview.getWidth(); + + AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight()); + AspectRatio previewRatio = AspectRatio.of(previewWidth, previewHeight); + mCameraListener.onPictureTaken(picture); } else { mCameraListener.onPictureTaken(picture); diff --git a/camerakit/src/main/java/com/flurgle/camerakit/Constants.java b/camerakit/src/main/java/com/flurgle/camerakit/Constants.java deleted file mode 100644 index 7e203fdb..00000000 --- a/camerakit/src/main/java/com/flurgle/camerakit/Constants.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.flurgle.camerakit; - -public class Constants { - - public static final int FACING_BACK = 0; - public static final int FACING_FRONT = 1; - - public static final int FLASH_OFF = 0; - public static final int FLASH_ON = 1; - public static final int FLASH_AUTO = 2; - - public static final int PICTURE_MODE_QUALITY = 0; - public static final int PICTURE_MODE_SPEED = 1; - -} diff --git a/camerakit/src/main/res/values/attrs.xml b/camerakit/src/main/res/values/attrs.xml index 7328910a..f646eda2 100644 --- a/camerakit/src/main/res/values/attrs.xml +++ b/camerakit/src/main/res/values/attrs.xml @@ -22,6 +22,12 @@ + + + + + + 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 d4a61c54..a6496705 100644 --- a/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java +++ b/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java @@ -14,9 +14,9 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; +import com.flurgle.camerakit.CameraKit; import com.flurgle.camerakit.CameraListener; import com.flurgle.camerakit.CameraView; -import com.flurgle.camerakit.Constants; import butterknife.BindView; import butterknife.ButterKnife; @@ -57,7 +57,7 @@ public class MainActivity extends AppCompatActivity { @BindView(R.id.height) EditText height; - int pictureMode = Constants.PICTURE_MODE_QUALITY; + int pictureMode = CameraKit.Constants.PICTURE_MODE_QUALITY; boolean blockInvalidation; @@ -116,11 +116,11 @@ public class MainActivity extends AppCompatActivity { @OnClick(R.id.toggleCamera) void toggleCamera() { switch (camera.toggleFacing()) { - case Constants.FACING_BACK: + case CameraKit.Constants.FACING_BACK: Toast.makeText(this, "Switched to back camera!", Toast.LENGTH_SHORT).show(); break; - case Constants.FACING_FRONT: + case CameraKit.Constants.FACING_FRONT: Toast.makeText(this, "Switched to front camera!", Toast.LENGTH_SHORT).show(); break; } @@ -129,15 +129,15 @@ public class MainActivity extends AppCompatActivity { @OnClick(R.id.toggleFlash) void toggleFlash() { switch (camera.toggleFlash()) { - case Constants.FLASH_ON: + case CameraKit.Constants.FLASH_ON: Toast.makeText(this, "Flash on!", Toast.LENGTH_SHORT).show(); break; - case Constants.FLASH_OFF: + case CameraKit.Constants.FLASH_OFF: Toast.makeText(this, "Flash off!", Toast.LENGTH_SHORT).show(); break; - case Constants.FLASH_AUTO: + case CameraKit.Constants.FLASH_AUTO: Toast.makeText(this, "Flash auto!", Toast.LENGTH_SHORT).show(); break; } @@ -147,7 +147,7 @@ public class MainActivity extends AppCompatActivity { void modeQuality(CompoundButton buttonCompat, boolean checked) { modeSpeed.setChecked(false); if (checked) { - camera.setPictureMode(CameraView.PICTURE_MODE_QUALITY); + camera.setPictureMode(CameraKit.Constants.PICTURE_MODE_QUALITY); } invalidateParameters(); @@ -157,7 +157,7 @@ public class MainActivity extends AppCompatActivity { void modeSpeed(CompoundButton buttonCompat, boolean checked) { modeQuality.setChecked(false); if (checked) { - camera.setPictureMode(CameraView.PICTURE_MODE_SPEED); + camera.setPictureMode(CameraKit.Constants.PICTURE_MODE_SPEED); } invalidateParameters(); diff --git a/demo/src/main/res/layout/activity_main.xml b/demo/src/main/res/layout/activity_main.xml index 3fd3cf27..fde00098 100644 --- a/demo/src/main/res/layout/activity_main.xml +++ b/demo/src/main/res/layout/activity_main.xml @@ -21,7 +21,7 @@ app:ckCropOutput="true" app:ckFacing="back" app:ckFlash="off" - app:ckPictureMode="quality" /> + app:ckPictureMode="speed" />