Skip to content
This repository has been archived by the owner on Dec 29, 2022. It is now read-only.

Commit

Permalink
add touch focus
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWoki committed Jul 14, 2017
1 parent 8031b91 commit 47b8a4e
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 0 deletions.
130 changes: 130 additions & 0 deletions library/src/main/api14/com/google/android/cameraview/Camera1.java
Expand Up @@ -17,13 +17,19 @@
package com.google.android.cameraview;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Build;
import android.os.Handler;
import android.support.v4.util.SparseArrayCompat;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
Expand Down Expand Up @@ -71,6 +77,10 @@ class Camera1 extends CameraViewImpl {

private int mDisplayOrientation;

private Handler mHandler = new Handler();

private Camera.AutoFocusCallback mAutofocusCallback;

Camera1(Callback callback, PreviewImpl preview) {
super(callback, preview);
preview.setCallback(new PreviewImpl.Callback() {
Expand Down Expand Up @@ -107,6 +117,8 @@ void stop() {
mCamera.stopPreview();
}
mShowingPreview = false;
if (mHandler != null)
mHandler.removeCallbacksAndMessages(null);
releaseCamera();
}

Expand Down Expand Up @@ -443,12 +455,16 @@ private boolean setAutoFocusInternal(boolean autoFocus) {
if (isCameraOpened()) {
final List<String> modes = mCameraParameters.getSupportedFocusModes();
if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
attachFocusTapListener();
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
detachFocusTapListener();
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
detachFocusTapListener();
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
} else {
detachFocusTapListener();
mCameraParameters.setFocusMode(modes.get(0));
}
return true;
Expand Down Expand Up @@ -482,4 +498,118 @@ private boolean setFlashInternal(int flash) {
}
}

@TargetApi(14)
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();
String focusMode = parameters.getFocusMode();
Rect rect = calculateFocusArea(event.getX(), event.getY());
List<Camera.Area> meteringAreas = new ArrayList<>();
meteringAreas.add(new Camera.Area(rect, getFocusMeteringAreaWeight()));
if (parameters.getMaxNumFocusAreas() != 0 && focusMode != null &&
(focusMode.equals(Camera.Parameters.FOCUS_MODE_AUTO) ||
focusMode.equals(Camera.Parameters.FOCUS_MODE_MACRO) ||
focusMode.equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) ||
focusMode.equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setFocusAreas(meteringAreas);
if (parameters.getMaxNumMeteringAreas() > 0) {
parameters.setMeteringAreas(meteringAreas);
}
if(!parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
return false; //cannot autoFocus
}
mCamera.setParameters(parameters);
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
resetFocus(success, camera);
}
});
} else if (parameters.getMaxNumMeteringAreas() > 0) {
if(!parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
return false; //cannot autoFocus
}
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setFocusAreas(meteringAreas);
parameters.setMeteringAreas(meteringAreas);

mCamera.setParameters(parameters);
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
resetFocus(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;
}
});
}

@TargetApi(14)
private void resetFocus(final boolean success, final Camera camera) {
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (camera != null) {
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);
}
}
}
}, DELAY_MILLIS_BEFORE_RESETTING_FOCUS);
}

Rect calculateFocusArea(float x, float y) {
int buffer = getFocusAreaSize() / 2;
int centerX = calculateCenter(x, mPreview.getView().getWidth(), buffer);
int centerY = calculateCenter(y, mPreview.getView().getHeight(), buffer);
return new Rect(
centerX - buffer,
centerY - buffer,
centerX + buffer,
centerY + buffer
);
}

static int calculateCenter(float coord, int dimen, int buffer) {
int normalized = (int) ((coord / dimen) * 2000 - 1000);
if (Math.abs(normalized) + buffer > 1000) {
if (normalized > 0) {
return 1000 - buffer;
} else {
return -1000 + buffer;
}
} else {
return normalized;
}
}

}
65 changes: 65 additions & 0 deletions library/src/main/api21/com/google/android/cameraview/Camera2.java
Expand Up @@ -19,21 +19,26 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.support.annotation.NonNull;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;

import java.nio.ByteBuffer;
import java.util.Arrays;
Expand Down Expand Up @@ -525,14 +530,17 @@ void updateAutoFocus() {
// Auto focus is not supported
if (modes == null || modes.length == 0 ||
(modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) {
detachFocusTapListener();
mAutoFocus = false;
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_OFF);
} else {
attachFocusTapListener();
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
}
} else {
detachFocusTapListener();
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_OFF);
}
Expand Down Expand Up @@ -671,6 +679,63 @@ void unlockFocus() {
}
}

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) {
Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
if (rect == null) return true;
int areaSize = getFocusAreaSize();
int right = rect.right;
int bottom = rect.bottom;
int viewWidth = mPreview.getView().getWidth();
int viewHeight = mPreview.getView().getHeight();
int ll, rr;
Rect newRect;
int centerX = (int) event.getX();
int centerY = (int) event.getY();
ll = ((centerX * right) - areaSize) / viewWidth;
rr = ((centerY * bottom) - areaSize) / viewHeight;
int focusLeft = clamp(ll, 0, right);
int focusBottom = clamp(rr, 0, bottom);
newRect = new Rect(focusLeft, focusBottom, focusLeft + areaSize, focusBottom + areaSize);
MeteringRectangle meteringRectangle = new MeteringRectangle(newRect, getFocusMeteringAreaWeight());
MeteringRectangle[] meteringRectangleArr = {meteringRectangle};

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, meteringRectangleArr);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, meteringRectangleArr);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);

updatePreview();
}
}
return true;
}
});
}

private int clamp(int x, int min, int max) {
if (x < min) {
return min;
} else if (x > max) {
return max;
} else {
return x;
}
}

private void updatePreview() {
try {
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

/**
* A {@link CameraCaptureSession.CaptureCallback} for capturing a still picture.
*/
Expand Down
Expand Up @@ -22,6 +22,10 @@

abstract class CameraViewImpl {

static final int FOCUS_AREA_SIZE_DEFAULT = 300;
static final int FOCUS_METERING_AREA_WEIGHT_DEFAULT = 1000;
static final int DELAY_MILLIS_BEFORE_RESETTING_FOCUS = 3000;

protected final Callback mCallback;

protected final PreviewImpl mPreview;
Expand All @@ -35,6 +39,18 @@ View getView() {
return mPreview.getView();
}

int getFocusAreaSize() {
return FOCUS_AREA_SIZE_DEFAULT;
}

int getFocusMeteringAreaWeight() {
return FOCUS_METERING_AREA_WEIGHT_DEFAULT;
}

void detachFocusTapListener() {
mPreview.getView().setOnTouchListener(null);
}

/**
* @return {@code true} if the implementation was able to start the camera session.
*/
Expand Down

0 comments on commit 47b8a4e

Please sign in to comment.