FirstClown

firstclown at firstclown.us

Archive for December 11th, 2008

Adding Icons to Your Android Application

After seeing how easy it is to add an icon to a contact in my new G1 phone, I decided to try and do it in an application of my own. I've sense been asked about it a little bit, so I figured I'd post how to do it on my blog. It's surprisingly easy, but there's quite a few steps involved.

BTW, none if this is original, but I haven't seen anyone really write a up a complete post on how to do it. I reverse engineered the concept and the steps from the great open source project apps-for-android.

UI

To set up the interface for adding the icon, you'll want to add an ImageButton to the edit screen for your items. You can then set the image with:

    protected void showIconButton(String iconUri){
        if(iconUri != null){
            ImageButton iconField = (ImageButton) findViewById(R.id.iconButton);
            iconField.setImageURI(null);
            iconField.setImageURI(Uri.parse(iconUri));
            iconField.invalidate();
        }
    }

You'll need the extra iconField.setImageURI(null); call in there since Android ignores a call to setImageURI that has the same URI is it currently holds. Since I save the new icon image to the same place as the old one, that can be a problem.

You'll also want to have the button set up to select a new image when it's clicked. That will be a simple call to iconField.setOnClickListener(cmdIconListener); in the onCreate method of the Activity.

Button Listener

Now we can create the action the button should take when it's clicked.

    protected OnClickListener cmdIconListener = new OnClickListener() {
        public void onClick(View arg0) {
            Intent i = new Intent("android.intent.action.GET_CONTENT");
            i.setType("image/*"); // We just want images.
 
            //ADD_ICON is a unique integer code for the intent response.
            startActivityForResult(i, AddTea.ADD_ICON); 
        }
    };

You can see we're firing a very simple Intent to get an image. This will allow the user to select an image from their picture gallery, just like the contact application does. It also keeps it generic enough that another application can act on this Intent, too.

Crop the Image

This Intent will return an image URI that we then want to crop:

    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        // See which child activity is calling us back.
        switch (requestCode) {
        case AddTea.ADD_ICON:
            // This is the standard resultCode that is sent back if the
            // activity crashed or didn't doesn't supply an explicit result.
            if (resultCode != RESULT_CANCELED){
                Intent i = new Intent("com.android.camera.action.CROP");
                i.setClassName("com.android.camera", "com.android.camera.CropImage");
                i.setData(data.getData());
                Log.d(TAG, "path: " + data.getData().getPath());
                i.putExtra("noFaceDetection", true);
                i.putExtra("outputX", iconWidth);
                i.putExtra("outputY", iconHeight);
                i.putExtra("aspectX", iconWidth);
                i.putExtra("aspectY", iconHeight);
                i.putExtra("scale", true);
 
                if(iconUri == null){
                    ContentValues values = new ContentValues();
                    values.put(android.provider.MediaStore.Images.Media.TITLE, name + " Icon");
                    values.put(android.provider.MediaStore.Images.Media.BUCKET_ID, "STeaP_Tea_Timer_Icons");
                    values.put(android.provider.MediaStore.Images.Media.BUCKET_DISPLAY_NAME, "STeaP Tea Timer Icons");
                    values.put(android.provider.MediaStore.Images.Media.IS_PRIVATE, 1);
                    iconUri = getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values).toString();
                }
                i.putExtra("output", Uri.parse(iconUri));
                startActivityForResult(i, CROP_ICON);
            }
            break;

We're basically just sending another Intent after getting the first one back. Here we are sending the Intent to a specific Activity, the com.android.camera.CropImage Activity. This Activity will crop the image and save the image, so we need to pass all the information we want the image saved with. The important ones are:

  • noFaceDetection - Unless you're looking for people, you'll want this to be true.
  • outputX - The width of the resulting image. In pixels.
  • outputY - The height of the resulting image. In pixels.
  • aspectX, aspectY - The aspect ratio of the crop square. Don't set these if you want the user to pick whatever size they want, otherwise set them to what you want.
  • scale - Whether you want the image scaled to the dimensions you set. Almost always should be true.
  • android.provider.MediaStore.Images.Media.IS_PRIVATE - Set to true if you don't want all of your little icons clogging up the Android Pictures app.

The insert command on the ContentProvider will hand you back the images URI so you can store it with the rest of your item's data. In my example, if I already have a URI for the icon, I just overwrite it with the new cropped image, no need to create another one.

Now we just need to handle the result from the Crop Intent:

case AddTea.CROP_ICON:
            if (resultCode != RESULT_CANCELED) {
                Log.d(TAG, "Data String: " + iconUri);
                showIconButton(iconUri);
            }
        default:
            break;

And now you've got your icon stored in the ContentProvider and the URI in your application. Easy as that!

WordPress 2.7 Backup and Upgrade Features

This blog is currently running off of WordPress 2.7 and I was impressed at the backup and upgrade features that have been built into it. I would recommend everyone to upgrade to 2.7 and, to entice you, I've listed some of my favorite features below.

Version Control

When you edit a post or page, WordPress will keep a record of every time you save it, and even times in between. That means that you have a full revision history of all of your posts. Liked it better three minutes ago before you completely butchered it? Just open up an old revision a start editing from there.

There's also a view that lets you see the differences between two different versions. Very useful if you're not quite sure what you changed.

Export/Import

WordPress has an Export option, which allows you to export all of your posts, pages, comments, fields, categories and tags into an XML document that you can then import into another WordPress blog. There are also a ton of Import options for a variety of other blog platforms to WordPress. This has been in WordPress for a while and doesn't replace a full database backup, but it is a nice quick way to backup your data.

Auto Update

2.7 now let's you update your WordPress blog with the push of a button, instead of jumping through hoops to upload the files to your site (and maybe accidentally overwrite your themes folder). With the one push update, it'll be easier than ever to keep your site updated with the latest security fixes released by WordPress. I used to do this with Automattic's Subversion repositories, but now anyone can do an upgrade easily without resorting to FTP or crazy command line tricks.

I have had no problems at all with themes or plugins. Everything seems very backwards compatible.

All of these features and the updated Dashboard make WordPress 2.7 a recommended update.

FirstClown is powered by WordPress
Entries (RSS) and Comments (RSS).