Add generic touch to auto focus (not positoned)

pull/1/head
Dylan McIntyre 8 years ago
parent 5b62096b19
commit 328552e386
  1. 54
      camerakit/src/main/java/com/flurgle/camerakit/Camera1.java
  2. 23
      camerakit/src/main/java/com/flurgle/camerakit/CameraImpl.java
  3. 71
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  4. 32
      camerakit/src/main/java/com/flurgle/camerakit/PreviewImpl.java
  5. 2
      camerakit/src/main/java/com/flurgle/camerakit/types/Facing.java
  6. 2
      camerakit/src/main/java/com/flurgle/camerakit/types/Flash.java
  7. 2
      camerakit/src/main/java/com/flurgle/camerakit/types/PictureMode.java
  8. 2
      camerakit/src/main/java/com/flurgle/camerakit/types/TapToFocus.java
  9. 83
      camerakit/src/main/java/com/flurgle/camerakit/utils/AspectRatio.java
  10. 7
      camerakit/src/main/java/com/flurgle/camerakit/utils/DisplayOrientationDetector.java
  11. 1
      camerakit/src/main/java/com/flurgle/camerakit/utils/Size.java
  12. 19
      camerakit/src/main/java/com/flurgle/camerakit/utils/YuvUtils.java
  13. 3
      demo/src/main/res/layout/activity_main.xml

@ -6,6 +6,7 @@ import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.util.SparseArrayCompat;
import android.view.SurfaceHolder;
@ -19,7 +20,7 @@ import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public class Camera1 extends CameraViewImpl {
public class Camera1 extends CameraImpl {
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>();
static {
@ -28,10 +29,10 @@ public class Camera1 extends CameraViewImpl {
FLASH_MODES.put(CameraKit.Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
}
private static File VIDEO_FILE;
private File mVideoFile;
private int mCameraId;
Camera mCamera;
private Camera mCamera;
private Camera.Parameters mCameraParameters;
private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
@ -46,8 +47,16 @@ public class Camera1 extends CameraViewImpl {
private MediaRecorder mMediaRecorder;
Camera1(CameraListener callback, PreviewImpl preview) {
super(callback, preview);
private CameraListener mCameraListener;
Camera1(@NonNull CameraListener cameraListener, @NonNull PreviewImpl preview) {
super(cameraListener, preview);
this.mCameraListener = cameraListener;
this.mPreviewSizes = new TreeSet<>();
this.mCaptureSizes = new TreeSet<>();
this.mVideoFile = new File(getView().getContext().getExternalFilesDir(null), "video.mp4");
preview.setCallback(new PreviewImpl.Callback() {
@Override
public void onSurfaceChanged() {
@ -57,11 +66,6 @@ public class Camera1 extends CameraViewImpl {
}
}
});
mPreviewSizes = new TreeSet<>();
mCaptureSizes = new TreeSet<>();
VIDEO_FILE = new File(getView().getContext().getExternalFilesDir(null), "video.mp4");;
}
@Override
@ -113,11 +117,6 @@ public class Camera1 extends CameraViewImpl {
return false;
}
@Override
int getFacing() {
return mFacing;
}
@Override
void setFlash(int flash) {
if (flash == mFlash) {
@ -150,11 +149,6 @@ public class Camera1 extends CameraViewImpl {
}
}
@Override
int getFlash() {
return mFlash;
}
@Override
void setAutoFocus(boolean autoFocus) {
if (autoFocus == mAutoFocus) {
@ -178,6 +172,8 @@ public class Camera1 extends CameraViewImpl {
} else {
mCameraParameters.setFocusMode(modes.get(0));
}
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
return true;
} else {
return false;
@ -215,7 +211,7 @@ public class Camera1 extends CameraViewImpl {
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
getCameraListener().onPictureTaken(data);
mCameraListener.onPictureTaken(data);
camera.startPreview();
}
});
@ -232,7 +228,7 @@ public class Camera1 extends CameraViewImpl {
getView().post(new Runnable() {
@Override
public void run() {
getCameraListener().onPictureTaken(data);
mCameraListener.onPictureTaken(data);
}
});
}
@ -318,7 +314,7 @@ public class Camera1 extends CameraViewImpl {
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mMediaRecorder.setOutputFile(VIDEO_FILE.getAbsolutePath());
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
mMediaRecorder.setOrientationHint(mCameraInfo.orientation);
mMediaRecorder.prepare();
@ -332,10 +328,15 @@ public class Camera1 extends CameraViewImpl {
mMediaRecorder = null;
}
getCameraListener().onVideoTaken(VIDEO_FILE);
mCameraListener.onVideoTaken(mVideoFile);
}
@Override
void focus() {
mCamera.autoFocus(null);
}
@Override
void setDisplayOrientation(int displayOrientation) {
if (mDisplayOrientation == displayOrientation) {
@ -399,7 +400,6 @@ public class Camera1 extends CameraViewImpl {
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
// TODO: fix this
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation) + (mFacing == CameraKit.Constants.FACING_FRONT ? 180 : 0));
setAutoFocusInternal(mAutoFocus);
@ -458,14 +458,14 @@ public class Camera1 extends CameraViewImpl {
adjustCameraParameters();
mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation));
getCameraListener().onCameraOpened();
mCameraListener.onCameraOpened();
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
getCameraListener().onCameraClosed();
mCameraListener.onCameraClosed();
}
}

@ -2,16 +2,15 @@ package com.flurgle.camerakit;
import android.view.View;
import com.flurgle.camerakit.annotations.Facing;
import com.flurgle.camerakit.annotations.Flash;
import com.flurgle.camerakit.types.Facing;
import com.flurgle.camerakit.types.Flash;
public abstract class CameraViewImpl {
public abstract class CameraImpl {
protected CameraListener mCameraListener;
protected final PreviewImpl mPreview;
CameraViewImpl(CameraListener callback, PreviewImpl preview) {
CameraImpl(CameraListener callback, PreviewImpl preview) {
mCameraListener = callback;
mPreview = preview;
}
@ -28,12 +27,8 @@ public abstract class CameraViewImpl {
abstract void setFacing(@Facing int facing);
abstract int getFacing();
abstract void setFlash(@Flash int flash);
abstract int getFlash();
abstract void setAutoFocus(boolean autoFocus);
abstract boolean getAutoFocus();
@ -46,14 +41,8 @@ public abstract class CameraViewImpl {
abstract void endVideo();
abstract void setDisplayOrientation(int displayOrientation);
void setCameraListener(CameraListener cameraListener) {
this.mCameraListener = cameraListener;
}
abstract void focus();
protected CameraListener getCameraListener() {
return mCameraListener != null ? mCameraListener : new CameraListener() {};
}
abstract void setDisplayOrientation(int displayOrientation);
}

@ -18,12 +18,14 @@ 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 com.flurgle.camerakit.annotations.Facing;
import com.flurgle.camerakit.annotations.Flash;
import com.flurgle.camerakit.annotations.PictureMode;
import com.flurgle.camerakit.annotations.TapToFocus;
import com.flurgle.camerakit.types.Facing;
import com.flurgle.camerakit.types.Flash;
import com.flurgle.camerakit.types.PictureMode;
import com.flurgle.camerakit.types.TapToFocus;
import com.flurgle.camerakit.utils.DisplayOrientationDetector;
import java.io.File;
@ -40,18 +42,13 @@ import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_VISIBLE;
public class CameraView extends FrameLayout {
private static final int PERMISSION_REQUEST_CAMERA = 16;
private static final int DEFAULT_CAPTURE_SIZE = -1;
@Facing
private int mFacing;
@Facing
private int mDefaultFacing;
@Flash
private int mFlash;
@Flash
private int mDefaultFlash;
@PictureMode
private int mPictureMode;
@ -69,10 +66,11 @@ public class CameraView extends FrameLayout {
private boolean mWaitingForPermission;
private CameraListener mCameraListener;
private CameraListenerMiddleWare mCameraListener;
private DisplayOrientationDetector mDisplayOrientationDetector;
private CameraViewImpl mCameraImpl;
private CameraImpl mCameraImpl;
private PreviewImpl mPreviewImpl;
public CameraView(@NonNull Context context) {
super(context, null);
@ -123,8 +121,10 @@ public class CameraView extends FrameLayout {
a.recycle();
}
final PreviewImpl preview = new TextureViewPreview(context, this);
mCameraImpl = new Camera1(mCameraListener, preview);
mCameraListener = new CameraListenerMiddleWare();
mPreviewImpl = new TextureViewPreview(context, this);
mCameraImpl = new Camera1(mCameraListener, mPreviewImpl);
setFacing(mFacing);
setFlash(mFlash);
@ -247,6 +247,11 @@ public class CameraView extends FrameLayout {
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 setAutoFocus(boolean autoFocus) {
@ -258,8 +263,7 @@ public class CameraView extends FrameLayout {
}
public void setCameraListener(CameraListener cameraListener) {
this.mCameraListener = new CameraListenerMiddleWare(cameraListener);
mCameraImpl.setCameraListener(mCameraListener);
this.mCameraListener.setCameraListener(cameraListener);
}
public void capturePicture() {
@ -307,6 +311,19 @@ public class CameraView extends FrameLayout {
}
}
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
@ -349,36 +366,42 @@ public class CameraView extends FrameLayout {
}
protected class CameraListenerMiddleWare extends CameraListener {
private static class CameraListenerMiddleWare extends CameraListener {
private CameraListener mCameraListener;
public CameraListenerMiddleWare(CameraListener cameraListener) {
this.mCameraListener = cameraListener;
}
@Override
public void onCameraOpened() {
super.onCameraOpened();
mCameraListener.onCameraOpened();
getCameraListener().onCameraOpened();
}
@Override
public void onCameraClosed() {
super.onCameraClosed();
mCameraListener.onCameraClosed();
getCameraListener().onCameraClosed();
}
@Override
public void onPictureTaken(byte[] picture) {
super.onPictureTaken(picture);
mCameraListener.onPictureTaken(picture);
getCameraListener().onPictureTaken(picture);
}
@Override
public void onVideoTaken(File video) {
super.onVideoTaken(video);
mCameraListener.onVideoTaken(video);
getCameraListener().onVideoTaken(video);
}
public void setCameraListener(@Nullable CameraListener cameraListener) {
this.mCameraListener = cameraListener;
}
@NonNull
public CameraListener getCameraListener() {
return mCameraListener != null ? mCameraListener : new CameraListener() {
};
}
}

@ -47,6 +47,22 @@ public abstract class PreviewImpl {
return null;
}
void setSize(int width, int height) {
mWidth = width;
mHeight = height;
// Refresh true preview size to adjust scaling
setTruePreviewSize(mTrueWidth, mTrueHeight);
}
int getWidth() {
return mWidth;
}
int getHeight() {
return mHeight;
}
void setTruePreviewSize(int width, int height) {
this.mTrueWidth = width;
this.mTrueHeight = height;
@ -67,20 +83,12 @@ public abstract class PreviewImpl {
}
}
void setSize(int width, int height) {
mWidth = width;
mHeight = height;
// Refresh true preview size to adjust scaling
setTruePreviewSize(mTrueWidth, mTrueHeight);
}
int getWidth() {
return mWidth;
int getTrueWidth() {
return mTrueWidth;
}
int getHeight() {
return mHeight;
int getTrueHeight() {
return mTrueHeight;
}
}

@ -1,4 +1,4 @@
package com.flurgle.camerakit.annotations;
package com.flurgle.camerakit.types;
import android.support.annotation.IntDef;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.annotations;
package com.flurgle.camerakit.types;
import android.support.annotation.IntDef;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.annotations;
package com.flurgle.camerakit.types;
import android.support.annotation.IntDef;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.annotations;
package com.flurgle.camerakit.types;
import android.support.annotation.IntDef;

@ -7,62 +7,11 @@ import android.support.v4.util.SparseArrayCompat;
public class AspectRatio implements Comparable<AspectRatio>, Parcelable {
private final static SparseArrayCompat<SparseArrayCompat<AspectRatio>> sCache
= new SparseArrayCompat<>(16);
private final static SparseArrayCompat<SparseArrayCompat<AspectRatio>> sCache = new SparseArrayCompat<>(16);
private final int mX;
private final int mY;
/**
* Returns an instance of {@link AspectRatio} specified by {@code x} and {@code y} values.
* The values {@code x} and {@code} will be reduced by their greatest common divider.
*
* @param x The width
* @param y The height
* @return An instance of {@link AspectRatio}
*/
public static AspectRatio of(int x, int y) {
int gcd = gcd(x, y);
x /= gcd;
y /= gcd;
SparseArrayCompat<AspectRatio> arrayX = sCache.get(x);
if (arrayX == null) {
AspectRatio ratio = new AspectRatio(x, y);
arrayX = new SparseArrayCompat<>();
arrayX.put(y, ratio);
sCache.put(x, arrayX);
return ratio;
} else {
AspectRatio ratio = arrayX.get(y);
if (ratio == null) {
ratio = new AspectRatio(x, y);
arrayX.put(y, ratio);
}
return ratio;
}
}
/**
* Parse an {@link AspectRatio} from a {@link String} formatted like "4:3".
*
* @param s The string representation of the aspect ratio
* @return The aspect ratio
* @throws IllegalArgumentException when the format is incorrect.
*/
public static AspectRatio parse(String s) {
int position = s.indexOf(':');
if (position == -1) {
throw new IllegalArgumentException("Malformed aspect ratio: " + s);
}
try {
int x = Integer.parseInt(s.substring(0, position));
int y = Integer.parseInt(s.substring(position + 1));
return AspectRatio.of(x, y);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Malformed aspect ratio: " + s, e);
}
}
private AspectRatio(int x, int y) {
mX = x;
mY = y;
@ -109,7 +58,6 @@ public class AspectRatio implements Comparable<AspectRatio>, Parcelable {
@Override
public int hashCode() {
// assuming most sizes are <2^16, doing a rotate will give us perfect hashing
return mY ^ ((mX << (Integer.SIZE / 2)) | (mX >>> (Integer.SIZE / 2)));
}
@ -123,14 +71,31 @@ public class AspectRatio implements Comparable<AspectRatio>, Parcelable {
return -1;
}
/**
* @return The inverse of this {@link AspectRatio}.
*/
public AspectRatio inverse() {
//noinspection SuspiciousNameCombination
return AspectRatio.of(mY, mX);
}
public static AspectRatio of(int x, int y) {
int gcd = gcd(x, y);
x /= gcd;
y /= gcd;
SparseArrayCompat<AspectRatio> arrayX = sCache.get(x);
if (arrayX == null) {
AspectRatio ratio = new AspectRatio(x, y);
arrayX = new SparseArrayCompat<>();
arrayX.put(y, ratio);
sCache.put(x, arrayX);
return ratio;
} else {
AspectRatio ratio = arrayX.get(y);
if (ratio == null) {
ratio = new AspectRatio(x, y);
arrayX.put(y, ratio);
}
return ratio;
}
}
private static int gcd(int a, int b) {
while (b != 0) {
int c = b;
@ -151,8 +116,7 @@ public class AspectRatio implements Comparable<AspectRatio>, Parcelable {
dest.writeInt(mY);
}
public static final Parcelable.Creator<AspectRatio> CREATOR
= new Parcelable.Creator<AspectRatio>() {
public static final Parcelable.Creator<AspectRatio> CREATOR = new Parcelable.Creator<AspectRatio>() {
@Override
public AspectRatio createFromParcel(Parcel source) {
@ -165,6 +129,7 @@ public class AspectRatio implements Comparable<AspectRatio>, Parcelable {
public AspectRatio[] newArray(int size) {
return new AspectRatio[size];
}
};
}

@ -11,7 +11,6 @@ public abstract class DisplayOrientationDetector {
private final OrientationEventListener mOrientationEventListener;
static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray();
static {
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0);
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90);
@ -30,23 +29,23 @@ public abstract class DisplayOrientationDetector {
@Override
public void onOrientationChanged(int orientation) {
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN ||
mDisplay == null) {
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN || mDisplay == null) {
return;
}
final int rotation = mDisplay.getRotation();
if (mLastKnownRotation != rotation) {
mLastKnownRotation = rotation;
dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(rotation));
}
}
};
}
public void enable(Display display) {
mDisplay = display;
mOrientationEventListener.enable();
// Immediately dispatch the first callback
dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(display.getRotation()));
}

@ -42,7 +42,6 @@ public class Size implements Comparable<Size> {
@Override
public int hashCode() {
// assuming most sizes are <2^16, doing a rotate will give us perfect hashing
return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
}

@ -1,10 +1,6 @@
package com.flurgle.camerakit.utils;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.Image;
import android.support.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -12,21 +8,6 @@ import java.nio.ByteBuffer;
public class YuvUtils {
public static byte[] createRGB(Image image, @Nullable Rect crop) {
byte[] data = getYUVData(image);
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
if (crop == null) {
crop = new Rect(0, 0, image.getWidth(), image.getHeight());
}
yuvImage.compressToJpeg(crop, 50, out);
return out.toByteArray();
}
public static byte[] getYUVData(Image image) {
ByteBuffer bufferY = image.getPlanes()[0].getBuffer();
byte[] y = new byte[bufferY.remaining()];

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

Loading…
Cancel
Save