Mobility

Android's camera intent makes taking pics a snap

Learn how to fire up Android's built-in camera app from within your own program and return the resulting picture.

If you've been using computers for a very long time, you're no doubt familiar with the acronym K.I.S.S.  I first ran across the term way back in the heyday of the TRS-80.

When I was 12, I wrote what I thought was a very impressive version of Lunar Lander. I sent it off to a publication in hopes the editor might run an article about it and perhaps even call me up for an interview; instead, I received a short handwritten note very politely declining my masterpiece with the initials K.I.S.S. scrawled at the bottom. A few years later, my high school programming class teacher wrote K.I.S.S. on the blackboard and underneath it: "Keep it simple, Stupid!" A light went on in my head, and I immediately recalled the rejection letter. I was simultaneously delighted and insulted.

These days I hear from some of my younger cohorts that it's taught as: "Keep it super simple." Regardless, the meaning is clear, and I'm a firm believer that more often than not the simplest solution to any problem is the best one.

As Android has continued to mature as a platform and as a consumer device, the camera has improved dramatically. As the camera has grown, so has the API surrounding it. Google's Camera API makes it possible to completely integrate the entire photo-taking process from preview to editing right into your app. That said, just because it's possible to do something doesn't mean you should do it.

The built-in camera app that comes with every Android phone is pretty darn polished, and since version 1.0 of Android, it has been exposed via Android's intent model. I'm certain there are people who have a good reason for tightly integrating the entire camera functionality into an app, but for my money, taking advantage of the camera app that comes as part of the base OS offering is the way to go.

This tutorial demonstrates how to fire up the built-in camera app from within your own program, and subsequently return the resulting picture. You can follow along with the steps below or download the entire project and import it directly into Eclipse.

1. Open Eclipse and create a new Android project. Target Android 1.6 or higher. Be sure to rename the startup activity to Main.java.

2. Because we are taking advantage of the built-in camera app to capture a photo, we won't need any special permissions in our manifest — we can start directly by creating a main.xml file in our /resource/layout folder. The layout consists of an image view and two buttons.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Using the camera intent."
        android:padding="10dip"
        android:gravity="center" />
<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
<Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Snap!"
                android:id="@+id/snap"/>
<Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Rotate!"
                android:id="@+id/rotate"/>
</LinearLayout>

  <ImageView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minHeight="100dip"
    android:id="@+id/photo_holder"/>
</LinearLayout>

3. Go to our /src/Main.java file, where we define a couple of class variables and wire up our buttons in the on create override.

package com.authorwjf.camera;

import java.io.File;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import com.authorwjf.camera.R;

public class Main extends Activity implements OnClickListener {
        private static final int TAKE_PICTURE = 0;
        private Uri mUri;
        private Bitmap mPhoto;
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         ((Button) findViewById(R.id.snap)).setOnClickListener(this);
         ((Button) findViewById(R.id.rotate)).setOnClickListener(this);
     }
}

4. The button handler consists of a case statement responsible for launching the camera and possibly rotating the image. Why do we need a button to rotate the image? Good question. In my experience, based on the many form factors Android devices come in, there is no good way to know if the camera app will default photos to landscape or portrait. A button allowing the user to rotate the image immediately if need be is a quick, universal fix.

@Override
public void onClick(View v) {
        if (v.getId()== R.id.snap) {
                Intent i = new Intent("android.media.action.IMAGE_CAPTURE");
        File f = new File(Environment.getExternalStorageDirectory(),  "photo.jpg");
        i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
        mUri = Uri.fromFile(f);
        startActivityForResult(i, TAKE_PICTURE);
        } else {
                if (mPhoto!=null) {
                        Matrix matrix = new Matrix();
           matrix.postRotate(90);
           mPhoto = Bitmap.createBitmap(mPhoto , 0, 0, mPhoto.getWidth(), mPhoto.getHeight(), matrix, true);
           ((ImageView)findViewById(R.id.photo_holder)).setImageBitmap(mPhoto);
               }
       }
}

5. Override the on activity result callback and import the image from the content provider and then apply it to our image view.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
       switch (requestCode) {
       case TAKE_PICTURE:
           if (resultCode == Activity.RESULT_OK) {
               getContentResolver().notifyChange(mUri, null);
               ContentResolver cr = getContentResolver();
               try {
                   mPhoto = android.provider.MediaStore.Images.Media.getBitmap(cr, mUri);
                ((ImageView)findViewById(R.id.photo_holder)).setImageBitmap(mPhoto);
               } catch (Exception e) {
                    Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
                  }
             }
       }
}

In an effort to keep the code as short as possible I'm not dealing with orientation changes or calling recycle on the bitmap resource; if you decide to use this code in a live application, you'll want to do both. For the purposes of our tutorial, the resulting app may be run on the emulator, but camera support in the emulator is a little clunky and requires an ADB image with SDRAM.

In line with our mantra of keeping things as simple as possible, I recommend downloading the app straight to your device and trying it firsthand. Hopefully you'll be more impressed than my cat was with it (Figure A)! Figure A

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

Editor's Picks