How to use the Android Camera

I have now spent quite a few hours programming for my next app which needs to take pictures. I did not want to use the camera app that’s already there for several reasons. So I need to programm my own. The API is not all that difficult to understand. Here’s the basic version of how to talk to the camera:

[sourcecode language=”java” wraplines=”true”]
//creating the camera object
Camera camera = Camera.open();
camera.setPreviewDisplay(getSurfaceHolder());
final Camera.Parameters parameters = findBestParameters(w, h);
camera.setParameters(parameters);
camera.startPreview();
final PictureCallback callback = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
//async task for storing the photo
new SavePhotoTask(CameraView.this.ctx, data).execute();
} catch (final SavePhotoException e) {
//some exceptionhandling
}
}
};
//no need for shutter callback or raw callback, jpg callback is enough
camera.takePicture(null, null, callback);
[/sourcecode]

Doesn’t sound so hard? It only took me hours to get it right. Because I never got to the onPictureTaken(...) method. The callback never happend! I made the mistake wanting to do something else after taking the picture – who wouldn’t?

There are several issues with that. It takes the phone quite a while (~5 seconds) to actually take that picture once the camera.takePicture(...) method is called. Since the method is an asynchronous callback you can do all kinds of fun things(tm), while waiting for the result. For example I managed to execute some very important piece of code:

[sourcecode language=”java” wraplines=”true”]
public void clearCamera() {
if (this.camera != null) {
try {
this.camera.stopPreview();
this.camera.release();
this.camera = null;
} catch (final Exception e) {
//handle some exceptions
}
}
}
[/sourcecode]

This should be called by onPause() of your activity (and onResume() you should of course re-open the camera!). So if for some reason while you do the fun things(tm) I mentionned above your activity decides to take a break, the callback never happens! Ouch.

So how did I get my activity to wait for the callback and then do something?

In the first code sample you can see that the actual picture storing takes place in a class called SavePhotoTask. This class is an asynchronous task that offers the functionality I needed. Please notice that since the first code sample some things changed and the task now also implements the callback interface:

[sourcecode language=”java” wraplines=”true”]
public class SavePhotoTask
extends AsyncTask<Boolean, Void, File>
implements PictureCallback {

//fill in the rest as a light exercise at home
private final ProgressDialog dialog;

@Override
protected void onPreExecute() {
this.dialog.setMessage(String.format("Saving Picture"));
this.dialog.show();
}

@Override
protected File doInBackground(Boolean… params) {
this.camera.takePicture(null, null, this);
return this.spot.getPhoto();
}

@Override
protected void onPostExecute(final File success) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
if (success != null && success.exists()) {
DialogFactory.keepPhotoDialog(this.ctx, this.photo).show();
} else {
Toast.makeText(this.ctx, "You failed!", Toast.LENGTH_SHORT).show();
}
}

@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
//I guess you know how to save a file
saveFile(data);
} catch (final Exception e) {
//capture flying shit
}
}
}
[/sourcecode]

So now I can execute my picture taking as an asynchronous task, that gets a callback to onPostExecute(...) when it is finished. I can then open another dialog prompting the user to do something. I introduced that additional dialog to get a break before leaving the original activity (remember how leaving will close the camera and we should not do it before the picture is stored safely on the sdcard).

So to keep it complete, here’s the final piece of code: the dialog.

[sourcecode language=”java” wraplines=”true”]
public static AlertDialog keepPhotoDialog(final Activity a, final MyPhoto photo) {
final AlertDialog.Builder builder = new AlertDialog.Builder(a);
builder.setMessage("Keep photo?");
builder.setCancelable(false);
builder.setPositiveButton("yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
final Intent i = new Intent(a, DoFunThingsActivity.class);
i.putExtra(DoFunThingsActivity.PHOTO, photo);
a.startActivity(i);
}
});
builder.setNegativeButton("no", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
final File file = new File(photo.getFilename());
if (file.exists()) {
file.delete();
}
dialog.dismiss();
//you might want to call startPreview() again at this point
}
});
return builder.create();
}
[/sourcecode]

So here’s it, I chained two dialogs to take a picture and do fun things(tm) with it later without having to start handle threads and all that stuff.

Any questions?

This entry was posted in android. Bookmark the permalink.