I\'m working on an app which has a custom camera screen, for which I\'m supposed to implement tap to focus, like in the Android(more specifically, the Galaxy S4) camera app.
I have the same issue. I've checked this on many devices, and many Android versions.
It appears that focus-area is not working in CONTINUOUS focus-mode.
My workaround is to set focus-mode to AUTO or MACRO along with setting focus-area:
params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
params.setFocusAreas(focusAreas);
mCamera.setParameters(params);
Please note that the stock Camera app on Galaxy S3 & S4 works the same way: it's permanently in continuous mode. When you touch the screen it switches to auto & sets focus-area. But after a while it comes back to continuous mode, and focus-area goes back to the center of the screen.
I hope this helps you somehow.
this has the solution. I just added the implementation of some missing methods in his code.
private static final int FOCUS_AREA_SIZE= 300;
//
mCameraPreview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
focusOnTouch(event);
}
return true;
}
});
//
private void focusOnTouch(MotionEvent event) {
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<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
meteringAreas.add(new Camera.Area(rect, 800));
parameters.setFocusAreas(meteringAreas);
mCamera.setParameters(parameters);
mCamera.autoFocus(mAutoFocusTakePictureCallback);
}else {
mCamera.autoFocus(mAutoFocusTakePictureCallback);
}
}
}
private Rect calculateFocusArea(float x, float y) {
int left = clamp(Float.valueOf((x / mCameraPreview.getWidth()) * 2000 - 1000).intValue(), FOCUS_AREA_SIZE);
int top = clamp(Float.valueOf((y / mCameraPreview.getHeight()) * 2000 - 1000).intValue(), FOCUS_AREA_SIZE);
return new Rect(left, top, left + FOCUS_AREA_SIZE, top + FOCUS_AREA_SIZE);
}
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;
}
// implement this callback to trigger the focus.
private Camera.AutoFocusCallback mAutoFocusTakePictureCallback = new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
// do something...
Log.i("tap_to_focus","success!");
} else {
// do something...
Log.i("tap_to_focus","fail!");
}
}
};
Bumped into this issue recently. As MatheusJardimB said, this question helps a lot.
However, in my case, I wanted to start in the ContinuousPicture
mode then be able to tap to focus and then continue with the ContinuousPicture
mode.
I managed to get it to work by using the onAutoFocus
method of the Camera.AutoFocusCallback()
. I'm not sure if it's the best or the prettiest way of doing it, but it seems to work.
Here's the code:
setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mCamera != null) {
Camera camera = mCamera.getCamera();
camera.cancelAutoFocus();
Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
Parameters parameters = camera.getParameters();
parameters.setFocusMode(Parameters.FOCUS_MODE_MACRO);
if (parameters.getMaxNumFocusAreas() > 0) {
List<Area> mylist = new ArrayList<Area>();
mylist.add(new Camera.Area(focusRect, 1000));
parameters.setFocusAreas(mylist);
}
camera.setParameters(parameters);
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
camera.cancelAutoFocus();
Parameters params = camera.getParameters();
if (!params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
camera.setParameters(params);
}
}
});
}
return true;
}
return false;
});
You could just change the focus area to
ArrayList<Area> focusAreas = new ArrayList<Camera.Area>(1);
focusAreas.add(new Area(new Rect(-1000, -1000, 1000, 0), 750));
and it should work.
UPDATE
I recently acquired a Samsung S5 and tested this out on it. It didn't work that well, so I added a few modifications and it's working now. This was also successfully tested on the Galaxy S6 and Galaxy Note4.
Here's the modified code:
setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mCamera != null) {
Camera camera = mCamera.getCamera();
camera.cancelAutoFocus();
Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
Parameters parameters = camera.getParameters();
if (parameters.getFocusMode().equals(
Camera.Parameters.FOCUS_MODE_AUTO) {
parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
}
if (parameters.getMaxNumFocusAreas() > 0) {
List<Area> mylist = new ArrayList<Area>();
mylist.add(new Camera.Area(focusRect, 1000));
parameters.setFocusAreas(mylist);
}
try {
camera.cancelAutoFocus();
camera.setParameters(parameters);
camera.startPreview();
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (!camera.getParameters().getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Parameters parameters = camera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
if (parameters.getMaxNumFocusAreas() > 0) {
parameters.setFocusAreas(null);
}
camera.setParameters(parameters);
camera.startPreview();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
});
One of the other answers causes your camera to discard the focus points previously given and return to continuous focus which I don't think makes sense.
Also if you take a look at the link in the post the original answer uses parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
I've implemented the above with this line of code instead of Continuous focus and it seems to work much better.
binding.cPreview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCamera.autoFocus(myAutoFocusCallback);
}
});
Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback(){
@Override
public void onAutoFocus(boolean arg0, Camera arg1) {
// TODO Auto-generated method stub
}};