Skip to content

Instantly share code, notes, and snippets.

@gregkorossy
Last active November 22, 2019 11:38
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save gregkorossy/7de0b9fdd7a444e53b5a to your computer and use it in GitHub Desktop.
Save gregkorossy/7de0b9fdd7a444e53b5a to your computer and use it in GitHub Desktop.
Mobile Vision API fix for missing autofocus feature
/*
* IF YOU WANT TO JUST ACCESS THE CAMERA INSTANCE SO THAT YOU CAN SET ANY OF THE PARAMETERS, VISIT THE FOLLOWING LINK:
* https://gist.github.com/Gericop/364dd12b105fdc28a0b6
*/
/**
* Custom annotation to allow only valid focus modes.
*/
@StringDef({
Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
Camera.Parameters.FOCUS_MODE_AUTO,
Camera.Parameters.FOCUS_MODE_EDOF,
Camera.Parameters.FOCUS_MODE_FIXED,
Camera.Parameters.FOCUS_MODE_INFINITY,
Camera.Parameters.FOCUS_MODE_MACRO
})
@Retention(RetentionPolicy.SOURCE)
private @interface FocusMode {}
/**
* <p>
* Sets the Mobile Vision API provided {@link com.google.android.gms.vision.CameraSource}'s
* focus mode. Use {@link Camera.Parameters#FOCUS_MODE_CONTINUOUS_PICTURE} or
* {@link Camera.Parameters#FOCUS_MODE_CONTINUOUS_VIDEO} for continuous autofocus.
* </p>
* <p>
* Note that the CameraSource's {@link CameraSource#start()} or
* {@link CameraSource#start(SurfaceHolder)} has to be called and the camera image has to be
* showing prior using this method as the CameraSource only creates the camera after calling
* one of those methods and the camera is not available immediately. You could implement some
* kind of a callback method for the SurfaceHolder that notifies you when the imaging is ready
* or use a direct action (e.g. button press) to set the focus mode.
* </p>
* <p>
* Check out <a href="https://github.com/googlesamples/android-vision/blob/master/face/multi-tracker/app/src/main/java/com/google/android/gms/samples/vision/face/multitracker/ui/camera/CameraSourcePreview.java#L84">CameraSourcePreview.java</a>
* which contains the method <code>startIfReady()</code> that has the following line:
* <blockquote><code>mCameraSource.start(mSurfaceView.getHolder());</code></blockquote><br>
* After this call you can use our <code>cameraFocus(...)</code> method because the camera is ready.
* </p>
*
* @param cameraSource The CameraSource built with {@link com.google.android.gms.vision.CameraSource.Builder}.
* @param focusMode The focus mode. See {@link android.hardware.Camera.Parameters} for possible values.
* @return true if the camera's focus is set; false otherwise.
* @see com.google.android.gms.vision.CameraSource
* @see android.hardware.Camera.Parameters
*/
public static boolean cameraFocus(@NonNull CameraSource cameraSource, @FocusMode @NonNull String focusMode) {
Field[] declaredFields = CameraSource.class.getDeclaredFields();
for (Field field : declaredFields) {
if (field.getType() == Camera.class) {
field.setAccessible(true);
try {
Camera camera = (Camera) field.get(cameraSource);
if (camera != null) {
Camera.Parameters params = camera.getParameters();
if (!params.getSupportedFocusModes().contains(focusMode)) {
return false;
}
params.setFocusMode(focusMode);
camera.setParameters(params);
return true;
}
return false;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
return false;
}
@pm0733464
Copy link

Thanks. See also the focus mode constants here:

http://developer.android.com/reference/android/hardware/Camera.Parameters.html

(e.g., supplying "continuous-video" for focusMode should work well)

@Aeefire
Copy link

Aeefire commented Aug 17, 2015

or torch flash mode?

@gregkorossy
Copy link
Author

If you want to access the camera (so that you can set the other parameters as well), use this:
https://gist.github.com/Gericop/364dd12b105fdc28a0b6

@pm0733464
Copy link

Note that some devices don't support camera auto focus (hardware issue). You should probably do something like this:

if (params.getSupportedFocusModes().contains(focusMode)) {
    params.setFocusMode(focusMode);
    camera.setParameters(params);
    return true;
} else {
    // Camera auto focus is not supported on this device.
    return false;
}

@gregkorossy
Copy link
Author

Thanks for the note, updated the gist to check if the focus mode is supported.

@tundeaina
Copy link

Thanks Gergely! cameraFocus works like a charm. I'll try using getCamera next.

@joshfischer1108
Copy link

A lot of this code was deprecated in Api 21. Any fix on the way? Either way, nice work.

@gregkorossy
Copy link
Author

This is the official way Google does the camera handling (they don't use the new Camera 2 API in their code so I couldn't do it either).

@Mun0n
Copy link

Mun0n commented Sep 28, 2015

I can't get autofocus working. I'm doing something wrong for sure

CameraSource.Builder builder = new CameraSource.Builder(getApplicationContext(), barcodeDetector)
                .setFacing(CameraSource.CAMERA_FACING_BACK)
                .setRequestedPreviewSize(1600, 1024)
                .setRequestedFps(15.0f);

mCameraSource = builder.build();
cameraFocus(mCameraSource, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

I've also detected that the 1D barcodes are not detected since I've used this code.

Any help?

@gregkorossy
Copy link
Author

You're calling the cameraFocus(...) method before the Camera instance in the CameraSource object is initialized. After you call mCameraSource.start(...), you should be good. Here's the sample project's CameraSourcePreview's startIfReady() method as an example:

private void startIfReady() throws IOException {
    if (mStartRequested && mSurfaceAvailable) {
        mCameraSource.start(mSurfaceView.getHolder());
        MultiTrackerActivity.cameraFocus(mCameraSource, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        // [...]
    }
}

Note that the latest sample open sources the CameraSource class and its Builder has a setFocusMode(...) method that can be used instead of my temporary bugfix with reflection.

@Mun0n
Copy link

Mun0n commented Sep 29, 2015

Thanks for the response. I don't understand. Everything is working fine except in some Samsung devices like SM-N9005. It doesn't detect anything, even using the demo app from google. Any idea?

@gregkorossy
Copy link
Author

Are those devices connected to the Internet? Did you check if the detector isOperational()?

@hendrawd
Copy link

I was searching how to show line focus like zxing library to google camera API and got here. I little bit confused at first and think that this gist is still valid. Can you update the gist description, since the new example already have setFocusMode? It will be useful to inform the other users that got here without reading the comments or trying to implement the code. Thank you

@anroswart
Copy link

.setAutoFocusEnabled(true) does not work although my device has auto focus. http://stackoverflow.com/questions/41629911/

@sarimo1
Copy link

sarimo1 commented Apr 7, 2017

where can i add this code gyus . i'm a biginer
please tell me

@nguyenthao1988
Copy link

how to use file VisionApiFocusFix.java. Please share source scan qr code with mobile vision with fixed auto camera focus. Thanks all!

@ivnsch
Copy link

ivnsch commented Feb 27, 2018

This isn't necessary anymore... or am I missing something?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment