Recipe Customizing the Camera

Control of the camera is abstracted into various components in the Android system:

■ Camera class—Accesses the camera hardware

■ Camera.Parameters class—Specifies the camera parameters such as picture size, picture quality, flash modes, and method to assign Global Positioning System (GPS) location

■ Camera Preview methods—Sets the camera output display and toggles streaming video preview to the display

■ SurfaceView class—Dedicates a drawing surface at the lowest level of the view hierarchy as a placeholder to display the camera preview

Before describing how these are tied together, the layout structure is introduced.The main layout is shown in Listing 7.1 and includes a SurfaceView to hold the camera output.

Listing 7.1 res/layout/main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical">

<SurfaceView android:id="@+id/surface" android:layout_width="fill_parent" android:layout_height="fill_parent">

</SurfaceView>

</LinearLayout>

A control interface can be added on top of this view by using a separate layout, as shown in Listing 7.2.This layout contains a button at the bottom, center of the screen to take a picture.

Listing 7.2 res/layout/cameraoverlay.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:gravity="bottom" android:layout_gravity="bottom">

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"

android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_horizontal"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="take picture" />

</LinearLayout> </LinearLayout>

The main activity involves multiple functionalities. First, the layout is set up as follows:

1. The window settings are changed to be translucent and full screen. (In this instance, they hide the title and notification bar.)

2. The SurfaceView defined in the previous layout (R.id.surface) is then filled by the camera preview. Each SurfaceView contains a SurfaceHolder for access and control over the surface.The activity is added as the SurfaceHolder's callback and the type is set to SURFACE_TYPE_PUSH_BUFFERS, which means it creates a "push" surface and the object does not own the buffer.This makes video streaming more efficient.

3. A LayoutInflater is declared to inflate another layout (cameraoverlay.xml) over the original (main.xml) layout.

Next, the activity sets a trigger for taking a picture:

1. An OnClickListener is added on the button from the cameraoverlay layout, so when clicked, it takes a picture (mCamera.takePicture()).

2. The takePicture() method needs three methods to be defined:.

■ ShutterCallback() to define any effects needed after the picture is taken, such as a sound to let the user know that picture has been captured.

■ A PictureCallback() for raw picture data if hardware has enough memory to support this feature. (Otherwise. the data might return as null.)

■ A second PictureCallback() for the compressed picture data.This calls the local method done() to save the picture.

Then, the activity saves any pictures that were taken:

1. The compressed picture byte array is saved to a local variable tempdata for manipu-lation.The BitmapFactory is used to decode the ByteArray into a Bitmap Object.

2. The media content provider is used to save the bitmap and return a URL. If this main activity were called by another activity, this URL would be the return information to the caller activity to retrieve the image.

3. After this process, finish() is called to kill the activity.

Finally, the activity sets up a response to a change in the surface view:

1. A SurfaceHolder.CallBack interface is implemented.This requires three methods to be overridden:

■ surfaceCreated()—Called when the surface is first created. Initialize objects here.

■ surfaceChanged()—Called after surface creation and when the surface changes (for example, format or size).

■ surfaceDestroyed()—Called between removing the surface from the view of the user and destroying the surface.This is used for memory cleanup.

2. The parameters for the camera are changed when the surface is changed (such as the PreviewSize based on the surface size).

These functionalities are in the complete activity shown in Listing 7.3. Listing 7.3 src/com/cookbook/hardware/CameraApplication.java package com.cookbook.hardware;

import android.app.Activity;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.PixelFormat;

import android.hardware.Camera;

import android.hardware.Camera.PictureCallback;

import android.hardware.Camera.ShutterCallback;

import android.os.Bundle;

import android.provider.MediaStore.Images; import android.util.Log; import android.view.Layoutlnflater; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.Toast;

public class CameraApplication extends Activity implements SurfaceHolder.Callback { private static final String TAG = "cookbook.hardware"; private Layoutlnflater mInflater = null; Camera mCamera; byte[] tempdata;

boolean mPreviewRunning = false; private SurfaceHolder mSurfaceHolder; private SurfaceView mSurfaceView;

Button takepicture;

^Override public void onCreate(Bundle savedlnstanceState) { super.onCreate(savedlnstanceState);

getWindow().setFormat(PixelFormat.TRANSLUCENT); requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

setContentView(R.layout.main);

mSurfaceView = (SurfaceView)findViewByld(R.id.surface); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this);

mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

mInflater = Layoutlnflater.from(this);

View overview = mInflater.inflate(R.layout.cameraoverlay, null); this.addContentView(overView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); takepicture = (Button) findViewById(R.id.button); takepicture.setOnClickListener(new OnClickListener(){ public void onClick(View view){

mCamera.takePicture(mShutterCallback, mPictureCallback, mjpeg);

ShutterCallback mShutterCallback = new ShutterCallback(){ @Override public void onShutter() {}

PictureCallback mPictureCallback = new PictureCallback() {

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

PictureCallback mjpeg = new PictureCallback() {

public void onPictureTaken(byte[] data, Camera c) { if(data !=null) { tempdata=data; done();

Bitmap bm = BitmapFactory.decodeByteArray(tempdata,

0, tempdata.length); String url = Images.Media.insertImage(getContentResolver(), bm, null, null); bm.recycle();

bundle.putString("url", url);

Intent mIntent = new Intent(); mlntent.putExtras(bundle); setResult(RESULT_OK, mIntent); } else {

Toast.makeText(this, "Picture can not be saved", Toast.LENGTH_SHORT).show();

^Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.e(TAG, "surfaceChanged"); try {

if (mPreviewRunning) {

mCamera.stopPreview(); mPreviewRunning = false;

Camera.Parameters p = mCamera.getParameters(); p.setPreviewSize(w, h);

mCamera.setParameters(p);

mCamera.setPreviewDisplay(holder);

mCamera.startPreview();

mPreviewRunning = true;

@Override public void surfaceCreated(SurfaceHolder holder) { Log.e(TAG, "surfaceCreated"); mCamera = Camera.open();

@Override public void surfaceDestroyed(SurfaceHolder holder) { Log.e(TAG, "surfaceDestroyed"); mCamera.stopPreview(); mPreviewRunning = false; mCamera.release(); mCamera=null;

Note the camera preview from the camera hardware is not standardized, and some Android devices might show the preview sideways. In this case, simply add the following to the onCreate() method of the CameraPreview activity:

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Character Building Thought Power

Character Building Thought Power

Character-Building Thought Power by Ralph Waldo Trine. Ralph draws a distinct line between bad and good habits. In this book, every effort is made by the writer to explain what comprises good habits and why every one needs it early in life. It draws the conclusion that habits nurtured in early life concretize into impulses in future for the good or bad of the subject.

Get My Free Ebook


Post a comment