diff --git a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java index 124dae08..cc14b043 100644 --- a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java +++ b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java @@ -1,13 +1,17 @@ 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.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; @@ -24,6 +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 = 1000; + private int mCameraId; private Camera mCamera; private Camera.Parameters mCameraParameters; @@ -32,6 +39,7 @@ public class Camera1 extends CameraImpl { private Size mCaptureSize; private MediaRecorder mMediaRecorder; private File mVideoFile; + private Camera.AutoFocusCallback mAutofocusCallback; private int mDisplayOrientation; @@ -137,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); @@ -147,11 +156,18 @@ public class Camera1 extends CameraImpl { break; case FOCUS_TAP: - setFocus(FOCUS_CONTINUOUS); + 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); @@ -403,4 +419,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 915f1c92..56335cf3 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