Camera

Intro

As with other built-in applications, you can use the device's built-in default camera app to take pictures for use in your app.  In fact, doing so is quite simple as long as your app has the proper manifest file entries and you take a few minutes to understand the options available to you, the developer.

Manifest Settings

To save your image to external storage, such as the SD card, you need permission for that:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

It's also important to let the device know that your app needs to use the camera, but declaring so in the manifest file:

<uses-feature android:name="android.hardware.camera" />

Making this declaration will prevent your app from being installed in devices that do not have a camera.  This includes your AVD!  To enable the camera in the virtual device, edit its settings using the AVD Manager.  Under "Advanced Settings", set the front and/or back camera to something other than "None".  Also, be sure to set the SD Card memory size to an amount greater than 100MB.

*Note: If your app does not use the default camera app (launched with the CAMERA action Intent), but instead handles the taking of pictures itself, then you need to set the proper permission in the manifest file:

<uses-permission android:name="android.permission.CAMERA" />

For this lesson, we will be using the default camera, so no extra permissions are needed.

Using the Default Camera

The default Camera is accessed using an Intent and passing the MediaStore.ACTION_IMAGE_CAPTURE action.  The intent should be launched using startActivityForResults, so that the captured image can be returned to your Activity in the onActivityResult method:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_REQUEST_CODE);

When launched this way, a low-quality image is returned as an Intent extra, and can be used as needed:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == CAMERA_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {

            // this gets a low-quality resolution photo
            Bitmap photo = (Bitmap) data.getExtras().get("data");
            imageView.setImageBitmap(photo);

        } else if (resultCode == RESULT_CANCELED) {
            // image capture cancelled
        } else {
            // image capture failed
        }
    }
}

Capturing a High Resolution Picture

In order to enable the storing of higher-quality pictures, you must pass a file location as an Intent extra.  Specifically, you need to add a MediaStore.EXTRA_OUTPUT extra containing the Uri of the destination file:

public void takePicture(View v){
    // intent to launch default camera app
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
    // calls custom method that creates a file name based on the current Date
    String fileName = createFileName();

    // store picture to public pictures directory.  This file persists if app deleted
    filePath = Environment
                  .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) 
                  + "/" + fileName;
    
    // or store picture to app specific folder.  Files will be deleted if app is deleted
   /*filePath = getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/" + fileName; */
    
    File cameraFile = new File(filePath);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraFile));

    // start the image capture Intent
    startActivityForResult(intent, CAMERA_REQUEST_CODE);
}

private String createFileName(){
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    return "IMG_"+ timeStamp + ".jpg";
}

Unlike the low-quality photo, the high-quality version is not delivered as an intent extra.  Instead, it must be retrieved using the file path that you specified in the Intent extra:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == CAMERA_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {

            // get the high-quality image created if intent extra used
            Bitmap photo = BitmapFactory.decodeFile(filePath);
            imageView.setImageBitmap(photo);

        } else if (resultCode == RESULT_CANCELED) {
            // image capture cancelled
        } else {
            // image capture failed
        }
    }
}

Notice that you have two options when it comes to saving your image file:

For more information on standard file-saving conventions, refer to the developer docs: http://developer.android.com/guide/topics/media/camera.html#saving-media