Android SDK: How To Make an Automatic Snapshot Android App

Let’s make an app that takes and saves a picture after a specified time when you push a button.

The Interface

As mentioned we’ll need a button, let’s also use a text view to display the time left before the picture is taken. You won’t see anything in the text view initially but when the button is pressed a count down will show.

a button for the automatic picture app

Our automatic snapshot app interface

Put this code in layout/main.xml, notice that in the button widget we are calling the function startTimer on click.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
	<Button
		android:id="@+id/buttonStartTimer"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="Start Timer"
		android:onClick="startTimer" />
	<TextView 
		android:id="@+id/textTimeLeft"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text=""
		/>
	
</LinearLayout>

Handling Data Returned From Camera

The function used to take photos can handle up to four callbacks but only need one. This function returns the photo data in bytes. We are going to call our callback function jpegCallBack. Inside this function we’ll save the photo to the main directory of the SD card also.

thumbnail of photo taken shown in sd card folder

SD card folder with thumbnail of the photo taken by the app

Making JPEGs Out of Byte Data

As mentioned above the camera returns an array of bytes, fortunately we don’t have to deal with the 1′s and 0′s of the byte data, the Android SDK has a function called decodeByteArray to to change byte data to bitmap.

This is the code you need to convert the data from bytes to an image and to save the image in your SD card’s top directory.

	Camera.PictureCallback jpegCallBack=new Camera.PictureCallback() {		
		public void onPictureTaken(byte[] data, Camera camera) {
			// set file destination and file name
			File destination=new File(Environment.getExternalStorageDirectory(),"myPicture.jpg");
			try {
				Bitmap userImage = BitmapFactory.decodeByteArray(data, 0, data.length);
				// set file out stream
				FileOutputStream out = new FileOutputStream(destination);
				// set compress format quality and stream
				userImage.compress(Bitmap.CompressFormat.JPEG, 90, out);		
				
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	};

Counting Down

Counting down is the easiest part, we simply need to use the CountDownTimer function which takes two parameters: the time until the count down finishes and the counting interval both in milliseconds.

a start timer button and count down text

counting down

This app takes 5 seconds after you press the button to take a picture so we need 5000ms at intervals of 1000ms.

picture taken message

The text changes to "Picture Taken" when the timer reaches 0


The other cool thing about this function is that it has two functions: onFinish() and onTick() which as you might have guessed execute when the count finishes at every tick (every 1000ms in our case) respectively.

We are going to call the camera.takePicture() function on finish and update the timer on tick. Here’s the code to do that.

	public void startTimer(View v){
		
		// 5000ms=5s at intervals of 1000ms=1s so that means it lasts 5 seconds
		new CountDownTimer(5000,1000){

			@Override
			public void onFinish() {
				// count finished
				textTimeLeft.setText("Picture Taken");
				camera.takePicture(null, null, null, jpegCallBack);
			}

			@Override
			public void onTick(long millisUntilFinished) {
				// every time 1 second passes
				textTimeLeft.setText("Seconds Left: "+millisUntilFinished/1000);
			}

		}.start();
	}

The Full Code

AutomaticPhotoActivity.java

package com.yoursite.automaticphoto;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;

public class AutomaticPhotoActivity extends Activity{
	private Camera camera; // camera object
	private TextView textTimeLeft; // time left field


	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		textTimeLeft=(TextView)findViewById(R.id.textTimeLeft); // make time left object
		camera = Camera.open();
		SurfaceView view = new SurfaceView(this);
		
		try {
			camera.setPreviewDisplay(view.getHolder()); // feed dummy surface to surface
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		camera.startPreview();   
	}

	Camera.PictureCallback jpegCallBack=new Camera.PictureCallback() {		
		public void onPictureTaken(byte[] data, Camera camera) {
			// set file destination and file name
			File destination=new File(Environment.getExternalStorageDirectory(),"myPicture.jpg");
			try {
				Bitmap userImage = BitmapFactory.decodeByteArray(data, 0, data.length);
				// set file out stream
				FileOutputStream out = new FileOutputStream(destination);
				// set compress format quality and stream
				userImage.compress(Bitmap.CompressFormat.JPEG, 90, out);		
				
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	};

	public void startTimer(View v){
		
		// 5000ms=5s at intervals of 1000ms=1s so that means it lasts 5 seconds
		new CountDownTimer(5000,1000){

			@Override
			public void onFinish() {
				// count finished
				textTimeLeft.setText("Picture Taken");
				camera.takePicture(null, null, null, jpegCallBack);
			}

			@Override
			public void onTick(long millisUntilFinished) {
				// every time 1 second passes
				textTimeLeft.setText("Seconds Left: "+millisUntilFinished/1000);
			}

		}.start();
	}

}

AndroidManifest.xml

Our app requires some special permissions to access the camera and write to the file system.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.yoursite.automaticphoto"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />
      <uses-feature android:name="android.hardware.camera" />
  <uses-feature android:name="android.hardware.camera.front"
                android:required="false" />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".AutomaticPhotoActivity"
                  android:label="@string/app_name"
                  android:screenOrientation="landscape"
                  android:configChanges="keyboardHidden|orientation">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    
    
</manifest>

Related posts: