Android Mobility: Open Source Hits the Road

ven prior to Google’s splashy announcement about Android late last year, rumors were swirling about the so-called “gPhone.” Now that programmers have had several months to experiment with early releases of the SDK, a clearer vision of Android has emerged. Android offers a robust and modern Java-derived API, visual components that look great out of the box, and has a uniquely pluggable architecture that makes first-class citizens out of all your phone applications.

That said, Android does have its faults. Some of these are just growing pains: APIs that do not work as expected, unimplemented features, or outright bugs. Many developers also feel nervous about Android’s future?if Android becomes just another platform to support, its new features will become a burden to already overwhelmed porting engineers.

Do Android’s positive features outweigh the negatives? The best way to tell is to try it for yourself! This article will take you on a whirlwind tour through many of Android’s capabilities as you build a networked camera application called ConnectedCamera. You will learn how to use Android’s camera, create files and databases for storage, navigate through multiple screens, update information, and communicate with a server. Though you’ll be building a richly featured application, it’s also simple enough that you’ll be able to focus on the important concepts.

Step Zero
First, some housekeeping. The application in this article was developed using the M5-RC15 release of the SDK. It should run on earlier or later versions as well, but will require modification as Google continues to tinker with the APIs.

Prior to starting, install the SDK and set up your development environment. You should be able to run the basic “Hello World” application that is created with new projects. If you need help, see the related resources at the left-hand navbar of this article.

Start a new Android project. Your main Activity’s name will be Camera and the layout camera.xml.

Imagining the App
Before digging into the code, it’s helpful to think a bit about how to organize the application. First, it’s generally best to make each screen a separate Activity. This leverages Android’s existing capabilities for state transition and management, and cleanly divides the application into components. It’s not hard to do either. You’ll need four Activities: a camera, an album, an editor, and an uploader.

You’ll also need a way to store data. Android offers a plethora of persistence mechanisms, but in this instance, two are most applicable: a SQLite database or a Content Provider. Because you do not need to share data with other applications, private SQLite storage is the best option for this app.

Finally, you need to decide if your application needs to act or respond when not actually running. If so, you’ll need a Service or special IntentReceiver. In this case, you don’t need it, so let the coding begin!

Take a Picture
One of Android’s more striking features is that it allows you to define your user interface in XML. This provides a nice middle ground between the extremes of specifying all your layout in code, which can be hard to maintain, or using an external visual editing tool, which tends to be inflexible and generate inscrutable code.

The camera screen should both instruct the user to shoot and also provide a way to navigate through the app. This XML, placed in /res/layout/camera.xml or a similar file, will generate an appropriate screen:

Any value that starts with @string is defined in /res/values/strings.xml (Listing 1). This allows for easier localization.

At this point, you can run the application and see your layout?without having added one line of Java code. As you may expect, you can see two Buttons: a large one that fills most of the screen and a smaller one at the bottom. The sizing effect is accomplished through the layout_weight flag, which instructs Android to provide this Button with any leftover available space. Because you do not know how large the button will be, set the initial height to 0dip (that represents Device Independent Pixels) so Android can use an optimized algorithm to calculate the appropriate sizes. You can experiment using different size emulators (HVGA vs. QVGA, for example) and different orientations (Portrait vs. Horizontal), but the layout will always be resized to fit the screen and look good.

Going back to the Camera Activity, it’s now time to actually take a picture. Retrieve the cameraInstructions item, and attach a hook to perform the action.

Button click = (Button)findViewById(R.id.cameraInstructions);click.setOnClickListener(new View.OnClickListener () {    public void onClick(View v)    {        // Action goes here.    }});

Android provides a CameraDevice as part of its android.hardware package. Listing 2 shows that the code for capturing an image is fairly simple.

Figure 1. DDMS File Explorer in Eclipse: Navigating the phone file system to locate a file.

Several components interact here:

  1. The CameraDevice allows you to configure the camera and take a picture.
  2. The Bitmap stores actual image pixel data.
  3. The Canvas connects your camera to the storage. Note that you could use a screen Canvas to preview instead of saving.
  4. The FileOutputStream writes the data to disk.

Go ahead and run the application. By setting a debugger in the above code, you can step through and see the actions it takes.

In Eclipse, open the DDMS perspective and locate your file in the File Explorer under /data/data/your.package.name (shown in Figure 1).

You can copy the picture.jpg image to your hard drive for a clearer view.

Stick Around
The application won’t be very useful if it only saves a single picture. You need to create a database that will keep track of all the pictures your users will take, as well as their associated information?things like their creation time and captions.

Google’s Notepad tutorial application includes a sample wrapper, which wraps around a SQLite database called NotesDbAdapter. This is a good foundation for your application’s database needs: it provides the power of SQL with a friendly API. The code shown in Listing 3 affords the same convenience.

With this adapter in hand, you can easily save a record of the picture:

CameraDbAdapter adapter = new CameraDbAdapter(Camera.this);adapter.open();adapter.createImage(filename, "Enter a caption.", System.currentTimeMillis());

Photo Album
You now have an application that saves and stores pictures on the device. To make it more useful, what about providing a way to review the pictures that have been taken?

To display the items as a simple list, you can extend ListActivity and have it manage your UI. All you need is to define what each line item should look like. This happens with a single element in /res/layout/camera_item.xml:

The corresponding Album Activity is simple as well. With the database keeping track of your content and the ListActivity handling your interface, all you need is a little glue to tie those pieces together. That glue comes in the form of an Adapter. For a basic UI, the SimpleCursorAdapter will do the trick:

CameraDbAdapter adapter = new CameraDbAdapter(this);adapter.open();SimpleCursorAdapter labels = new SimpleCursorAdapter    (this, R.layout.camera_item, adapter.fetchAllImages(),     new String[]{CameraDbAdapter.KEY_CAPTION},     new int[]{R.id.albumItemCaption});setListAdapter(labels)

The parameters in the SimpleCursorAdapter bind the UI layout elements to the appropriate Cursor data. That’s all there is to it! You could further customize the list by modifying the albumItemCaption XML element.

Linked In
How do you move from the initial Camera screen to the new Album screen? Any time you think about doing a screen transition in Android, your first thought should be Intent. Intents can be very powerful abstract mechanisms for tying together disparate pieces of functionality. Within an application, however, they tend to be very simple: you just specify where to go.

The Camera should go to the Album after taking a picture or clicking the Album button. A simple helper function will contain all that is needed:

private void advance(){    Intent i = new Intent(this, Album.class);    startActivity(i);}

Call this function from within the onClickListener for the two Camera buttons. Listing 4 shows the completed Camera class.

One more step is needed to allow this transition. Although you’ve created AndroidManifest.xml:

This may look a little sparse compared to other definitions, but it is actually quite common. Most Activities you’ll write aren’t meant to be accessed from outside your application. Thus, they do not need the intent-filters of your entry point.

What’s My Name?
It’s a little boring to give every picture the same caption. A simple editor will let you review the picture and add a caption. Listing 5 shows the layout for a new Editor Activity. The XML for this screen adds two new types of elements: editable text and images.

While the specific items may be different, the strategy for dealing with these new elements in the Activity is the same as for Camera:

  1. Set the content layout to the XML file.
  2. Retrieve items of interest by ID.
  3. Modify items and attach listeners to implement specialized behavior.

The complete Editor in Listing 6 is more complex than the previous two classes, so some more details may be helpful. The Editor needs some way of knowing which specific image is being edited. The standard way to do this is through an Intent Extra. An “extra” is a simple key-value pair; in this case, a long value that uniquely identifies the database row ID for this image.

Displaying the image is compact but complex:

image.setImageBitmap( BitmapFactory.decodeFile(getFilesDir() + "/" +        mCursor.getString(mCursor.getColumnIndex(CameraDbAdapter.KEY_FILE))));

Breaking it apart:

  • Look up the database column that holds the filename.
  • Retrieve the actual filename String value.
  • Construct the fully-qualified filepath.
  • Pass this filepath to the BitmapFactory (a utility class that generates Bitmaps).
  • Set the loaded bitmap on the Image.

Setting the current caption on the EditText view is simple in comparison:

Figure 2. Camera Editor: Viewing and editing a saved picture.

mCaption.setText(mCursor, mCursor.getColumnIndex(CameraDbAdapter.KEY_CAPTION));

Finally, note that the caption is updated in the onPause() method. This is a common idiom known as “Edit in place”. Rather than burdening the user with special menus and reminders to save, all edits are seamlessly performed as the user moves in and out of the Activity. It may feel unusual if you are used to more conventional behavior for saving, but it is very well suited to mobile devices.

Before seeing the Editor in action (see Figure 2), remember to add it to AndroidManifest.xml and add an appropriate Intent to Album. To tell the Editor which Image to retrieve, be sure to include the extra value for the Row ID. Listing 7 contains the now-complete code for Album.

By this point, you should be able to navigate the program and view stored pictures.

Author’s Note: If you copied code from the Listing, comment out the transition to Uploader.

You may be curious about the source of the image. While Android has the API to capture an image, in the emulator it will retrieve a manufactured image. On an actual phone it would use the phone’s camera. Future versions of the emulator will likely support web cameras for more realistic image capture.

Sharing
Android’s features include always-on networking; much like the iPhone, you can think of it as an Internet terminal in your pocket. So let’s make this a 21st-century application by allowing you to easily share your pictures with the world.

The uploader UI, shown in Listing 8, is simple. Another new View appears here: ProgressBar. This View indicates that the application is working.

To make this look better, apply the “Dialog” theme when adding the new Activity to AndroidManifest.xml. This will make the upload appear as a modal dialog above the previous screen:

How will you handle the actual upload? Unlike the other examples so far, you should not use onCreate, onPause, or any of the other Android life cycle points. These methods are invoked by the program’s solitary UI thread; if too much time is taken during the network upload, nothing else on the phone will be able to draw or react. The solution is clear to Java developers: create a new thread to handle the network.

Android ships with the standard java.io and java.net packages. It also includes the org.apache.http package for HTTP networking. This example uses a fictional simple socket connection for uploading, but you can easily adapt it to match whatever your server expects (see Listing 9).

When reviewing the code for the Uploader, Java developers may be struck by how ordinary the uploading code appears. By avoiding specialized classes, Android offers a gentle learning curve to experienced Java SE and Java EE developers.

One concept requires some special explanation: the Handler. As mentioned above, Android uses only a single UI thread. If your new Thread attempts to update an element on the screen while the main UI thread is also trying to update, this may corrupt the state. The solution is to define a Handler, which is a simple class that receives messages. When your thread wants to update something on the screen, it creates a Message and sends it to the Handler. The Handler will be invoked in the main UI thread where it can safely update the screen?in this situation, stopping the progress animation and displaying some text.

Where Do We Go From Here?
By writing four Activities, four XML files, and one helper class, you have created an application that exercises many Android capabilities:

  • You used a variety of Android’s Views and arranged them into different layouts.
  • You have created a SQLite database that provides access to image records.
  • You have learned how to capture, store, view, and send camera images.
  • You can navigate between Activities.
  • You can update information in a database.
  • You can communicate over the network to an external server.

You should now have the tools to go out and create your own Android applications. If you’d like to enhance ConnectedCamera, here are some things you could explore:

  • Instead of showing the names of photos in the Album, show thumbnail images.
  • Add the ability to delete images. Don’t forget to clean up the filesystem as well as the database!
  • Try registering your images with the Image ContentProvider so other applications can access them.
  • Use geocoding to record where each image was taken.

Programming in Android is coding on the bleeding edge. It offers solid functionality and design, at the cost of a rapidly evolving platform that doesn’t always work as advertised. After handsets start to ship, you may look back at these hectic early days with nostalgia. In the meantime, get out there, code, and have fun!

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: