I’m having Android G1 device and while I’m doing the photos with integrated camera software I see that device is trying to focus before taking the photos (I hear the beep and see green border after camera is focused)
But here is the issue – how to focus the camera using the Android API from you android application ?
In the book “Professional Application Android Development” I’ve found only short example about using camera and it doesn’t use any autofocus features of the device/API. (see chapter 10 “Accessing Android Hardware”/”Using Camera”). It is actually an entry point but not the solution to take good pictures (I must admit it’s quite optimistic to say that G1 could make photos with good quality – probably only in a sunny day. But again – it will never be even close to the photos from Nokia N82)
CameraPreiew class (com.example.android.apis.graphics package) from the API-Examples shows only the way to start activity with preview from camera.
The key here is to call camera.autoFocus(autoFocusCallBack) and after we focused method autofocusCallback.onAutoFocus(boolean success, Camera camera) is called – call the camera.takePicture (Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg)
here is the example code (take a notice that everything here is happen inside onKeyDown event handler)
public final boolean onKeyDown(int keyCode, KeyEvent event) {
synchronized(this) {
if (!bIsPictureTaking) {
//we care only about two buttons here
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_CAMERA) {
//that method support tow modes with and without autofocus
if (USE_AUTOFOCUS){
//autofocus mode
if (!bIsPictureTaking && !bIsAutoFocusStarted){
//start autofocus if it was-not started
AutoFocusCallBackImpl autoFocusCallBack = new AutoFocusCallBackImpl();
cDevice.autoFocus(autoFocusCallBack);
//set the bIsAutoFocusStarted trigger to false to avoid extra autofocus attempts
bIsAutoFocusStarted = true;
return true;
}
long autoFocusTime = event.getEventTime() - event.getDownTime();
//autoFocusTime is the time we spent in the autofocusing
boolean isAutofocusTimeout = (bIsAutoFocusStarted && autoFocusTime > AUTOFOCUS_TIME_LIMIT_MILISECONDS);
if (bIsAutoFocused){
Log.i(TAG, "Autofocused, taking picture. Autofocus time="+autoFocusTime+" ms");
} else if (isAutofocusTimeout){
Log.i(TAG, "Autofocus timeout reached, taking picture. time for focus is:"+autoFocusTime+" ms");
}
if (bIsAutoFocused || isAutofocusTimeout){
//if camera got focused or we have autofocus-timeout - take the picture (we will never be focused in the darkness)
takePicture();
}
} else {
//non-autofocus mode, nothing special just take the picture
takePicture();
}
}
//support for the BACK button to exit from activity
if (keyCode == KeyEvent.KEYCODE_BACK) {
setResult(LifecycleConstants.CAMERA_CANCELLED);
return super.onKeyDown(keyCode, event);
}
}
}
return true;
}
private class AutoFocusCallBackImpl implements Camera.AutoFocusCallback {
@Override
public void onAutoFocus(boolean success, Camera camera) {
bIsAutoFocused = success; //update the flag used in onKeyDown()
Log.i(TAG, "Inside autofocus callback. autofocused="+success);
//play the autofocus sound
MediaPlayer.create(CameraActivity.this, R.raw.auto_focus).start();
}
}
private void takePicture(){
bIsPictureTaking = true; //set it to true to avoid onKeyDown dispatching during taking picture. it may be time-consuming
bIsAutoFocused = false; //reset to false
bIsAutoFocusStarted = false; //reset to false
//create the file to write output content (picture) to
String fileName = myDateFormat.format(new Date()).concat(".jpg");
ContentValues values = new ContentValues();
values.put(Media.TITLE, fileName);
values.put(Media.DESCRIPTION, "Image capture by camera");
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
OutputStream os = null;
try {
os = (FileOutputStream) getContentResolver().openOutputStream(uri);
} catch (Exception ex) {
Logger.getLogger("CameraActivity").log(Level.WARNING,"Failed to take Picture", ex);
setResult(LifecycleConstants.CAMERA_FAILED_TO_TAKE_PHOTO);
finish();
return;
}
//create ImageCaptureCallback and pass output stream to it
ImageCaptureCallback iccb = new ImageCaptureCallback(os, uri.toString());
//you also could add shuter callback to play sound for example
cDevice.takePicture(null, null, iccb);
findViewById(R.id.surface).setVisibility(View.INVISIBLE);
findViewById(R.id.SavingPhotoPanel).setVisibility(View.VISIBLE);
}
private class ImageCaptureCallback implements PictureCallback {
private OutputStream foStream;
private final String sFileName;
public ImageCaptureCallback(OutputStream filoutputStream, String fileName) {
this.foStream = filoutputStream;
this.sFileName = fileName;
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
boolean exception = false;
//write image and close output-stream
try {
foStream.write(data);
foStream.flush();
} catch (Exception ex) {
exception = true;
android.util.Log.v(getClass().getSimpleName(), "Error while taking photo", ex);
ex.printStackTrace();
} finally {
if (foStream != null){
try {
foStream.close();
} catch (Exception ex){
android.util.Log.v(getClass().getSimpleName(), "Error while taking photo", ex);
ex.printStackTrace();
}
}
}
//pass the information back to the caller-activity via Intent with Bundle (intent.putExtras(bundle))
Bundle bundle = new Bundle();
if (sFileName != null) {
//set the file-name property, so caller activity will be able to resolve the file to which picture was written to
bundle.putString(LifecycleConstants.PHOTO_URI, sFileName);
}
Intent intent = new Intent();
intent.putExtras(bundle);
setResult(exception ? LifecycleConstants.CAMERA_FAILED_TO_TAKE_PHOTO : LifecycleConstants.CAMERA_PHOTO_TAKEN, intent);
finish();
}
}
It’s the description of my short experience with Android autofocus, if you are interested in that topic you could explore ZXing library (which is actually scan Bar-Codes and QR-Codes but it also use autofocus inside //continuous autofocus)
and the very interesting ideas could be found in the “Snap Photo Pro” for Android, that software uses the accelerometer to stabilize the image. it also has the white-balance and other features. But it’s not an open-source, it’s a paid software. It would be very interesting to know how image-stabilization is implemented and I think it would be very useful component if they will make their software available as a component (like ZXing) which you can use/integrate with your application via Intent/Activity
Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
activity.startActivityForResult(intentScan, requestCode);