I\'ve been battling with this feature for couple of days now...
It seems, that camera is ignoring(?) focus areas that I\'ve defined. Here is snippets of the code:
My problem was much simpler :)
All I had to do is cancel previously called autofocus. Basically the correct order of actions is this:
protected void focusOnTouch(MotionEvent event) {
if (camera != null) {
camera.cancelAutoFocus();
Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
Rect meteringRect = calculateTapArea(event.getX(), event.getY(), 1.5f);
Parameters parameters = camera.getParameters();
parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
parameters.setFocusAreas(Lists.newArrayList(new Camera.Area(focusRect, 1000)));
if (meteringAreaSupported) {
parameters.setMeteringAreas(Lists.newArrayList(new Camera.Area(meteringRect, 1000)));
}
camera.setParameters(parameters);
camera.autoFocus(this);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
...
Parameters p = camera.getParameters();
if (p.getMaxNumMeteringAreas() > 0) {
this.meteringAreaSupported = true;
}
...
}
/**
* Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
*/
private Rect calculateTapArea(float x, float y, float coefficient) {
int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
int left = clamp((int) x - areaSize / 2, 0, getSurfaceView().getWidth() - areaSize);
int top = clamp((int) y - areaSize / 2, 0, getSurfaceView().getHeight() - areaSize);
RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
matrix.mapRect(rectF);
return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
}
private int clamp(int x, int min, int max) {
if (x > max) {
return max;
}
if (x < min) {
return min;
}
return x;
}
use FOCUS_MODE_FIXED
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
mCamera = Camera.open(mCameraId);
} else {
mCamera = Camera.open();
}
cameraParams = mCamera.getParameters();
// set the focus mode
cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
// set Camera parameters
mCamera.setParameters(cameraParams);
Hi, try below code copy and change for yourself
public class CameraActivity extends AppCompatActivity implements Camera.AutoFocusCallback {
private Camera camera;
private FrameLayout fl_camera_preview;
...
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView( R.layout.camera_activity );
//this View, is lens camera
fl_camera_preview = findViewById( R.id.fl_camera_preview );
Button someButtonCapturePicture = findViewById(R.id.someButtonCapturePicture);
pictureCall = getPictureCallback();
//check camera access
if ( getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) ) {
if ( safeCameraOpen(0) ) {
cameraPreview = new CameraPreview( this, camera );
fl_camera_preview.addView( cameraPreview );
someButtonCapturePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
camera.takePicture(null, null, pictureCall);
}
});
} else {
Log.w(TAG, "getCameraInstance: Camera is not available (in use or does not exist)." );
}
}
}
private boolean safeCameraOpen(int id) {
boolean qOpened = false;
try {
camera = Camera.open( id );
// set some parameters
Camera.Parameters par = camera.getParameters();
List<Camera.Size> supportedPreviewSizes = par.getSupportedPreviewSizes();
for ( Camera.Size cs : supportedPreviewSizes ) {
if ( cs.height == 720 ) {
par.setPictureSize(cs.width, cs.height);
par.setPreviewSize(cs.width, cs.height);
break;
}
}
camera.setParameters(par);
qOpened = ( camera != null );
} catch (Exception e) {
Log.e(TAG, "safeCameraOpen: failed to open Camera");
e.printStackTrace();
}
return qOpened;
}
public void touchFocusCamera( final Rect touchFocusRect ) {
//Convert touche coordinate, in width and height to -/+ 1000 range
final Rect targetFocusRect = new Rect(
touchFocusRect.left * 2000/fl_camera_preview.getWidth() - 1000,
touchFocusRect.top * 2000/fl_camera_preview.getHeight() - 1000,
touchFocusRect.right * 2000/fl_camera_preview.getWidth() - 1000,
touchFocusRect.bottom * 2000/fl_camera_preview.getHeight() - 1000);
final List<Camera.Area> focusList = new ArrayList<Camera.Area>();
Camera.Area focusArea = new Camera.Area(targetFocusRect, 1000);
focusList.add(focusArea);
Camera.Parameters para = camera.getParameters();
List<String> supportedFocusModes = para.getSupportedFocusModes();
if ( supportedFocusModes != null &&
supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO) ) {
try {
para.setFocusAreas(focusList);
para.setMeteringAreas(focusList);
camera.setParameters(para);
camera.autoFocus( CameraActivity.this );
} catch (Exception e) {
Log.e(TAG, "handleFocus: " + e.getMessage() );
}
}
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
if ( success ) {
camera.cancelAutoFocus();
}
float focusDistances[] = new float[3];
camera.getParameters().getFocusDistances(focusDistances);
}
/**
* Get Bitmap from camera
* @return picture
*/
private Camera.PictureCallback getPictureCallback() {
Camera.PictureCallback picture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.i(TAG, "onPictureTaken: size bytes photo: " + data.length );
}
};
return picture;
}
...
}
//And SurfaceView with Callback
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
SurfaceHolder holder;
Camera camera;
public CameraPreview( Context context, Camera _camera ) {
super(context);
camera = _camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
holder = getHolder();
holder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if( event.getAction() == MotionEvent.ACTION_DOWN ) {
// Get the pointer's current position
float x = event.getX();
float y = event.getY();
float touchMajor = event.getTouchMajor();
float touchMinor = event.getTouchMinor();
Rect touchRect = new Rect(
(int)(x - touchMajor/2),
(int)(y - touchMinor/2),
(int)(x + touchMajor/2),
(int)(y + touchMinor/2));
((CameraActivity)getContext())
.touchFocusCamera( touchRect );
}
return true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (this.holder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
camera.setPreviewDisplay(this.holder);
camera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
...
}
Beside setting:
parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
you need to set:
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
if you want real 'live' auto-focus. Also, it will be good to check available focuses:
List<String> focusModes = parameters.getSupportedFocusModes();
LLog.d("focusModes=" + focusModes);
if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
On Samsung S6 you must set this with little delay (~ 500 ms) after getting camera preview.
I had this problem today :/
And after hours of struggling, I found the solution!
It's strange, but it appears that setting focus-mode to "macro" right before setting focus-areas solved the problem ;)
params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
params.setFocusAreas(focusAreas);
mCamera.setParameters(params);
I have Galaxy S3 with Android 4.1.2
I hope this will work for you either :)