Linux.com

Home Learn Linux Linux Tutorials How to Call the Camera in Android App Development

How to Call the Camera in Android App Development

Calling the camera on Android

One of the great things about modern mobile phones is the increasingly good onboard camera. The Android API gives you seamless access to the camera from any other app, giving you plenty of scope to enhance existing apps or create new ones.

There are two basic approaches to camera access: you can use an Intent to call the default camera app, or you can use the API to build your own camera Activity. The second is more flexible, but also requires more work to code. Often it's fine just to use the default app, and that's what we'll cover in this tutorial.

Our example app will be pretty basic, just to illustrate the idea. We'll have a button, which we click to launch a camera intent, then we'll show the returned picture. As explained in a previous tutorial, Intents are used by Android to pass messages within and between Activities and modules. Here, our Intent will pass a message to and from the onboard Camera.

Setting up

Once you've created your project, and before you start coding, you'll need to edit your manifest (AndroidManifest.xml) to add permission to use the camera and external storage, and to add a note that this app uses the Camera feature:

<manifest .... >
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-feature android:name="android.hardware.camera" />

Next, set up the XML display (in activity_call_camera.xml) to show a button and an image:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" >
    <Button
        android:id="@+id/button_callcamera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="18dp"
        android:text="@string/get_photo" />
    <ImageView
        android:id="@+id/photo_image"
        android:contentDescription="will vary; image taken from camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="80dp"
        android:src="/@drawable/ic_launcher" />
</RelativeLayout>

Calling the Camera with Intent

Now, set up your single Activity:

public class CallCamera extends Activity {
	
  private static final String TAG = "CallCamera";
  private static final int CAPTURE_IMAGE_ACTIVITY_REQ = 0;
	
  Uri fileUri = null;
  ImageView photoImage = null;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_call_camera);
    photoImage = (ImageView) findViewById(R.id.photo_image);
        
    Button callCameraButton = (Button) findViewById(R.id.button_callcamera);
    callCameraButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File file = getOutputPhotoFile();
        fileUri = Uri.fromFile(getOutputPhotoFile());
        i.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        startActivityForResult(i, CAPTURE_IMAGE_ACTIVITY_REQ );
      }
    });
  }
}

We're using startActivityForResult(), because we want a result (the photo file) returned to our Activity when the camera is done. This means that we need to hand in a URI to give the Camera somewhere to save the photo. (See a little further down for why fileUri, annoyingly, needs to be a class variable.)

The getOutputPhotoFile() method looks like this:

private File getOutputPhotoFile() {
  File directory = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), getPackageName());
  if (!directory.exists()) {
    if (!directory.mkdirs()) {
      Log.e(TAG, "Failed to create storage directory.");
      return null;
    }
  }
  String timeStamp = new SimpleDateFormat("yyyMMdd_HHmmss", locale.UK).format(new Date());
  return new File(directory.getPath() + File.separator + "IMG_"  
                    + timeStamp + ".jpg");
}

This gives your photo a sensible and standard (time-linked) name, and uses the system-preferred picture storage directory for your device.

Finally, we need to deal with the result when it returns to the activity. This is our onActivityResult():

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQ) {
    if (resultCode == RESULT_OK) {
      Uri photoUri = null;
      if (data == null) {
        // A known bug here! The image should have saved in fileUri
        Toast.makeText(this, "Image saved successfully", 
                       Toast.LENGTH_LONG).show();
        photoUri = fileUri;
      } else {
        photoUri = data.getData();
        Toast.makeText(this, "Image saved successfully in: " + data.getData(), 
                       Toast.LENGTH_LONG).show();
      }
      // showPhoto(photoUri);
    } else if (resultCode == RESULT_CANCELED) {
      Toast.makeText(this, "Cancelled", Toast.LENGTH_SHORT).show();
    } else {
      Toast.makeText(this, "Callout for image capture failed!", 
                     Toast.LENGTH_LONG).show();
    }
  }
}

 

You'll notice that comment about a known bug. What should happen is that the image URI should be returned by the Intent. However, some older devices (including mine) do save the file in the requested location, but send back a null Intent. The workaround is to save the location (fileUri) and use that if we get an "OK" result code but no image location data. If you run this code as-is, it should work, but you'll only get Toast messages on return.

 

Showing the Image

Now, let's show the returned image. Uncomment the showPhoto() line in the method above, and add a showPhoto() method:

private void showPhoto(Uri photoUri) {
  File imageFile = new File(photoUri);
  if (imageFile.exists()){
     Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
     BitmapDrawable drawable = new BitmapDrawable(this.getResources(), bitmap);
     photoImage.setScaleType(ImageView.ScaleType.FIT_CENTER);
     photoImage.setImageDrawable(drawable);
  }       
}

Run the code, and you should see the photo shown beneath the 'get photo' button when you return from the Camera.

Improvements and bug fixes

If you click the button a second time and take a second photo, the old photo should be replaced by your new one... but in fact, if you try it, depending on your device you may be faced with an OutOfMemoryError. To fix this, add this line in showPhoto(): private void showPhoto(Uri photoUri) { if (imageFile.exists()){ ((BitmapDrawable)photoImage.getDrawable()).getBitmap().recycle(); //... as before } }

Finally, you might have noticed that initially when you fire up the code, you get a little Android robot where the image should be. To fix this and just show nothing, add a line in onCreate():

photoImage = (ImageView) findViewById(R.id.photo_image);
photoImage.setImageDrawable(null);

You'll also need to make some changes in showPhoto() to avoid a NullPointerException:

private void showPhoto(Uri photoUri) {
  if (imageFile.exists()){
    Drawable oldDrawable = photoImage.getDrawable();
    if (oldDrawable != null) { ((BitmapDrawable)oldDrawable).getBitmap().recycle(); }
    // rest as before
  }       
}

One last issue: depending on your device, the image may also be rotated on your screen. Unfortunately this is a little complicated to fix, largely because of the memory cost of rotating bitmaps, and is outside the scope of this tutorial. If you want to explore this further, you can use the EXIF information to find the rotation, and BitmapFactory to reduce the overhead of handling bitmaps. A little later in this tutorial series, I'll look at manipulating bitmaps and images; the next tutorial in the series, though, will take a closer look at the Camera API and at building your own camera app.

 

Comments

Subscribe to Comments Feed
  • android apps development in chennai Said:

    Nice...!

  • Android mobile development in Chennai Said:

    Nice to your blog

  • iOSAndroid Said:

    Why not make the tutorial available for download so I can test it and see if it works on my device? I worked through a tutorial and when I run it, it says "Unfortunately Camera has stopped" and then it quits.

  • Sasmita Said:

    Thanks for the tutorial. For those who are looking for the complete tutorial, here is the link to my project http://github.com/sasmita/Camera.git

  • galgali Said:

    nice info thank for sharing http://www.android-training-apps.com/

  • Mayaa Said:

    Cleanly explained, thanks for your great work.. Even this http://www.compiletimeerror.com/2013/08/android-camera-app-in-android-example.html might help, have a look..

  • Lauren Said:

    Thanks for this, it really helped and was clear to understand. After going though the code I see how it works.

  • kavin Said:

    sir, how to configure camera in video mode .. ???

  • Itzik Said:

    Very nice. It is working with a minor changes in the layout.xml in showphoto() add this 2 lines: String filePath = photoUri.getEncodedPath(); File imageFile = new File(filePath);

  • Dharmik Said:

    Hi, Its work fine but that image is rotate from Portrait to Landscape mode how to solve that ? Thanks, Dharmik

  • mrjlaebiads Said:

    Nice to read this blog and thanks for creating this informative blog...!Used camera sale in chennai,is get from the mrjalebi classifieds site as much as possible.

  • Brian Said:

    Hi, I've implemented the above solution, but when it returns to the main activity, the toast shows image saved and doesn't show it in the image view. Any ideas as to why its not showing the captured image?

  • Brian Said:

    I'm trying to get the captured image back to the image view using the showPhoto method but I get an error at this line, "File imageFile = new File(photoUri);", the error is The constructor File(Uri) is undefined. Is there an error somewhere in your code?


Who we are ?

The Linux Foundation is a non-profit consortium dedicated to the growth of Linux.

More About the foundation...

Frequent Questions

Join / Linux Training / Board