
Marko Gargenta
Marakana, Inc.
Android SDK supports the connectivity to the built-in camera. Using the camera to take photos is relatively easy. It is somewhat harder to setup the camera preview to work properly.
In our main activity, we create the Preview object. This object will create the Camera object and return it to the CameraDemo activity.
Next we register couple of call-back method with the Camera to be performed when the user takes a photo.
shutterCallback is called when the shutter is opened and picture is taken.
rawCallback and
jpegCallback will get the data for the raw and jpeg encoding of the photo. It's up to you to do something with this data, such as save it to the SD card.
CameraDemo.java
Code:
package com.example;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
public class CameraDemo extends Activity {
private static final String TAG = "CameraDemo";
Camera camera;
Preview preview;
Button buttonClick;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preview = new Preview(this);
((FrameLayout) findViewById(R.id.preview)).addView(preview);
buttonClick = (Button) findViewById(R.id.buttonClick);
buttonClick.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
preview.camera.takePicture(shutterCallback, rawCallback,
jpegCallback);
}
});
Log.d(TAG, "onCreate'd");
}
ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
Log.d(TAG, "onShutter'd");
}
};
/** Handles data for raw picture */
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken - raw");
}
};
/** Handles data for jpeg picture */
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
// write to local sandbox file system
// outStream =
// CameraDemo.this.openFileOutput(String.format("%d.jpg",
// System.currentTimeMillis()), 0);
// Or write to sdcard
outStream = new FileOutputStream(String.format(
"/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Log.d(TAG, "onPictureTaken - jpeg");
}
};
}
Preview class handles the preview from the camera. It subclasses SurfaceView class so that it can be placed in the UI itself. It also implements the SurfaceHolder.Callback interface so it gets the callbacks when the UI becomes available.
Preview.java
Code:
package com.example;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
class Preview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "Preview";
SurfaceHolder mHolder;
public Camera camera;
Preview(Context context) {
super(context);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
camera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera arg1) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format(
"/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d(TAG, "onPreviewFrame - wrote bytes: "
+ data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Preview.this.invalidate();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// Because the CameraDevice object is not a shared resource, it's very
// important to release it when the activity is paused.
camera.stopPreview();
camera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(w, h);
camera.setParameters(parameters);
camera.startPreview();
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
Paint p = new Paint(Color.RED);
Log.d(TAG, "draw");
canvas.drawText("PREVIEW", canvas.getWidth() / 2,
canvas.getHeight() / 2, p);
}
}
The layout is fairly straight forward. We have the FrameLayout as the placeholder for the Preview to be attached to. This is done programmatically in CameraDemo.onCreate().
/res/layout/main.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:id="@+id/layout">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Camera Demo"
android:textSize="24sp" />
<FrameLayout android:id="@+id/preview"
android:layout_weight="1" android:layout_width="fill_parent"
android:layout_height="fill_parent">
</FrameLayout>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/buttonClick"
android:text="Click" android:layout_gravity="center"></Button>
</LinearLayout>
And finally remember to add
<uses-permission android:name="android.permission.CAMERA" /> to your AndroidManifest.xml file.
The final app looks like this:
Source Code:/static/tutorials/CameraDemo.zip
Edited 7 times. Last edit by Marko Gargenta on Jul 26, 2010 at 3:56:04 PM (about 5 weeks ago).

Me Me
Me
Thanks, that was very helpful.
It is better to call camera.release() when finishing the activity.

Me Me
Org
Where you save the image with FileOutputStream, I get "java.lang.IllegalArgumentException: File /sdcard/whatever.jpg contains a path separator". Any ideas?

A Member
Org
Thanks, I tried the code on my android phone. I am seeing a picture orientation problem. On focus I see on the phone screen a picture that is inverted. I am trying to figure why this happens. If you have an answer to this, please let me know.

SeungHun Lee
Iconlab
How to use OCR??

A Member
Org
OCR?? What does it stand for?

Chun Ming Chin
UIUC
This code only allows us to take a snap shot once before it freezes over. How could we make it take multiple shots and save it onto a file system or SD card?

Chun Ming Chin
UIUC
Optical Character Recognition

Nan Z
GoldSequence
First of all, it is really appreciated that you can post this sample application.
I tried to bring up this app in OS 2.2 and run in Nexus one phone. However, the app crashes and DDMS shows the following message:
ERROR/QualcommCameraHardware(59): Invalid preview size requested: 480x604
The problem can be fixed by using getOptimalPreviewSize() function and surfaceChanged() function provided in an Android sample program CameraPreview.java. It can be found at
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html (retrieved today)
However, I still observe camera orentation and image size distortion problems.
Edited one time. Last edit by Nan Z on Jul 14, 2010 at 9:40:29 AM (about 5 weeks ago).

Marko Gargenta
Marakana, Inc.
Hmm, I'll have to test this on an actual NexusOne. I do have a newer version of the code here:
https://marakana.com/static/courseware/android/Camera.zip

Luka Divac Krnic
Me
Hello Marko. The last one Camera.zip works fine on my HTC with Android 2.1 (the last code somehow never did). There is only one peculiarity: once I activate your new Camera Demo, I can not start the Camera App of HTC Corpotion or any other App that uses the cam. When I restart the Phone, everything is again OK. Seems some resources stay allocated "forever".
Greetings, Luka

Marko Gargenta
Marakana, Inc.
Hi Luka,
You may want to try this new and improved version of Camera app. Here is the code:
https://marakana.com/static/courseware/android/Camera.zip.
It is possible that in the old code camera object was not released properly so other apps weren't able to get a hold of the camera.
Cheers,
Marko

Sai Kiran Veluri
Lead Engineer
Incube
Hi,
i am new bee to android development, and we have a requirement that we need to take a picture, but we should not show the camera preview. Is it possible with Android camera API's?, if yes, could you please let me know, how to achieve this.
Thanks & Regards,
Sai Kiran V.

Marko Gargenta
Marakana, Inc.
Yes, it's possible. The CameraDemo does that, ++.