Say Cheese: Building a Photo App for Your Android Device

Learn how to snap a picture and display it in your application

5 Megapixels at Your Service, If You Please

Today it is hard to think of a phone without a camera.

In fact we are just as likely to take a picture with our phone as we are to make a call.

And once we take a photo, we are quite likely to send it as a message to someone else, but that is a topic for another day!

In this column we are going to write a simple Android application which demonstrates taking a photo and displaying it to the screen of your phone.

The User Interface

Our application, which we name “Photo Booth” is very simple.

It contains only three “widgets” within a basic linear layout:

  • A TextView to convey a simple banner. In our case it just says “Smile!”
  • A Button widget with some simple text which says “Take Photo”.
  • An ImageView widget which is used to display our image once it has been acquired.

This UI is defined in XML in the file named res/main.xml.

<?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"
    >
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Smile !"
    />
    <Button android:id="@+id/TakePhoto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Take Photo"
    />
    <ImageView android:id="@+id/PictureFrame"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"/>
</LinearLayout>

This layout is as expected pretty plain in the phone UI as shown below.

Basic UI before an image is captured
Basic UI before an image is captured

OK, so now that we know what the UI looks like, let’s check out the code to make the application work.

The Code

To review this code, we will break it down into three sections. The first section to review is the list of “import” statements.

Every Java application — and Android is no exception — needs to include the requisite import statements to define for the code which classes are to be used when the application is compiled. Here are the imports used by this application:

package com.msi.linuxmag;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Button;
import android.view.View;
import android.content.Intent;
import android.graphics.Bitmap;

The boiler-plate Android application includes the android.app.Activity and android.os.Bundle imports. I always like to add the Log class to add statements to the logging interface within Eclipse as a debugging aid.

Beyond those, we include imports for the ImageView, the Button, the View (to get the OnClickListener method), the Intent and of course, the Bitmap which is used to manage our image.

With the imports all set, let’s look at the structure of the class itself.

All UI based Android applications include at least a single class which extends the android.app.Activity class. In our case, the class name is PhotoBooth:

public class PhotoBooth extends Activity {
	protected ImageView iv = null;
	protected Bitmap b = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.i(PhotoBooth.class.getName(),"Activity Ready to Go!");

        final Button  btn = (Button) this.findViewById(R.id.TakePhoto);
        btn.setOnClickListener(new View.OnClickListener(){

        	public void onClick(View v){
        		Log.i(PhotoBooth.class.getName(),"Button Clicked!");
        		try {
        			Intent action = new Intent("android.media.action.IMAGE_CAPTURE");
        			startActivityForResult(action,1);
        		} catch (Exception e) {
        			Log.e(PhotoBooth.class.getName(),"Error occured [" + e.getMessage() + "]");
        		}
        	}
        });

        iv = (ImageView) this.findViewById(R.id.PictureFrame);

    }
     // onActivityResult goes here (defined below)
}

Our application defines two Activity-scoped variables: iv which is an ImageView and b which is a Bitmap. Please pardon the highly descriptive variable names.

The onCreate method is invoked when the application is launched and the Activity is activated. The first thing it does is call the super class’s onCreate method as all over-ride methods ought to do.

Next, the method “inflates” the layout named R.layout.main, which was shown above. This causes the user interface to be created and shown to the user.

The next thing that takes place is the “connecting” of a Button variable with the Button defined in the layout. The primary purpose if this step is so we can define an anonymous class to act as the Button’s “OnClickListener”.

The OnClickListener itself performs the important task of initiating the “image capture preview” operation by way of the Android technique of defining and starting an “Intent”.

An Intent is a construct used by Android to define a particular action and submit a request for its fulfillment. Optionally, an Intent can pass data along with the request.

Intents can be implicit or explicit. An explicit Intent uniquely defines which Activity is to be initiated. An implicit Intent, such as we are using here, is used to allow the Android platform to determine how a particular Intent is “dispatched”.

Note that if there is no registered “handler” for a particular Intent type Android throws a Java Exception. If you spend any time writing Android code, you will see this for yourself the first time you fat-finger the Intent!

If you are interested in learning more about the structure of Android applications and Intents in particular, you can browse the first chapter of Unlocking Android which is freely available from the publisher. Or you can read the online documentation here.

Once the Button is selected, the application launches a “preview” window.

Previewing an image
Previewing an image

The image is the remains of a remote control car my son had lying around on his desk. For the first person to find the item that “doesn’t belong” in this photo I will send you a complimentary copy of Unlocking Android, Second Edition. Contact me via email (address is at the bottom of this article).

When the button is pressed, the Intent is setup and dispatched with the call to startActivityForResult().

The “for result” implies that we want notification that the image has been taken — this happens via the “callback” method defined within the Activity. This method has a particular name: onActivityResult. We will review that in just a moment.

To round out the code in the onCreate() method note that we also connect the ImageView variable in code so we can programmatically manipulate it after we have taken our photo.

Handling the Image

Now that the photo has been “snapped” we need to do something with the image. This is where the onActivityResult method comes into play.

  protected void onActivityResult(int requestCode,int resultCode,Intent data)
    {
    	try {
    		if (requestCode == 1) {
    			if (resultCode == RESULT_OK) {
	    			if (b != null) b.recycle();
	    			b = (Bitmap) data.getExtras().get("data");
	    			if (b != null) {
	    				iv.setImageBitmap(b);
	    			}
    			}
    		}
    	}catch (Exception e) {
    		Log.e(PhotoBooth.class.getName(),"onActivityResult Error [" + e.getMessage() + "]");
    	}

    }

Note that this particular method may be used by many different invocations of startActivityForResult() within this class. To accommodate this multi-usage scenario, the first parameter of the method is an integer indicating which call was requested. Even though our application is super simple and only has one usage case, we evaluate the requestCode parameter as an example of a best-practice coding technique.

The next parameter is resultCode. This too is an integer and should be evaluated to check for a successful result. In our case the value will be RESULT_OK (which equates to -1 by the way) if the user has actually taken and accepted a photo. If the user cancels without taking and accepting the photo we do not want to look for a bitmap image which is not there! On the other hand, if you want to see the exception handler in action, comment out the line which checks for the resultCode.

Assuming we have a successful image capture, we want to extract the bitmap and display it within the ImageView, which we do by extracting the image from the “Intent Extras” bundle, specifically the datum associated with the key “data”.

We set this image into the ImageView and we are all set!

Displaying our captured image
Displaying our captured image

Note that if the Bitmap was previously assigned (i.e. consuming memory) coming into this routine, we call the recycle() method to free up resources prior to extracting the newly captured image.

You are now the proud owner of a super simple image capture application. You can download or browse the code on the Linux Magazine Mobile code hosting site.

Now, for some more fun, change the orientation of your phone — i.e. if it is “portrait”, change it to “landscape” or vice versa. See what happened? Your image disappeared! There is a simple explanation and a relatively simple solution — we’ll tackle both next time — stay tuned!

Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62