Tuesday, 21 June 2011

Checking if an Intent handler or Activity is present

Quite often in Android you need to call a 3rd party Intent or activity.
For example, to scan a barcode using the Barcode Scanner application, or to start the "hidden" Field Test application in HTC phones.

In order to make the life of a user easier, it is a good idea to check if the Intent Receiver/Activity exists before you attempt to invoke it. Some of the reasons being:
  1. If a non-existent intent, you application will force close.
  2. If the intent receiver is not present, you might want to redirect the user to the market to download the necessary application.
  3. Depending on the existence of an intent you might want to make menu options appear/disappear.
This post contains two functions (isIntentAvailable() and isActivityAvailable())which can perform the checking and return a boolean accordingly.


public boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List resolveInfo =
            packageManager.queryIntentActivities(intent,
                    PackageManager.MATCH_DEFAULT_ONLY);
   if (resolveInfo.size() > 0) {
     return true;
    }
   return false;
}

The following example will check to see if the encode action of Barcode Scanner exists and load it with dummy data ("123456789"). If the intent is unavailable, it will open up Barcode Scanner's page in the Android Market so the user can download it. In a real deployment you might want to add a messagebox informing the user of what is going on and possibly allowing him to cancel.

if (isIntentAvailable(this, "com.google.zxing.client.android.ENCODE")){  
 Intent i = new Intent();
 i.setAction("com.google.zxing.client.android.ENCODE");
 i.putExtra ("ENCODE_TYPE", "TEXT_TYPE");
 i.putExtra ("ENCODE_DATA", "123456789");
 startActivity(i); 
} else {
 Intent intent = new Intent(Intent.ACTION_VIEW);
     intent.setData(Uri.parse(market://details?id=com.google.zxing.client.android));
     startActivity(intent);
}

The following snippet will try to find if an activity exists so it can be called.

public boolean isActivityAvailable(Context context, String packageName, String className) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent();
    intent.setClassName(packageName, className);
    
    List list = packageManager.queryIntentActivities(intent,
                    PackageManager.MATCH_DEFAULT_ONLY);

    return list.size() > 0;
}

The following example, will check if the "Field Test" activity exists. Field Test is an application which gives low-level information about a phone's communication systems and it only exists on HTC devices running Sense. If the Activity exists, it will create the respective menu item.

    /** Creates the menu items */
public boolean onCreateOptionsMenu(Menu menu) {
    Boolean fieldTest = isActivityAvailable("com.htc.fieldtest", "com.htc.fieldtest.FieldTestActivity");

    menu.add(0, MENU_BUTTONS.REFRESH.ordinal(), 0,
            getString(R.string.label_menu_refresh)).setIcon(android.R.drawable.ic_menu_rotate);
    menu.add(0, MENU_BUTTONS.EXPORT.ordinal(), 0,
            getString(R.string.label_menu_export)).setIcon(android.R.drawable.ic_menu_upload);
    menu.add(0, MENU_BUTTONS.ABOUT.ordinal(), 0,
            getString(R.string.label_menu_about)).setIcon(android.R.drawable.ic_menu_info_details);
    if (fieldTest){       
        menu.add(0, MENU_BUTTONS.FIELD_TEST.ordinal(), 0,
                getString(R.string.label_menu_field_test)).setIcon(android.R.drawable.ic_menu_manage);
    }
    return true;
}

Acknowledgements: The first function is taken from http://android-developers.blogspot.com/2009/01/can-i-use-this-intent.html

12 comments:

  1. The second part of the example won't work unless you include a context in the function call. FYI.

    ReplyDelete
  2. Any idea how to unit test this? I've been searching for a way to shadow the PackageManager but found nothing.

    ReplyDelete
  3. Καλησπέρα! Θα μπορούσατε να μου πείτε πώς λέγεται το "intent handler" στα Ελληνικά; Ευχαριστώ πολύ! :)

    ReplyDelete
  4. Good sharing! I need a javascript encode number interleafed barcode, but I haven't any idea, can you help me? Thanks a lot.

    ReplyDelete