Android: Nuts and Bolts VII

Today we continue our lesson on Activities and Intents. In Part One of our discussion, I explained how to switch Activities within a single application. This time, we’ll discuss how to launch an Activity belonging to another application. I will use as an example some code from my work with the OpenIntents FileBrowser. Check out the Read More!

In order for an Activity to accept generic requests (implicit Intents), it must specify one or more Intent Filters. An Intent Filter is a statement made in the AndroidManifest.xml that lets the environment know what your Activity can do. There is no specification for how your Activity handles a given Intent, you merely make the statement that you handle it. Of course, it would be bad practice indeed to advertise functionality that you don’t actually have!

The example we’re discussing concerns the OpenIntents FileManager class, so I’ll go ahead and show you the full Manifest entry for that Activity:

(NOTE: as with last time, I mean LESS_THAN and GREATER_THAN instead of [ and ], but the blog
likes to interpret the xml as actual xml instead of raw code)
[activity android:name=".FileManagerActivity" android:label="@string/app_name"]
[intent-filter]
[action android:name="android.intent.action.MAIN" /]
[category android:name="android.intent.category.LAUNCHER" /]
[/intent-filter]
[intent-filter]
[action android:name="org.openintents.action.PICK_FILE"/]
[category android:name="android.intent.category.DEFAULT" /]
[data android:scheme="file" /]
[/intent-filter]
[intent-filter]
[action android:name="org.openintents.action.PICK_FILE"/]
[category android:name="android.intent.category.DEFAULT" /]
[/intent-filter]
[intent-filter]
[action android:name="org.openintents.action.PICK_DIRECTORY"/]
[category android:name="android.intent.category.DEFAULT" /]
[data android:scheme="file" /]
[/intent-filter]
[intent-filter]
[action android:name="org.openintents.action.PICK_DIRECTORY"/]
[category android:name="android.intent.category.DEFAULT" /]
[/intent-filter]
[/activity]

Don’t worry too much over the Scheme stuff for now- you can read about all of the bells and whistles of Intents/Intent Filters after we cover the basics. Essentially what we have above is: a statement that the FileManager Activity exists, the name to display in the title bar, and a list of Intent-filters which the Activity can handle. You don’t need to have more than one, but OpenIntents includes these five because they have coded functionality for many use cases.

Basically, what we have here is OpenIntents letting Android know that their Activity can be used to pick directories or files. Other applications can use this Activity to achieve these tasks with minimal effort. Additionally, the filebrowser can be launched by itself as a stand-alone activity.

The Action field describes what general types of requests the Activity will respond to, while the Category (and also Data, but this isn’t used in our example) field describes specifics about what the Intent is doing. If an intent filter does not include every category which is in the intent object being sent, the intent will not be sent! The component field is only used when declaring an explicit intent (launching a specific Activity as opposed to letting the user choose).

Now, as far as what I do on the Mobile Metagenomics side, I must again give credit to the OpenIntents guys. I took the snippet straight out of another part of their File Browser utility. Essentially it creates an Intent object that will match up with one of the Intent Filters given above:

public void openFile() {

Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE);

try {
startActivityForResult(intent, REQUEST_CODE_PICK_FILE_OR_DIRECTORY);
} catch (ActivityNotFoundException e) {
// No compatible file manager was found.
Toast.makeText(this, R.string.no_filemanager_installed,
Toast.LENGTH_SHORT).show();
}
}

Where openFile is called in MM’s browseButton.onClick() method in the onClickListener. The ‘Intent intent = new Intent’ business should look familiar to you from last time, with the notable difference being that we are not specifying a class. Instead, we are specifying an Action; specifically, we tell Android that we are trying to pick a file. The rest of the code is essentially the same as what we have already covered in previous N&B articles; we start the activity, keeping a code so we can write an onActivityResult switch, and in case the user has no file manager installed we pop up a Toast letting them know.

Note that if you set up your application classpath/dependencies/etc right in Eclipse, the OI File Manager will actually come bundled with your application. (But we still do error checking, because a user might say “what is this junk?!” and delete it!)

The last piece of the puzzle to implementing the FileManager as our file chooser is to do the aforementioned onActivityResult bit, but that turns out to be really simple:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Bundle extras = intent.getExtras();
switch(requestCode) {
case REQUEST_CODE_PICK_FILE_OR_DIRECTORY:
if (resultCode == RESULT_OK && intent != null) {
// obtain the filename
String filename = intent.getDataString();
if (filename != null) {
// Get rid of URI prefix:
if (filename.startsWith("file://")) {
filename = filename.substring(7);
}

fileName.setText(filename);
}                
}
break;
}
}

the if check song-and-dance is just to make sure we don’t end up with some gross Null value if something goes wrong. The substring business is MM-specific and exists just to display the filename in an uncluttered manner. The only parts the actually matter as far as what we’re trying to cover in this article are:

Bundle extras = intent.getExtras();

and

 String filename = intent.getDataString();

but beyond that, everything is specific to your application. I figured it was more educational to give a ‘real’ example, and it also gives a peek behind-the-scenes of MM 🙂

Of course, the concepts here can be applied to any of your own projects; whether creating custom ‘Intents’ for others to use like OI does, or breaking up your own application into several functional pieces. As always, I hope it helps, and thanks for reading!