Tap to focus setup

pull/1/head
Dylan McIntyre 8 years ago
parent 5d4b8fd90e
commit bb495dc278
  1. 21
      README.md
  2. 43
      camerakit/src/main/java/com/flurgle/camerakit/Camera2.java
  3. 25
      camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java
  4. 43
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  5. 15
      camerakit/src/main/java/com/flurgle/camerakit/Constants.java
  6. 6
      camerakit/src/main/res/values/attrs.xml
  7. 18
      demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java
  8. 2
      demo/src/main/res/layout/activity_main.xml

@ -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

@ -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);
// }
// }
}
};

@ -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;
}
}

@ -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);

@ -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;
}

@ -22,6 +22,12 @@
<attr name="ckCropOutput" format="boolean" />
<attr name="ckTapToFocus" format="enum">
<enum name="on" value="0" />
<enum name="invisible" value="1" />
<enum name="off" value="2" />
</attr>
<attr name="android:adjustViewBounds" />
</declare-styleable>

@ -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();

@ -21,7 +21,7 @@
app:ckCropOutput="true"
app:ckFacing="back"
app:ckFlash="off"
app:ckPictureMode="quality" />
app:ckPictureMode="speed" />
<LinearLayout
android:layout_width="match_parent"

Loading…
Cancel
Save