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.
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.
My mistake, just noticed I don’t have access to open /storage/emulated/0/Pictures/pic.jpg. Know any way I can fix this?
Also, imageUri is null if the phone’s orientation is landscape. On Portrait works.
Thank you. This help me much, i try to make an application and it need to capture an images.
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
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 ?
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
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