Simple Android Photo Capture

Download the source code here


Having the ability to use the built in Camera application in your own Android projects is pretty nice. The Camera app has controls for white balance, color effect and more. Personally I would prefer to use it over building my own camera app. Not because it doesn’t sound fun to hand roll a camera, it does, but I think using the OS’s built in app is a boost to usability. User’s are comfortable with the built in camera, hence your app immediately becomes more usable by implementing it over a custom camera. In this post I’ll walk you through the steps to creating a simple photo capture app.

protected Button _button;
protected ImageView _image;
protected TextView _field;
protected String _path;
protected boolean _taken;
	
protected static final String PHOTO_TAKEN = "photo_taken";

At the top of the main activity there are a few variables that we will assign to widgets in the layout xml file. The _path variable represents the path and filename of the image we will create. You can format this path however you like, in the next snippet we’ll take a look at this. The _taken variable is a boolean that gets set to true once a photo has been taken and the constant PHOTO_TAKEN variable is used as a key for determining whether or not a photo was taken. If any of this is unclear hold tight it will be explained in greater detail below.

@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
        
    setContentView(R.layout.main);
       
    _image = ( ImageView ) findViewById( R.id.image );
    _field = ( TextView ) findViewById( R.id.field );
    _button = ( Button ) findViewById( R.id.button );
    _button.setOnClickListener( new ButtonClickHandler() );
        
     _path = Environment.getExternalStorageDirectory() + "/images/make_machine_example.jpg";
}

This code assigns values to our onscreen widgets and also assigns a value to _path. This value could be handled in many different ways. For the sake of simplicity I am hard-coding a path directly to the image file we are creating. The Environment.getExternalStorageDirectory() will return the path to the SD card on your system. We also set the click listener on the button to a custom class that we will look at in the next step.

Note: You must create the folder on your SD card where you plan to store images, otherwise your application will fail silently. You could take care of this through code, but this tutorial does not demonstrate how to do this.

public class ButtonClickHandler implements View.OnClickListener 
{
    public void onClick( View view ){
    	startCameraActivity();
    }
}

This is just a simple in-line class that implements View.OnClickListener. This where we call the function that prepares an Intent to actually start the camera app.

protected void startCameraActivity()
{
    File file = new File( _path );
    Uri outputFileUri = Uri.fromFile( file );
    	
    Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE );
    intent.putExtra( MediaStore.EXTRA_OUTPUT, outputFileUri );
    	
    startActivityForResult( intent, 0 );
}

This function creates an Intent object that will start the camera activity. First we use use the _path variable to build a File object that we then in turn use to create Uri that will be sent along with out Intent to inform the camera activity of where to save the image. Using startActivityForResult tells the system that when the user is done with the camera app to return to this activity with some result.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{	
    Log.i( "MakeMachine", "resultCode: " + resultCode );
    switch( resultCode )
    {
    	case 0:
    		Log.i( "MakeMachine", "User cancelled" );
    		break;
    			
    	case -1:
    		onPhotoTaken();
    		break;
    }
}

Once the user has either pressed the “OK” or “Cancel” button in the camera activity your application should return to the previous activity and call the onAcitivtyResult function. The resultCode parameter can be used to determine what action the user took. If the user took a photo we can load and display it with this next snippet.

protected void onPhotoTaken()
{
    _taken = true;
    	
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    	
    Bitmap bitmap = BitmapFactory.decodeFile( _path, options );
    _image.setImageBitmap(bitmap);
    	
    _field.setVisibility( View.GONE );
}

This function immediately sets the _taken variable to true. Next it creates a BitmapFactory.Options object which we use to define some parameters of the image we are loading. It is unlikely that we need to load the full size image into our application. Doing so can have a negative affect on memory consumption. Setting the inSampleSize to anything higher than 1 tells the factory class to down-sample the image. You can alter this value based on your screen real estate. I’ve found that a value of 4 seems to work pretty well on the Droid. The Options object has many other parameters and could make for a good future topic. After creating the options we create a new Bitmap object and pass in the _path variable and the options variable. After that all we need to to do is assign the bitmap to our ImageView.

At this point you should be able to take a photo with the native Android camera app and then view the stored image back in your application. Works pretty well right? There is one catch though. If you rotate your device the image magically disappears. To get around this we use the to variables that we have heard much about yet – the constant PHOTO_TAKEN and the member boolean _taken. The following snippets demonstrate their use.

@Override
protected void onSaveInstanceState( Bundle outState ) {
    outState.putBoolean( PhotoCaptureExample.PHOTO_TAKEN, _taken );
}
@Override 
protected void onRestoreInstanceState( Bundle savedInstanceState)
{
    Log.i( "MakeMachine", "onRestoreInstanceState()");
    if( savedInstanceState.getBoolean( PhotoCaptureExample.PHOTO_TAKEN ) ) {
    	onPhotoTaken();
    }
}

When your device is rotated the onSaveInstanceState method is called. This gives you an opportunity to save any details about your application by pushing data into a Bundle object. When the device detects that the rotation is complete, onRestoreInstanceState and the Bundle that you pushed data into is passed through. Using this bundle you can restore the bitmap image.

Posted in Android | Tagged , , , , , , , , , | 13 Comments

13 Responses to Simple Android Photo Capture

  1. A.H says:

    I have copied your source code in my Application folder.When I am starting new android project,and I select New android project.I select the option Create project from existing source then I am getting the erroe “The API level for the selected SDK target does not match the Min SDK version.”
    I have android 2.1 (7 API) and Android 1.5 (3 API).So is there any way that I may be able to run this program and using android 1.5 whose API is different then your program

  2. Jeremy says:

    @A.H.
    You can change this line in the manifest to the API level you are targeting: <uses-sdk android:minSdkVersion=”5″/>.

  3. A.H says:

    Thanks… it worked but I installed android 2.0 because its API is 5.I got 4 errors. I used quick fix.It selected jdk 1.5 compling etc. It was some .class error. After using quick fix the error is removed. On running the application em getting please insert SD card before using the camera… But I have added SD card when I was creating virtual device.

  4. Jeremy says:

    @A.H.
    Glad to hear the example working is working for you. I have had marginal success using the camera in the emulator. I usually test with an actual device. I recommend you post your issue to StackOverlfow

  5. A.H says:

    I searched and found that following command is use to mount SD card in anroid AVD.

    android create avd -n -t -c [K|M]

    Should I read this in comand prompt in the tools folder? Second what should I wirte in place of target ID..????

    Brother, can you please tell me where does your photocapture program save the image I capture. And I want to send that pic captured taken from mobile camera via mms. Here is the code for mms
    At start Please also tell me what lines I should add If em using your program. For eg import kind of lines.

    1. Intent i = new Intent(Intent.ACTION_SEND) ;
    2. i.putExtra(Intent.EXTRA_STREAM,imageUri) ;
    3. i.setType(“image/jpeg”) ;
    4. startActivity(Intent.createChooser(i,”Send Image To:”)) ;

    I tried to run this program but it is also not working

  6. Jeremy says:

    @A.H.
    Images are saved to wherever Environment.getExternalStorageDirectory() is pointing to.

    As for the other questions, this post is not about sending via mms. This is just a simple example of how to capture images with the Android OS. My advice would be to continue reading the online reference manuals: android.developer.com

  7. umar says:

    when i press ok button after taking picture it gives me

    Force close error

    am i missing some permissions or what?

    please guide me whats the solution?

  8. Jeremy says:

    How are you using the example? Are you using just the PhotoCaptureExample class or did you import the whole project? Be sure that your device is not mounted when you try to save an image. I will look into this a little more to see if I can find a possible cause.

    Thanks,
    ~Jeremy

  9. umar says:

    ok solved above problem,

    just one issue left
    after taking photo is it not showing image on main screen only empty black screen with button.

    could you please guide why is that ?
    i am using same your code nothing changed except path which is

    _path = Environment.getExternalStorageDirectory() + “/images/media/make_machine_example.png”;

  10. Jeremy says:

    @Umar
    Make sure there is a folder structure on your device that matches the path your are sending in the intent.
    ~Jeremy

  11. Umar says:

    ok, then what you suggest?

    i dont want create folder structure manually but automatic.

    let suppose is it possible to save automatically in sdcard/ gallery and then display from there?
    using same you code you provided?

    what should i do

    i just want to display image right after capturing it.

  12. hardwing says:

    Hi, Umar,

    I got a dirty solution but it is working for the automatic purpose.

    _path = Environment.getExternalStorageDirectory() + “/make_machine_example.jpg”;

    Just put the image at the root of “ExternalStorageDirectory.

  13. Pingback: Making a Simple OCR Android App using Tesseract - Gautam Gupta's Blog