Friday, January 21, 2011

Controlling Android Camera

Recently, I have a requirement of how to programmatically control Android camera on taking snapshots periodically. With some research and help form Android SDK’s example, the task was successfully accomplished and herewith is the how to.


Android’s Camera class


The Camera object provides the programmatic interface to the Camera hardware.

- Create a Camera object

e.g. Camera mCamera = Camera.open();

- Set Camera parameters

Camera.Parameters params = mCamera.getParameters();

params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);

mCamera.setParameters(params);

- Create a Camera.PictureCallback function

e.g.

Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {

public void onPictureTaken(byte[] data, Camera camera) {

System.out.println("data length="+data.length);

System.out.println("data="+data);

// Do something …

}

};

- Calls the takePicture() function with the callback function

e.g. mCamera.takePicture(null, null, jpegCallback);

Tip 1: The takePicture() won’t work unless camera is on previewing display mode. The Android SDK has an example of activating the previewing mode.

Tip 2: takePicture() is invoked through a Handler and make the jpegCallback function to run on another thread.

- Release camera

e.g mCamera.release();


Periodic Camera Activity


- An activity class (i.e. CameraActivity) is created with all the Camera control logic.

- Create a PendingIntent and register the CameraActivity to AlarmManager

e.g.
AlarmManager am=(AlarmManager).getSystemService(Context.ALARM_SERVICE);

Intent anIntent=new Intent(this,CameraActivity.class);

PendingIntent pperation =PendingIntent.getActivity(this,0,anIntent,PendingIntent.FLAG_UPDATE_CURRENT);

am.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, interval, operation);



Source - CameraActivity.java


class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;

Preview(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
try {
long delayMillis=3000;
mCamera.setPreviewDisplay(holder);
Handler aHandler=new Handler();
aHandler.postDelayed(new Runnable(){
public void run() {
takePicture();
}
}, delayMillis);

} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}

public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mCamera=Camera.open();
mCamera.getParameters().setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
mPreview = new Preview(this);
setContentView(mPreview);
}


private void takePicture(){
Camera.PictureCallback jpegCallback;
final Context ctx=this;
jpegCallback=new Camera.PictureCallback() {

public void onPictureTaken(byte[] data, Camera camera) {
System.out.println("data length="+data.length);
System.out.println("data="+data);
final ProgressDialog aDialog=ProgressDialog.show(ctx,"Camera action","starting...");
final Handler aHandler=new Handler();
new Thread(new Runnable(){
public void run(){
// Do something ...
aDialog.dismiss();
System.out.println("Take pic and send to server ... done");
Events.list.add(((new Date())+" picture taken."));
aHandler.post(new Runnable(){
public void run(){
finishActivity();
}
});
}
}).start();
}
};
mCamera.takePicture(null, null, jpegCallback);

}

protected void finishActivity(){
System.out.println("CameraAcivity finished");
mPreview.invalidate();
this.finish();
}
}