From 29ccf4fa6a4db76752e9df8717efddf1e6ea6e97 Mon Sep 17 00:00:00 2001 From: Caleb Lewis Date: Wed, 8 Mar 2017 19:50:53 -0500 Subject: [PATCH 1/2] rough draft of implementing autofocus --- .../api16/com/flurgle/camerakit/Camera1.java | 117 +++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java index 0c137ef3..0172ca0a 100644 --- a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java +++ b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java @@ -1,19 +1,25 @@ package com.flurgle.camerakit; +import android.graphics.Rect; import android.graphics.YuvImage; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; +import android.util.Log; +import android.view.MotionEvent; import android.view.SurfaceHolder; +import android.view.View; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; +import static android.content.ContentValues.TAG; 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; @@ -24,6 +30,11 @@ import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STILL; @SuppressWarnings("deprecation") public class Camera1 extends CameraImpl { + + private static final int FOCUS_AREA_SIZE_DEFAULT = 300; + private static final int FOCUS_METERING_AREA_WEIGHT_DEFAULT = 800; + + private View view; private int mCameraId; private Camera mCamera; private Camera.Parameters mCameraParameters; @@ -32,8 +43,11 @@ public class Camera1 extends CameraImpl { private Size mCaptureSize; private MediaRecorder mMediaRecorder; private File mVideoFile; + private Camera.AutoFocusCallback mAutofocusCallback; private int mDisplayOrientation; + private int mFocusAreaSize = 0; + private int mFocusMeteringAreaWeight = 0; @Facing private int mFacing; @@ -52,6 +66,7 @@ public class Camera1 extends CameraImpl { Camera1(CameraListener callback, PreviewImpl preview) { super(callback, preview); + this.view = preview.getView(); preview.setCallback(new PreviewImpl.Callback() { @Override public void onSurfaceChanged() { @@ -147,7 +162,8 @@ public class Camera1 extends CameraImpl { break; case FOCUS_TAP: - setFocus(FOCUS_CONTINUOUS); + mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); + attachFocusTapListener(); break; case FOCUS_OFF: @@ -279,8 +295,107 @@ public class Camera1 extends CameraImpl { return mCamera != null; } + void setFocusAreaSize(int size) { + mFocusAreaSize = size; + } + + /** + * @link {@link android.hardware.Camera.Area#weight} + */ + void setFocusMeteringAreaWeight(int weight) { + mFocusMeteringAreaWeight = weight; + } + + void setTapToAutofocusListener(Camera.AutoFocusCallback callback) { + if (this.mFocus != FOCUS_TAP) { + throw new IllegalArgumentException("Please set the camera to FOCUS_TAP."); + } + + this.mAutofocusCallback = callback; + } + + private int getFocusAreaSize() { + if (mFocusAreaSize == 0) { + return FOCUS_AREA_SIZE_DEFAULT; + } else { + return mFocusAreaSize; + } + } + + private int getFocusMeteringAreaWeight() { + if (mFocusMeteringAreaWeight == 0) { + return FOCUS_METERING_AREA_WEIGHT_DEFAULT; + } else { + return mFocusMeteringAreaWeight; + } + } + // Internal: + private void attachFocusTapListener() { + view.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (mCamera != null ) { + + Camera.Parameters parameters = mCamera.getParameters(); + if (parameters.getMaxNumMeteringAreas() > 0){ + Log.i(TAG,"fancy !"); + Rect rect = calculateFocusArea(event.getX(), event.getY()); + + parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); + List meteringAreas = new ArrayList<>(); + meteringAreas.add(new Camera.Area(rect, FOCUS_METERING_AREA_WEIGHT_DEFAULT)); + parameters.setFocusAreas(meteringAreas); + + mCamera.setParameters(parameters); + mCamera.autoFocus(new Camera.AutoFocusCallback() { + @Override + public void onAutoFocus(boolean success, Camera camera) { + if (mAutofocusCallback != null) { + mAutofocusCallback.onAutoFocus(success, camera); + } + } + }); + } else { + mCamera.autoFocus(new Camera.AutoFocusCallback() { + @Override + public void onAutoFocus(boolean success, Camera camera) { + if (mAutofocusCallback != null) { + mAutofocusCallback.onAutoFocus(success, camera); + } + } + }); + } + } + } + return true; + } + }); + } + + private Rect calculateFocusArea(float x, float y) { + int left = clamp(Float.valueOf((x / view.getWidth()) * 2000 - 1000).intValue(), getFocusAreaSize()); + int top = clamp(Float.valueOf((y / view.getHeight()) * 2000 - 1000).intValue(), getFocusAreaSize()); + + return new Rect(left, top, left + getFocusAreaSize(), top + getFocusAreaSize()); + } + + private int clamp(int touchCoordinateInCameraReper, int focusAreaSize) { + int result; + if (Math.abs(touchCoordinateInCameraReper)+focusAreaSize/2>1000){ + if (touchCoordinateInCameraReper>0){ + result = 1000 - focusAreaSize/2; + } else { + result = -1000 + focusAreaSize/2; + } + } else{ + result = touchCoordinateInCameraReper - focusAreaSize/2; + } + return result; + } + private void openCamera() { if (mCamera != null) { releaseCamera(); From fba3ed4ee123c3619ffac4623f16a0d07dbb0ce2 Mon Sep 17 00:00:00 2001 From: Dylan McIntyre Date: Fri, 10 Mar 2017 12:54:35 -0500 Subject: [PATCH 2/2] Finish basic tap to focus --- .../api16/com/flurgle/camerakit/Camera1.java | 216 +++++++++--------- camerakit/src/main/res/values/attrs.xml | 2 +- .../camerakit/demo/FocusMarkerLayout.java | 71 ++++++ .../flurgle/camerakit/demo/MainActivity.java | 12 + .../main/res/drawable/focus_marker_fill.xml | 7 + .../res/drawable/focus_marker_outline.xml | 9 + demo/src/main/res/layout/activity_main.xml | 37 ++- .../main/res/layout/layout_focus_marker.xml | 24 ++ 8 files changed, 257 insertions(+), 121 deletions(-) create mode 100644 demo/src/main/java/com/flurgle/camerakit/demo/FocusMarkerLayout.java create mode 100644 demo/src/main/res/drawable/focus_marker_fill.xml create mode 100644 demo/src/main/res/drawable/focus_marker_outline.xml create mode 100644 demo/src/main/res/layout/layout_focus_marker.xml diff --git a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java index 0172ca0a..dc90f4de 100644 --- a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java +++ b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java @@ -5,7 +5,6 @@ import android.graphics.YuvImage; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; -import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; @@ -19,7 +18,6 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; -import static android.content.ContentValues.TAG; 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; @@ -30,11 +28,9 @@ import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STILL; @SuppressWarnings("deprecation") public class Camera1 extends CameraImpl { - private static final int FOCUS_AREA_SIZE_DEFAULT = 300; - private static final int FOCUS_METERING_AREA_WEIGHT_DEFAULT = 800; + private static final int FOCUS_METERING_AREA_WEIGHT_DEFAULT = 1000; - private View view; private int mCameraId; private Camera mCamera; private Camera.Parameters mCameraParameters; @@ -46,8 +42,6 @@ public class Camera1 extends CameraImpl { private Camera.AutoFocusCallback mAutofocusCallback; private int mDisplayOrientation; - private int mFocusAreaSize = 0; - private int mFocusMeteringAreaWeight = 0; @Facing private int mFacing; @@ -66,7 +60,6 @@ public class Camera1 extends CameraImpl { Camera1(CameraListener callback, PreviewImpl preview) { super(callback, preview); - this.view = preview.getView(); preview.setCallback(new PreviewImpl.Callback() { @Override public void onSurfaceChanged() { @@ -152,6 +145,7 @@ public class Camera1 extends CameraImpl { switch (focus) { case FOCUS_CONTINUOUS: if (mCameraParameters != null) { + detachFocusTapListener(); final List modes = mCameraParameters.getSupportedFocusModes(); if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); @@ -162,12 +156,18 @@ public class Camera1 extends CameraImpl { break; case FOCUS_TAP: - mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); - attachFocusTapListener(); + if (mCameraParameters != null) { + attachFocusTapListener(); + final List modes = mCameraParameters.getSupportedFocusModes(); + if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { + mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + } + } break; case FOCUS_OFF: if (mCameraParameters != null) { + detachFocusTapListener(); final List modes = mCameraParameters.getSupportedFocusModes(); if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); @@ -295,107 +295,8 @@ public class Camera1 extends CameraImpl { return mCamera != null; } - void setFocusAreaSize(int size) { - mFocusAreaSize = size; - } - - /** - * @link {@link android.hardware.Camera.Area#weight} - */ - void setFocusMeteringAreaWeight(int weight) { - mFocusMeteringAreaWeight = weight; - } - - void setTapToAutofocusListener(Camera.AutoFocusCallback callback) { - if (this.mFocus != FOCUS_TAP) { - throw new IllegalArgumentException("Please set the camera to FOCUS_TAP."); - } - - this.mAutofocusCallback = callback; - } - - private int getFocusAreaSize() { - if (mFocusAreaSize == 0) { - return FOCUS_AREA_SIZE_DEFAULT; - } else { - return mFocusAreaSize; - } - } - - private int getFocusMeteringAreaWeight() { - if (mFocusMeteringAreaWeight == 0) { - return FOCUS_METERING_AREA_WEIGHT_DEFAULT; - } else { - return mFocusMeteringAreaWeight; - } - } - // Internal: - private void attachFocusTapListener() { - view.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (mCamera != null ) { - - Camera.Parameters parameters = mCamera.getParameters(); - if (parameters.getMaxNumMeteringAreas() > 0){ - Log.i(TAG,"fancy !"); - Rect rect = calculateFocusArea(event.getX(), event.getY()); - - parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); - List meteringAreas = new ArrayList<>(); - meteringAreas.add(new Camera.Area(rect, FOCUS_METERING_AREA_WEIGHT_DEFAULT)); - parameters.setFocusAreas(meteringAreas); - - mCamera.setParameters(parameters); - mCamera.autoFocus(new Camera.AutoFocusCallback() { - @Override - public void onAutoFocus(boolean success, Camera camera) { - if (mAutofocusCallback != null) { - mAutofocusCallback.onAutoFocus(success, camera); - } - } - }); - } else { - mCamera.autoFocus(new Camera.AutoFocusCallback() { - @Override - public void onAutoFocus(boolean success, Camera camera) { - if (mAutofocusCallback != null) { - mAutofocusCallback.onAutoFocus(success, camera); - } - } - }); - } - } - } - return true; - } - }); - } - - private Rect calculateFocusArea(float x, float y) { - int left = clamp(Float.valueOf((x / view.getWidth()) * 2000 - 1000).intValue(), getFocusAreaSize()); - int top = clamp(Float.valueOf((y / view.getHeight()) * 2000 - 1000).intValue(), getFocusAreaSize()); - - return new Rect(left, top, left + getFocusAreaSize(), top + getFocusAreaSize()); - } - - private int clamp(int touchCoordinateInCameraReper, int focusAreaSize) { - int result; - if (Math.abs(touchCoordinateInCameraReper)+focusAreaSize/2>1000){ - if (touchCoordinateInCameraReper>0){ - result = 1000 - focusAreaSize/2; - } else { - result = -1000 + focusAreaSize/2; - } - } else{ - result = touchCoordinateInCameraReper - focusAreaSize/2; - } - return result; - } - private void openCamera() { if (mCamera != null) { releaseCamera(); @@ -520,4 +421,101 @@ public class Camera1 extends CameraImpl { } } + void setTapToAutofocusListener(Camera.AutoFocusCallback callback) { + if (this.mFocus != FOCUS_TAP) { + throw new IllegalArgumentException("Please set the camera to FOCUS_TAP."); + } + + this.mAutofocusCallback = callback; + } + + private int getFocusAreaSize() { + return FOCUS_AREA_SIZE_DEFAULT; + } + + private int getFocusMeteringAreaWeight() { + return FOCUS_METERING_AREA_WEIGHT_DEFAULT; + } + + private void detachFocusTapListener() { + mPreview.getView().setOnTouchListener(null); + } + + private void attachFocusTapListener() { + mPreview.getView().setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + if (mCamera != null) { + + Camera.Parameters parameters = mCamera.getParameters(); + if (parameters.getMaxNumMeteringAreas() > 0) { + Rect rect = calculateFocusArea(event.getX(), event.getY()); + + parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); + List meteringAreas = new ArrayList<>(); + meteringAreas.add(new Camera.Area(rect, getFocusMeteringAreaWeight())); + parameters.setFocusAreas(meteringAreas); + parameters.setMeteringAreas(meteringAreas); + + mCamera.setParameters(parameters); + mCamera.autoFocus(new Camera.AutoFocusCallback() { + @Override + public void onAutoFocus(boolean success, Camera camera) { + camera.cancelAutoFocus(); + Camera.Parameters params = camera.getParameters(); + if (params.getFocusMode() != Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) { + params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + params.setFocusAreas(null); + params.setMeteringAreas(null); + camera.setParameters(params); + } + + if (mAutofocusCallback != null) { + mAutofocusCallback.onAutoFocus(success, camera); + } + } + }); + } else { + mCamera.autoFocus(new Camera.AutoFocusCallback() { + @Override + public void onAutoFocus(boolean success, Camera camera) { + if (mAutofocusCallback != null) { + mAutofocusCallback.onAutoFocus(success, camera); + } + } + }); + } + } + } + return true; + } + }); + } + + private Rect calculateFocusArea(float x, float y) { + int centerX = clamp(Float.valueOf((x / mPreview.getView().getWidth()) * 2000 - 1000).intValue(), getFocusAreaSize()); + int centerY = clamp(Float.valueOf((y / mPreview.getView().getHeight()) * 2000 - 1000).intValue(), getFocusAreaSize()); + return new Rect( + centerX - getFocusAreaSize() / 2, + centerY - getFocusAreaSize() / 2, + centerX + getFocusAreaSize() / 2, + centerY + getFocusAreaSize() / 2 + ); + } + + private int clamp(int touchCoordinateInCameraReper, int focusAreaSize) { + int result; + if (Math.abs(touchCoordinateInCameraReper) + focusAreaSize / 2 > 1000) { + if (touchCoordinateInCameraReper > 0) { + result = 1000 - focusAreaSize / 2; + } else { + result = -1000 + focusAreaSize / 2; + } + } else { + result = touchCoordinateInCameraReper - focusAreaSize / 2; + } + return result; + } + } diff --git a/camerakit/src/main/res/values/attrs.xml b/camerakit/src/main/res/values/attrs.xml index 2508bc13..a962c7ee 100644 --- a/camerakit/src/main/res/values/attrs.xml +++ b/camerakit/src/main/res/values/attrs.xml @@ -19,7 +19,7 @@ - + diff --git a/demo/src/main/java/com/flurgle/camerakit/demo/FocusMarkerLayout.java b/demo/src/main/java/com/flurgle/camerakit/demo/FocusMarkerLayout.java new file mode 100644 index 00000000..0d695f3d --- /dev/null +++ b/demo/src/main/java/com/flurgle/camerakit/demo/FocusMarkerLayout.java @@ -0,0 +1,71 @@ +package com.flurgle.camerakit.demo; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.ImageView; + +public class FocusMarkerLayout extends FrameLayout { + + private FrameLayout mFocusMarkerContainer; + private ImageView mFill; + + public FocusMarkerLayout(@NonNull Context context) { + super(context, null); + } + + public FocusMarkerLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + LayoutInflater.from(getContext()).inflate(R.layout.layout_focus_marker, this); + + mFocusMarkerContainer = (FrameLayout) findViewById(R.id.focusMarkerContainer); + mFill = (ImageView) findViewById(R.id.fill); + + mFocusMarkerContainer.setAlpha(0); + } + + public void focus(float mx, float my) { + int x = (int) (mx - mFocusMarkerContainer.getWidth() / 2); + int y = (int) (my - mFocusMarkerContainer.getWidth() / 2); + + mFocusMarkerContainer.setTranslationX(x); + mFocusMarkerContainer.setTranslationY(y); + + mFocusMarkerContainer.animate().setListener(null).cancel(); + mFill.animate().setListener(null).cancel(); + + mFill.setScaleX(0); + mFill.setScaleY(0); + mFill.setAlpha(1f); + + mFocusMarkerContainer.setScaleX(1.36f); + mFocusMarkerContainer.setScaleY(1.36f); + mFocusMarkerContainer.setAlpha(1f); + + mFocusMarkerContainer.animate().scaleX(1).scaleY(1).setStartDelay(0).setDuration(330) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mFocusMarkerContainer.animate().alpha(0).setStartDelay(750).setDuration(800).setListener(null).start(); + } + }).start(); + + mFill.animate().scaleX(1).scaleY(1).setDuration(330) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mFill.animate().alpha(0).setDuration(800).setListener(null).start(); + } + }).start(); + + } + + +} 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 6adcad8f..cbb85c2c 100644 --- a/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java +++ b/demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java @@ -5,6 +5,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -23,6 +24,7 @@ import java.io.File; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import butterknife.OnTouch; public class MainActivity extends AppCompatActivity implements View.OnLayoutChangeListener { @@ -32,6 +34,9 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan @BindView(R.id.camera) CameraView camera; + @BindView(R.id.focusMarker) + FocusMarkerLayout focusMarker; + // Capture Mode: @BindView(R.id.captureModeRadioGroup) @@ -308,4 +313,11 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan camera.removeOnLayoutChangeListener(this); } + + @OnTouch(R.id.focusMarker) + boolean onTouchCamera(View view, MotionEvent motionEvent) { + focusMarker.focus(motionEvent.getX(), motionEvent.getY()); + return false; + } + } diff --git a/demo/src/main/res/drawable/focus_marker_fill.xml b/demo/src/main/res/drawable/focus_marker_fill.xml new file mode 100644 index 00000000..d5fc7756 --- /dev/null +++ b/demo/src/main/res/drawable/focus_marker_fill.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/demo/src/main/res/drawable/focus_marker_outline.xml b/demo/src/main/res/drawable/focus_marker_outline.xml new file mode 100644 index 00000000..5628256c --- /dev/null +++ b/demo/src/main/res/drawable/focus_marker_outline.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/demo/src/main/res/layout/activity_main.xml b/demo/src/main/res/layout/activity_main.xml index 4801771c..dbb46c5f 100644 --- a/demo/src/main/res/layout/activity_main.xml +++ b/demo/src/main/res/layout/activity_main.xml @@ -13,18 +13,33 @@ android:layout_height="wrap_content" android:orientation="vertical"> - + android:layout_height="wrap_content"> + + + + + + + + + + + + + + + + + \ No newline at end of file