Intents

Intro

You've already seen Intents before.  As you remember, Intents are the glue we use to tie Activities together.  They also allow us to pass data back and forth between Activities using Intent extras.  Until now, we've only used Intents to launch Activities that are a part of the same application.  But they can do so much more!  Using Intents, we can launch Activites from ANY application on the device, including the default built-in apps.

Sample App for this lesson: IntentExamples.zip

Invoking Built-in Activities

Up until this not, the only Activities that we've launched have been from within the same app.  To do this, we created a new Intent, with the second argument being the name of the Java class for the Activity we wanted to launch.  Formatted this way, the Activity creating the Intent knows that the desired Activity is a part of the same app: 

startActivity(new Intent(getBaseContext(), SampleActivity.class));
But what if you want to launch an Activity from a different app?  Luckily for us, we can also use Intents to invoke Activities in other applications!  We saw this behavior previously, whether you realized it or not.  When we first created the WebView Activity in our Presidents List app and tried to load a URL, the device's default browser was launched.  We had to explicitly tell our application to not do that.  There are certain behaviors (like loading web pages) that have default applications pre-assigned to them by the operating system.  Knowing this, if we know the proper format, we can launch these default applications from within our own app.  
 

The Intent we will use to launch default apps is known as an Implicit Intent, because instead passing a Java class file name, we tell the Intent what behavior we want to see. More specifically, Implicit Intents are usually formatted using an action and data pair.  The action specifies what to do and the data specifies what is affected.  The data is passed as an argument in the form of a Uri object.  For example, if you want your app to launch the device's Phone activity and dial a given number (but not call it), you would use the following code:

Uri sampleNumber = Uri.parse("tel:+8002752273");
Intent i = new Intent(Intent.ACTION_DIAL, sampleNumber);
startActivity(i);

In the above example, We use the Uri class to parse a telephone number, returning a Uri object.  We pass this newly created Uri as an argument to a new Intent, along with the ACTION_DIAL action.  The operating system will then look for any installed apps that have declared (in their manifest file) that they are able to handle that action.  In this case, the Phone app handles the action we want, and it is launched.  

If you instead wanted the Phone activity to call the number, you would use the ACTION_CALL action:

Intent i = new Intent(Intent.ACTION_CALL, sampleNumber);
**NOTE: accessing the phone requires the proper permissions in the manifest file:
                                 <uses-permission android:name="android.permission.CALL_PHONE"/>

 

Some actions have different behaviors based on the format of the data parsed by the Uri.  For example, to launch the default web browser, you would use the ACTION_VIEW action along with a parsed URL:

Intent i = new Intent(Intent.ACTION_VIEW,
        Uri.parse("http://www.usna.edu/Users/cs/pepin/courses/mobileos/"));
startActivity(i);

But if instead of passing a URL, I pass geographic coordinates, the Maps application is launched:

Intent i = new Intent(Intent.ACTION_VIEW,
        Uri.parse("geo:36.593920,-121.875661?z=16"));
startActivity(i);
**NOTE:  In order to use the Maps application, you'll need an AVD that supports the Google APIs.

 

Some other commonly used actions are:

To see the full list of standard Activity actions, visit the Android developer page and/or the API guide:

To see more examples of how to launch built-in applications, see here: Sending the User to Another App

Letting Other Apps Call Your Activity

Launching apps written by someone else is fun, but wouldn't it be nice if others could choose ot launch our app as well?  Well, they can!  In order for other apps to be able to invoke your Activity, you first need to define an intent filter for the Activity in your application's manifest file that contains both action and category elements:  

<activity 
    android:name=".SampleActivity"
    android:label="@string/app_name" >
		  
    <intent-filter>
	<action android:name="edu.cs.usna.SampleActivity" />
	<category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
	
</activity>

The label is the text that's displayed in the top bar (aka the Action Bar) of your activity.  The intent filter in the above example defines an action with a unique "name" property.  This is the value that other applications will use in order to launch this activity.  This name is usually formatted using the package name followed by the activity name.  This minimizes that chance that two activites from different apps on the device have the same intent-filter name.

In order to enable the ability for other apps to launch this activity using startActivity(), you must also set the category property using "android.intent.category.DEFAULT" as shown in the example above.  

You already know how to launch this activity from within your app:

startActivity(new Intent(getBaseContext(), SampleActivity.class));

To start this activity from another app, the format changes slightly:

startActivity(new Intent("edu.cs.usna.SampleActivity"));

When the calling Activity runs the above startActivity() method, the operating system will look for an installed Activity that has a defined intent filter containing an action named "edu.cs.usna.SampleActivity".

Intent Filter Name Collisions

There's always the possibility that two intent-filters on the device have the same name, creating a conflict.  So what happens when two activities (either from separate applications or the same) have the same intent-filter name?  Luckily for us, the developers at Google are smart, and have accounted for this possibility!  If a new intent is created using an intent-filter name that is defined by more than one activity installed on the device, a dialog will be displayed with a list of choices.  If you choose the option to use the chosen activity by default, the options dialog will not display again until you clear the default value from the device's settings.  Launch the Sample Project application and click on the "Open Browser" button to see this behavior.

Now that you know how intent-filters work, you can modify your "Poor Man's Browser" app so that the device user can set it as the device's default browser!!

Expanding Your Knowledge

Look closely at how the sample project handles setting onClick listeners for the Button elements.  There's a new android:onClick property defined:

<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Open Browser"
    android:onClick="openWebBrowser" />

The value given to the android:onClick property corresponds to the name of a method that must be implemented in the Activity that uses this layout file.  Doing it this way, you're not required set the OnClick listener programatically in your java code (using setOnClickListener());