Skip to content

Commit 231d111

Browse files
author
luowei
committed
Add support for manual tap to focus google#130
1 parent 8b21edd commit 231d111

File tree

11 files changed

+1085
-346
lines changed

11 files changed

+1085
-346
lines changed

demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ protected void onCreate(Bundle savedInstanceState) {
129129
if (mCameraView != null) {
130130
mCameraView.addCallback(mCallback);
131131
}
132+
mCameraView.setManualFocus(true);
132133

133134
mFab = (FloatingActionButton) findViewById(R.id.take_picture);
134135

library/src/main/api14/com/google/android/cameraview/Camera1.java

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
package com.google.android.cameraview;
1818

1919
import android.annotation.SuppressLint;
20+
import android.graphics.Rect;
21+
import android.graphics.RectF;
2022
import android.graphics.SurfaceTexture;
2123
import android.hardware.Camera;
2224
import android.os.Build;
25+
import android.os.Handler;
2326
import android.support.v4.util.SparseArrayCompat;
2427
import android.view.SurfaceHolder;
2528
import java.io.IOException;
29+
import java.util.Collections;
2630
import java.util.List;
2731
import java.util.Set;
2832
import java.util.SortedSet;
@@ -49,6 +53,8 @@ class Camera1 extends CameraViewImpl {
4953

5054
private final AtomicBoolean isPictureCaptureInProgress = new AtomicBoolean(false);
5155

56+
private final AtomicBoolean isAutoFocusInProgress = new AtomicBoolean(false);
57+
5258
Camera mCamera;
5359

5460
private Camera.Parameters mCameraParameters;
@@ -71,11 +77,30 @@ class Camera1 extends CameraViewImpl {
7177

7278
private int mDisplayOrientation;
7379

80+
private CameraCoordinateTransformer mCoordinateTransformer;
81+
82+
private Rect mPreviewRect = new Rect(0, 0, 0, 0);
83+
84+
private final Handler mCameraHandler;
85+
86+
private final Runnable mReturnToContinuousAFRunnable = new Runnable() {
87+
@Override
88+
public void run() {
89+
if (setAutoFocusInternal(mAutoFocus)) {
90+
mCamera.setParameters(mCameraParameters);
91+
mCamera.cancelAutoFocus();
92+
}
93+
}
94+
};
95+
7496
Camera1(Callback callback, PreviewImpl preview) {
7597
super(callback, preview);
98+
mCameraHandler = new Handler();
7699
preview.setCallback(new PreviewImpl.Callback() {
77100
@Override
78101
public void onSurfaceChanged() {
102+
mPreviewRect.set(0, 0, mPreview.getWidth(), mPreview.getHeight());
103+
resetCoordinateTransformer();
79104
if (mCamera != null) {
80105
setUpPreview();
81106
adjustCameraParameters();
@@ -108,6 +133,8 @@ void stop() {
108133
}
109134
mShowingPreview = false;
110135
releaseCamera();
136+
137+
mCameraHandler.removeCallbacks(mReturnToContinuousAFRunnable);
111138
}
112139

113140
// Suppresses Camera#setPreviewTexture
@@ -146,6 +173,8 @@ void setFacing(int facing) {
146173
stop();
147174
start();
148175
}
176+
177+
resetCoordinateTransformer();
149178
}
150179

151180
@Override
@@ -229,11 +258,12 @@ void takePicture() {
229258
throw new IllegalStateException(
230259
"Camera is not ready. Call start() before takePicture().");
231260
}
232-
if (getAutoFocus()) {
261+
if (getAutoFocus() || isAutoFocusInProgress.get()) {
233262
mCamera.cancelAutoFocus();
234263
mCamera.autoFocus(new Camera.AutoFocusCallback() {
235264
@Override
236265
public void onAutoFocus(boolean success, Camera camera) {
266+
isAutoFocusInProgress.set(false);
237267
takePictureInternal();
238268
}
239269
});
@@ -244,7 +274,14 @@ public void onAutoFocus(boolean success, Camera camera) {
244274

245275
void takePictureInternal() {
246276
if (!isPictureCaptureInProgress.getAndSet(true)) {
247-
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
277+
mCamera.takePicture(new Camera.ShutterCallback() {
278+
@Override
279+
public void onShutter() {
280+
if (setAutoFocusInternal(mAutoFocus)) {
281+
mCamera.setParameters(mCameraParameters);
282+
}
283+
}
284+
}, null, null, new Camera.PictureCallback() {
248285
@Override
249286
public void onPictureTaken(byte[] data, Camera camera) {
250287
isPictureCaptureInProgress.set(false);
@@ -256,6 +293,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
256293
}
257294
}
258295
});
296+
mCameraHandler.removeCallbacks(mReturnToContinuousAFRunnable);
259297
}
260298
}
261299

@@ -265,6 +303,7 @@ void setDisplayOrientation(int displayOrientation) {
265303
return;
266304
}
267305
mDisplayOrientation = displayOrientation;
306+
resetCoordinateTransformer();
268307
if (isCameraOpened()) {
269308
mCameraParameters.setRotation(calcCameraRotation(displayOrientation));
270309
mCamera.setParameters(mCameraParameters);
@@ -279,6 +318,49 @@ void setDisplayOrientation(int displayOrientation) {
279318
}
280319
}
281320

321+
@Override
322+
boolean hasManualFocus() {
323+
return isCameraOpened() && getFacing() == Constants.FACING_BACK
324+
&& (isFocusAreaSupported() || isMeteringAreaSupported());
325+
}
326+
327+
@Override
328+
void setFocusAt(int x, int y) {
329+
if (isPictureCaptureInProgress.get()) {
330+
return;
331+
}
332+
mCallback.onFocusAt(x, y);
333+
if (isAutoFocusInProgress.getAndSet(false)) {
334+
mCamera.cancelAutoFocus();
335+
}
336+
if (!isAutoFocusInProgress.getAndSet(true) && setFocusAndMeterInternal(x, y)) {
337+
mCamera.setParameters(mCameraParameters);
338+
mCamera.autoFocus(new Camera.AutoFocusCallback() {
339+
@Override
340+
public void onAutoFocus(boolean success, Camera camera) {
341+
isAutoFocusInProgress.set(false);
342+
resumeContinuousAFAfterDelay(Constants.FOCUS_HOLD_MILLIS);
343+
}
344+
});
345+
}
346+
}
347+
348+
boolean isFocusAreaSupported() {
349+
if (Build.VERSION.SDK_INT >= 14) {
350+
List<String> supportedFocusModes = mCameraParameters.getSupportedFocusModes();
351+
return (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)
352+
&& mCameraParameters.getMaxNumFocusAreas() > 0);
353+
}
354+
return false;
355+
}
356+
357+
boolean isMeteringAreaSupported() {
358+
if (Build.VERSION.SDK_INT >= 14) {
359+
return mCameraParameters.getMaxNumMeteringAreas() > 0;
360+
}
361+
return false;
362+
}
363+
282364
/**
283365
* This rewrites {@link #mCameraId} and {@link #mCameraInfo}.
284366
*/
@@ -484,12 +566,88 @@ private boolean setAutoFocusInternal(boolean autoFocus) {
484566
} else {
485567
mCameraParameters.setFocusMode(modes.get(0));
486568
}
569+
570+
if (Build.VERSION.SDK_INT >= 14 && hasManualFocus()) {
571+
if (isFocusAreaSupported()) {
572+
mCameraParameters.setFocusAreas(null);
573+
}
574+
if (isMeteringAreaSupported()) {
575+
mCameraParameters.setMeteringAreas(null);
576+
}
577+
}
578+
579+
return true;
580+
} else {
581+
return false;
582+
}
583+
}
584+
585+
/**
586+
* @return {@code true} if {@link #mCameraParameters} was modified.
587+
*/
588+
private boolean setFocusAndMeterInternal(int x, int y) {
589+
if (Build.VERSION.SDK_INT >= 14 && hasManualFocus() && mCoordinateTransformer != null) {
590+
if (isFocusAreaSupported()) {
591+
List<Camera.Area> focusArea = Collections.singletonList(
592+
new Camera.Area(computeCameraRectFromPreviewCoordinates(x, y,
593+
getAFRegionSizePx()), 1));
594+
mCameraParameters.setFocusAreas(focusArea);
595+
}
596+
if (isMeteringAreaSupported()) {
597+
List<Camera.Area> meteringArea = Collections.singletonList(
598+
new Camera.Area(computeCameraRectFromPreviewCoordinates(x, y,
599+
getAERegionSizePx()), 1));
600+
mCameraParameters.setMeteringAreas(meteringArea);
601+
}
602+
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
487603
return true;
488604
} else {
489605
return false;
490606
}
491607
}
492608

609+
/**
610+
* @return {@code width} of auto focus region in pixels.
611+
*/
612+
private int getAFRegionSizePx() {
613+
return (int) (Math.min(mPreview.getWidth(), mPreview.getHeight())
614+
* Constants.AF_REGION_BOX);
615+
}
616+
617+
/**
618+
* @return {@code width} of metering region in pixels.
619+
*/
620+
private int getAERegionSizePx() {
621+
return (int) (Math.min(mPreview.getWidth(), mPreview.getHeight())
622+
* Constants.AE_REGION_BOX);
623+
}
624+
625+
private Rect computeCameraRectFromPreviewCoordinates(int x, int y, int size) {
626+
int left = CameraUtil.clamp(x - size / 2, mPreviewRect.left,
627+
mPreviewRect.right - size);
628+
int top = CameraUtil.clamp(y - size / 2, mPreviewRect.top,
629+
mPreviewRect.bottom - size);
630+
RectF rectF = new RectF(left, top, left +size, top+ size);
631+
return CameraUtil.rectFToRect(mCoordinateTransformer.toCameraSpace(rectF));
632+
}
633+
634+
private void resetCoordinateTransformer() {
635+
if (mPreview.getWidth() > 0 && mPreview.getHeight() > 0) {
636+
mCoordinateTransformer = new CameraCoordinateTransformer(
637+
mFacing == Constants.FACING_FRONT,
638+
calcCameraRotation(mDisplayOrientation),
639+
CameraUtil.rectToRectF(mPreviewRect));
640+
}
641+
}
642+
643+
/**
644+
* Resume AF_MODE_CONTINUOUS_PICTURE after FOCUS_HOLD_MILLIS.
645+
*/
646+
private void resumeContinuousAFAfterDelay(int millis) {
647+
mCameraHandler.removeCallbacks(mReturnToContinuousAFRunnable);
648+
mCameraHandler.postDelayed(mReturnToContinuousAFRunnable, millis);
649+
}
650+
493651
/**
494652
* @return {@code true} if {@link #mCameraParameters} was modified.
495653
*/

0 commit comments

Comments
 (0)