Android Development 102: Camera

Last time we showed you how to make a simple android app with two buttons and detect when one or the other is pressed. Now we want to use a button to open the camera, take a photo and then retrieve the photo to use in a display. I’ll show you the code and explain what its doing after.

Step 1

Create your view. This is easy, just a text field with an intro, a button to activate the camera and an empty image view where our photo will be placed after we take the photo.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    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="@string/hello_world" />

    <Button
        android:id="@+id/button_camera"
        android:text="@string/button_camera"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"></Button>

    <ImageView
        android:id="@+id/image_view_camera"
        android:contentDescription="@string/image_view_camera"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Step 2

Now make sure you fill in the strings. This is done under CameraApp/res/values/strings.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">CameraApp3</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Camer App 3</string>
    <string name="button_camera">Camera</string>
    <string name="image_view_camera">This is a camera image</string>

</resources>

Step 3

Now that we have our strings filled out, we need to update our manifest file to allow camera the proper permissions to use the camera and also read/write to the onboard storage for the phone (sd card). This is how my manifest file looks. Watch out for the “uses-permission” tags and “android:screenOrientation” attributes. I’ve highlighted these parts in the code:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cameraapp3"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <!-- New permissions for camera app -->
    <uses-permission android:name="android.hardware.camera"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
	<!-- End new permissions for camera app -->

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <!-- added "android:screenOrientation" attribute below to ensure the use can't rotate the screen -->
        <activity
            android:name="com.example.cameraapp3.MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

Step 4

Now we wan to modify the MainActivity.java file in CameraApp/src/com.example.cameraapp/MainActivity.java. I explain what these are doing in the code:

package com.example.cameraapp3;

import java.io.File;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {

	// label our logs "CameraApp3"
	private static String logtag = "CameraApp3";
	// tells us which camera to take a picture from
	private static int TAKE_PICTURE = 1;
	// empty variable to hold our image Uri once we store it
	private Uri imageUri;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// look for the button we set in the view
		Button cameraButton = (Button)findViewById(R.id.button_camera);
		// set a listener on the button
		cameraButton.setOnClickListener(cameraListener);
	}

	// set a new listener
	private OnClickListener cameraListener = new OnClickListener() {
		public void onClick(View v) {
			// open the camera and pass in the current view
			takePhoto(v);
		}
	};

	public void takePhoto(View v) {
		// tell the phone we want to use the camera
		Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
		// create a new temp file called pic.jpg in the "pictures" storage area of the phone
		File photo = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "pic.jpg");
		// take the return data and store it in the temp file "pic.jpg"
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
		// stor the temp photo uri so we can find it later
		imageUri = Uri.fromFile(photo);
		// start the camera
		startActivityForResult(intent, TAKE_PICTURE);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	// override the original activity result function
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		// call the parent
		super.onActivityResult(requestCode, resultCode, data);
		switch(requestCode) {
		// if the requestCode was equal to our camera code (1) then...
		case 1:
			// if the user took a photo and selected the photo to use
			if(resultCode == Activity.RESULT_OK) {
				// get the image uri from earlier
				Uri selectedImage = imageUri;
				// notify any apps of any changes we make
				getContentResolver().notifyChange(selectedImage, null);
				// get the imageView we set in our view earlier
				ImageView imageView = (ImageView)findViewById(R.id.image_view_camera);
				// create a content resolver object which will allow us to access the image file at the uri above
				ContentResolver cr = getContentResolver();
				// create an empty bitmap object
				Bitmap bitmap;
				try {
					// get the bitmap from the image uri using the content resolver api to get the image
					bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, selectedImage);
					// set the bitmap to the image view
					imageView.setImageBitmap(bitmap);
					// notify the user
					Toast.makeText(MainActivity.this, selectedImage.toString(), Toast.LENGTH_LONG).show();
				} catch(Exception e) {
					// notify the user
					Toast.makeText(MainActivity.this, "failed to load", Toast.LENGTH_LONG).show();
					Log.e(logtag, e.toString());
				}
			}
		}
	}

}

Now that we’ve updated our Java file, we’ve set the image to the image view. Try to run the app, you will see that when you tap the button the camera opens. Then if select an image to use, the camera will return you to the app and display the image you just took as the app’s image view!

Hurrah, lesson 2 down. I’ll be making a video explaining all this in a couple days, right now it’s midnight on Sunday and I have to go to work tomorrow, so there, cuddling time with my misses lady instead.

8 thoughts on “Android Development 102: Camera

  1. My images isn’t showing in the imageView. After placing a break point, on the if in onActivityResult, I noticed imageUri was null. Maybe I missed something, but I wrote it along the video.

  2. My mistake, just noticed I don’t have access to open /storage/emulated/0/Pictures/pic.jpg. Know any way I can fix this?

  3. Hi Mike,

    Thanks a lot for this very useful tutorial. I have a remark/question: after the camera application is called from the code, eventhough I choose the Cancel button the picture is still stored in the sdcard. Of course when I choose OK, the picture is shown on the imageView as described in your blog. Is there a way to avoid picture saving when chosing to Cancel the operation?
    Thank you very much.

    Best regards

    Zakaria

  4. Hey Mike, very nice tutorial i was searching for one like that for a while now x.x Just a question, is there a way to not close the camera after shot was taken and saved ?

  5. Hi!

    Great tutorial!

    I’m trying to implement this in a test app I’m making. How do I save the temp image file to a file in the gallery after I take the picture and press OK?

    Thanks in advance,

    Roy

  6. Another question:

    I’m getting the Java.OutOfMemoryError, which means that the picture I made with the camera is using too much memory. How can I reduce the size of the photo before displaying it in the imageview?

    Thanks in advance!

    Roy

Leave a Reply

Your email address will not be published. Required fields are marked *