Today we’re going to talk about something we touched on earlier in the 31 Days of AndroidIntents.  If you’ve been following along, you’ll recall that you used intents when you wanted to go from one Activity in your application to another.  This is certainly one common use for intents and might be the only time you use them.  However, intents can be used for so much more.  In addition to be using to send messages within your application (say if you’re running a service or hosting a broadcast receiver), intents can be used to communicate with other applications.  You will see that intents are key to enabling the Android operating system to feature the rich interconnectivity that it does. You can download the sample code we’re going to start with here.

Note:  Some of the examples won’t work very well on the emulator due to the inability to install other applications.  If you have a device I would suggest testing with it.

What are Intents

Simply put, intents are messages.  More specifically, they are data structures that contain information on an operation to be performed or the description of something that has happened.  Typically messages specifying an operation to be performed will be sent to either an Activity or a Service.  Messages about something that has happened are usually delivered to Broadcast Receivers.  An intent can explicitly declare which component should receive (as is the case when you launch one Activity in your app from another) or it can be open ended.  These open ended Intents are one of the ways in which Android enables new applications to become connected to others without everyone needing to go back and update things.  We’ll get into more about how the open ended Intents work a little later today.

 

Launching Activities with Intents

If you were around for Day 5 where we went over using multiple activities in your application, moving between activities with intents will already be familiar.  Since the sample code is actually the results of Day 5, the code for this is already done.  Open src/com.daytwentysix/DayTwentySixActivity.java and look at the button2 onClickListener:

startActivity(new Intent(getApplicationContext(), ActivityTwo.class));
finish();

The first line of this code is actually all that is necessary to start ActivityTwo.  Here you are creating a new Intent object with the application Context and the class for the Activity that should be started.  The call to finish means that the current Activity will be terminated.  As such, if you run your app and tap the second button, you’ll be taken to the second Activity and if you hit back, you will back out of the app.  If you remove the call to finish and do the same thing, the second Activity will be stacked on top of the first one and when you hit back, you’ll return to the first Activity.  

 

Passing Data with Intents

Intents wouldn’t be very powerful if you could only start things with them but couldn’t pass any data.  This concept of sharing data was covered in detail in Day 7 but we’ll review it again as a refresher.  Intents, in addition to specifying an action or a receiver, can contain any data you want to pass as “extras”.  Adding extras to an intent is very easy and just requires a call to putExtra.  This method is overloaded to accept a key name and then most primitive types.  You can also pass in a parcelable object (similar to serializing) but I’ll point you back to Day 7 for more info on that.  Let’s say that you want to change the onClickListener to send the text you’ve entered in the EditText over to the second Activity.  Here’s how you’d accomplish that:

button2.setOnClickListener(new OnClickListener() {            
    public void onClick(View v) {
        Intent intent = new Intent(getApplicationContext(), ActivityTwo.class);
        intent.putExtra("MyStringValue", editText1.getText().toString());
        startActivity(intent);
    }
});

Here you’ve had to take the creation of the Intent out of the call to startActivity so that you can put your extra in it.  Now in ActivityTwo you can access the data passed over by getting the intent and pulling out the extra:

TextView textView1 = (TextView) findViewById(R.id.textView1);
Intent intent = getIntent();
textView1.setText(intent.getStringExtra("MyStringValue"));

 

Making Phone Calls with Intents

If you wanted to make a phone call out of your application, it’s extremely easy thanks to Intents.  First though, you need to add a permission to your manifest file:

<uses-permission android:name="android.permission.CALL_PHONE"/>

This permission means your app has access to interact with the phone.  Once that is done, you just need to alter your intent creation:

Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:8887676424")); 
startActivity(callIntent);

Now when you run your app and tap the second button, it will open up and start dialing the number passed in.  If you wanted to open up the phone dialer without immediately dialing (i.e. the user would have to hit the dial button) you could change ACTION_CALL to ACTION_DIAL.  If you wanted to open up the dialer and not pass any number in, you could use ACTION_DIAL and not use a second parameter.

 

Sharing with an Intent

One fairly common feature in Android is “sharing”.  Many of the apps Android users might use (Google+, Camera, Twitter, Facebook, Reader, etc) enable users to Share things.  Let’s take a look at the code first:

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, editText1.getText().toString());
startActivity(Intent.createChooser(shareIntent,"Share with"));

Intent.ACTION_SEND tells Android you want this intent to be handled by something capable of handling ACTION_SEND.  Many applications (such as Google+, Twitter, Facebook, etc) have set up Intent Filters that tell Android that they can handle ACTION_SEND.  The call’s to setType and putExtra specify what type of data you’re going to pass and what that data is.  Lastly, instead of just passing the Intent into startActivity you’re calling the createChooser method.  This will present a dialog to the user so they can select which application they want to handle the Intent.  When I run this on my phone here are some of the apps that say they are capable of sharing:

Android Sharing Options

 

Each application on the list might handle what you pass in a different manner and it’s entirely up to them.  Some, such as Facebook (at least as of writing) require you to pass a URL over in the EXTRA_TEXT

 

Sending an Email (only) with an Intent

You might notice as you look at all of the apps capable of handling ACTION_SEND that there are a lot.  Furthermore, some of them are capable of handling very different things.  For example, Twitter limits posts to 144 characters.  Conversely, an email’s body can be much larger and can also use a subject.  While it’s not impossible, it can be difficult to limit which apps will show up in the chooser.  If you wanted to limit to only programs that handle emails, you could change the type to be “message/rfc822”.  You could also pass in a subject to give email programs even more information about what you’re trying to share:

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("message/rfc822");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "the subject");                
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, editText1.getText().toString());
startActivity(Intent.createChooser(shareIntent,"Email with"));

You’ll find as you continue to explore intents that there are other values you can send over and other ways you might be able to limit the responding applications.

Opening a Website with an Intent

Opening a web page via an Intent is also easy to accomplish:

Intent webIntent = new Intent(Intent.ACTION_VIEW);  
webIntent.setData(Uri.parse("http://www.chrisrisner.com"));  
startActivity(webIntent);

Here Intent.ACTION_VIEW is passed in as the action and the URI of the web site you want to visit is passed in as the data.

 

Showing an Address on the Map

Provided you have the mailing address of the location you want to show on a map, pulling it up is very easy.  Note that this will present to the user a dialog to choose which map program they want to use (if there are multiple):

Intent myIntent = new Intent(Intent.ACTION_VIEW, 
        Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA+94043"));
startActivity(myIntent);

Intent.ACTION_VIEW is used again to open the maps.  This time though, you’re passing in the address as the Uri.  This should demonstrate how specific apps can be with what Intents they are capable of dealing with.  Map programs are set to handle addresses and geo coordinates.  Browsers are used for URLs.  Furthermore, an application can specify URLs that it can handle as well.  As an example, if you have the Yelp app installed and fire an intent to view a restaurant at the Yelp web page, Android will ask if you want to view it in the browser or the Yelp app.  This is another way that Android makes it possible to interconnect apps without having to go back and change older applications.

 

Opening a New Calendar Entry with an Intent

Creating a calendar entry is fairly straight forward and can be done.  However, it doesn’t seem to be well documented.  In addition, in Android 4.0 they’ve released a Calendar Content Provider that you should be able to use instead of this method.  Until then, you can use this:

Intent calendarIntent = new Intent(Intent.ACTION_EDIT);
calendarIntent.setType("vnd.android.cursor.item/event");
calendarIntent.putExtra("title", "The event title");
calendarIntent.putExtra("description", "The event description");
calendarIntent.putExtra("eventLocation", "1600+Amphitheatre+Parkway,+Mountain+View,+CA+94043");
startActivity(calendarIntent);

Here the action is Intent.ACTION_EDIT.  You’re passing a specific type that maps to an event and then details for the title, description, and location.

 

Launching the Marketplace via Intent

If you have multiple apps and you want to encourage people to install your other applications, you can send them to the Android Marketplace from your app with an Intent.  To do so, you just need to know the package name of your application.  The demo application’s package is com.daytwentyfive but for our demo let’s send people to Google+:

Uri marketUri = Uri.parse("market://search?q=com.google.android.apps.plus");
Intent marketIntent = new Intent(Intent.ACTION_VIEW).setData(marketUri);
startActivity(marketIntent);

You can get the package name for an application by finding it in the Marketplace and looking at the URL.  When you start this activity it will take the user to a search page with the results for this app. 

 

Listening for Intents:  The Intent Filter

The way that all of these intents work is that the applications they correspond to have set up Intent Filters to respond to the actions you sent over.  The only REQUIRED step for setting up your Intent Filter is a change to your manifest file.  Let’s alter your ActivityTwo manifest details so you can share text to your app:

<activity android:name=".ActivityTwo" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/*"/>                
    </intent-filter>    
</activity>

The action you specify is the ACTION_SEND that you used earlier to share out text.  The category is just the default.  Lastly the data type specifies that if an app wants to share String data, your app can respond to it.   Now after you install your app, start up a different app that is capable of sharing text.  I started the Twitter app for example.  After tapping the app’s share button, you should now see your application in the chooser dialog:

DayTwentySix in the Share Chooser

In order to handle actually getting shared to your ActivityTwo you will need to make some code changes.  You’re already getting the intent that fired the Activity.  Now you can check to see if the action of that Intent is ACTION_SEND and if so, pull out the EXTRA_TEXT variable passed in:

Intent intent = getIntent();
        
if (intent.getStringExtra("MyStringValue") != null)
    textView1.setText(intent.getStringExtra("MyStringValue"));
else if (intent.getAction().equals(Intent.ACTION_SEND)) {         
    textView1.setText("Created by sharing! And text is " + 
            intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
}

Now your ActivityTwo is capable of being created within your app and having MyStringValue sent into it, or it can be created via another application sharing to it.  If you do decide to create an Intent Filter in your app, make sure you understand if other people are using it before you go and remove it.  If someone else designs an application that makes use of your app via intent, it’s poor etiquette to go and break their functionality by altering or removing your filter.

 

Intents are Awesome

This just skims the surface of what is possible with Intents.  I truly believe that Intents are one of the most powerful parts of Android and really help differentiate it from iOS.  Instead of all the apps being sandboxed, there is interconnectivity and ways to make things easier and more convenient for users. 

You can download the final code from the sample app here.


Chris Risner