blob: 79c017b3ae9f2d850d2efbb539fb1657fbeac4b3 [file] [log] [blame]
Scott Mainba8f4352012-03-29 23:03:13 -07001page.title=Sending the User to Another App
2parent.title=Interacting with Other Apps
3parent.link=index.html
4
5trainingnavtop=true
6next.title=Getting a Result from an Activity
7next.link=result.html
8
9@jd:body
10
11
12<div id="tb-wrapper">
13 <div id="tb">
14
15<h2>This lesson teaches you to</h2>
16<ol>
17 <li><a href="#Build">Build an Implicit Intent</a></li>
18 <li><a href="#Verify">Verify There is an App to Receive the Intent</a></li>
19 <li><a href="#StartActivity">Start an Activity with the Intent</a></li>
Scott Main1cf92552012-04-20 15:46:49 -070020 <li><a href="#AppChooser">Show an App Chooser</a></li>
Scott Mainba8f4352012-03-29 23:03:13 -070021</ol>
22
23<h2>You should also read</h2>
24<ul>
Joe Malin45edbb72013-08-26 14:55:54 -070025 <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li>
Scott Mainba8f4352012-03-29 23:03:13 -070026</ul>
27
28 </div>
29</div>
30
31<p>One of Android's most important features is an app's ability to send the user to another app
32based on an "action" it would like to perform. For example, if
33your app has the address of a business that you'd like to show on a map, you don't have to build
Scott Maincb0b2df2012-08-09 11:49:50 -070034an activity in your app that shows a map. Instead, you can create a request to view the address
35using an {@link android.content.Intent}. The Android system then starts an app that's able to show
Scott Mainba8f4352012-03-29 23:03:13 -070036the address on a map.</p>
37
Scott Maincb0b2df2012-08-09 11:49:50 -070038<p>As explained in the first class, <a href="{@docRoot}training/basics/firstapp/index.html">Building
Scott Mainba8f4352012-03-29 23:03:13 -070039Your First App</a>, you must use intents to navigate between activities in your own app. You
40generally do so with an <em>explicit intent</em>, which defines the exact class name of the
41component you want to start. However, when you want to have a separate app perform an action, such
42as "view a map," you must use an <em>implicit intent</em>.</p>
43
44<p>This lesson shows you how to create an implicit intent for a particular action, and how to use it
45to start an activity that performs the action in another app.</p>
46
47
48
49<h2 id="Build">Build an Implicit Intent</h2>
50
51<p>Implicit intents do not declare the class name of the component to start, but instead declare an
52action to perform. The action specifies the thing you want to do, such as <em>view</em>,
53<em>edit</em>, <em>send</em>, or <em>get</em> something. Intents often also include data associated
54with the action, such as the address you want to view, or the email message you want to send.
55Depending on the intent you want to create, the data might be a {@link android.net.Uri},
56one of several other data types, or the intent might not need data at all.</p>
57
58<p>If your data is a {@link android.net.Uri}, there's a simple {@link
59android.content.Intent#Intent(String,Uri) Intent()} constructor you can use define the action and
60data.</p>
61
62<p>For example, here's how to create an intent to initiate a phone call using the {@link
63android.net.Uri} data to specify the telephone number:</p>
64
65<pre>
66Uri number = Uri.parse("tel:5551234");
67Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
68</pre>
69
70<p>When your app invokes this intent by calling {@link android.app.Activity#startActivity
71startActivity()}, the Phone app initiates a call to the given phone number.</p>
72
73<p>Here are a couple other intents and their action and {@link android.net.Uri} data
74pairs:</p>
75
76<ul>
77 <li>View a map:
78<pre>
79// Map point based on address
80Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
81// Or map point based on latitude/longitude
82// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
83Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
84</pre>
85 </li>
86 <li>View a web page:
87<pre>
88Uri webpage = Uri.parse("http://www.android.com");
89Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
90</pre>
91 </li>
92</ul>
93
94<p>Other kinds of implicit intents require "extra" data that provide different data types,
95such as a string. You can add one or more pieces of extra data using the various {@link
96android.content.Intent#putExtra(String,String) putExtra()} methods.</p>
97
98<p>By default, the system determines the appropriate MIME type required by an intent based on the
99{@link android.net.Uri} data that's included. If you don't include a {@link android.net.Uri} in the
100intent, you should usually use {@link android.content.Intent#setType setType()} to specify the type
101of data associated with the intent. Setting the MIME type further specifies which kinds of
102activities should receive the intent.</p>
103
104<p>Here are some more intents that add extra data to specify the desired action:</p>
105
106<ul>
107 <li>Send an email with an attachment:
108<pre>
109Intent emailIntent = new Intent(Intent.ACTION_SEND);
110// The intent does not have a URI, so declare the "text/plain" MIME type
111emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
112emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients
113emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
114emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
Scott Mainfd516982012-07-03 16:25:52 -0700115emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
Scott Mainba8f4352012-03-29 23:03:13 -0700116// You can also attach multiple items by passing an ArrayList of Uris
117</pre>
118 </li>
119 <li>Create a calendar event:
120<pre>
121Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
122Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
123Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
124calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
125calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
126calendarIntent.putExtra(Events.TITLE, "Ninja class");
127calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
128</pre>
129<p class="note"><strong>Note:</strong> This intent for a calendar event is supported only with API
130level 14 and higher.</p>
131 </li>
132</ul>
133
134<p class="note"><strong>Note:</strong> It's important that you define your {@link
135android.content.Intent} to be as specific as possible. For example, if you want to display an image
136using the {@link android.content.Intent#ACTION_VIEW} intent, you should specify a MIME type of
137{@code image/*}. This prevents apps that can "view" other types of data (like a map app) from being
138triggered by the intent.</p>
139
140
141
142<h2 id="Verify">Verify There is an App to Receive the Intent</h2>
143
144<p>Although the Android platform guarantees that certain intents will resolve to one of the
145built-in apps (such as the Phone, Email, or Calendar app), you should always include a
146verification step before invoking an intent.</p>
147
148<p class="caution"><strong>Caution:</strong> If you invoke an intent and there is no app
149available on the device that can handle the intent, your app will crash.</p>
150
151<p>To verify there is an activity available that can respond to the intent, call {@link
152android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()} to get a list
153of activities capable of handling your {@link android.content.Intent}. If the returned {@link
154java.util.List} is not empty, you can safely use the intent. For example:</p>
155
156<pre>
157PackageManager packageManager = {@link android.content.Context#getPackageManager()};
158List&lt;ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
159boolean isIntentSafe = activities.size() > 0;
160</pre>
161
162<p>If <code>isIntentSafe</code> is <code>true</code>, then at least one app will respond to
163the intent. If it is <code>false</code>, then there aren't any apps to handle the intent.</p>
164
165<p class="note"><strong>Note:</strong> You should perform this check when your activity first
166starts in case you need to disable the feature that uses the intent before the user attempts to use
167it. If you know of a specific app that can handle the intent, you can also provide a link for the
168user to download the app (see how to <a
Scott Main50e990c2012-06-21 17:14:39 -0700169href="{@docRoot}distribute/googleplay/promote/linking.html">link to your product on Google
Scott Mainba8f4352012-03-29 23:03:13 -0700170Play</a>).</p>
171
172
173<h2 id="StartActivity">Start an Activity with the Intent</h2>
174
Scott Main159a5ff2013-07-30 12:06:38 -0700175<div class="figure" style="width:200px;margin-top:-10px">
Scott Mainba8f4352012-03-29 23:03:13 -0700176 <img src="{@docRoot}images/training/basics/intents-choice.png" alt="" />
177 <p class="img-caption"><strong>Figure 1.</strong> Example of the selection dialog that appears
178when more than one app can handle an intent.</p>
179</div>
180
181<p>Once you have created your {@link android.content.Intent} and set the extra info, call {@link
182android.app.Activity#startActivity startActivity()} to send it to the system. If the system
183identifies more than one activity that can handle the intent, it displays a dialog for the user to
184select which app to use, as shown in figure 1. If there is only one activity that handles the
185intent, the system immediately starts it.</p>
186
187<pre>
188startActivity(intent);
189</pre>
190
191<p>Here's a complete example that shows how to create an intent to view a map, verify that an
192app exists to handle the intent, then start it:</p>
193
194<pre>
195// Build the intent
196Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
197Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
198
199// Verify it resolves
200PackageManager packageManager = {@link android.content.Context#getPackageManager()};
201List&lt;ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
202boolean isIntentSafe = activities.size() > 0;
Joe Malin45edbb72013-08-26 14:55:54 -0700203
Scott Mainba8f4352012-03-29 23:03:13 -0700204// Start an activity if it's safe
205if (isIntentSafe) {
206 startActivity(mapIntent);
207}
208</pre>
209
210
211
Scott Main1cf92552012-04-20 15:46:49 -0700212<h2 id="AppChooser">Show an App Chooser</h2>
213
Scott Main159a5ff2013-07-30 12:06:38 -0700214<div class="figure" style="width:200px;margin-top:-10px">
Scott Main1cf92552012-04-20 15:46:49 -0700215 <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="" />
Scott Main159a5ff2013-07-30 12:06:38 -0700216 <p class="img-caption"><strong>Figure 2.</strong> A chooser dialog.</p>
Scott Main1cf92552012-04-20 15:46:49 -0700217</div>
218
219<p>Notice that when you start an activity by passing your {@link android.content.Intent} to {@link
220android.app.Activity#startActivity startActivity()} and there is more than one app that responds to
221the intent, the user can select which app to use by default (by selecting a checkbox at the bottom
222of the dialog; see figure 1). This is nice when performing an action for which the user
223generally wants to use the same app every time, such as when opening a web page (users
Scott Main159a5ff2013-07-30 12:06:38 -0700224likely use just one web browser) or taking a photo (users likely prefer one camera).</p>
225
226<p>However, if the action to be performed could be handled by multiple apps and the user might
Scott Main1cf92552012-04-20 15:46:49 -0700227prefer a different app each time&mdash;such as a "share" action, for which users might have several
Scott Main159a5ff2013-07-30 12:06:38 -0700228apps through which they might share an item&mdash;you should explicitly show a chooser dialog
229as shown in figure 2. The chooser dialog
230forces the user to select which app to use for the action every time (the user cannot select a
Scott Main1cf92552012-04-20 15:46:49 -0700231default app for the action).</p>
232
233<p>To show the chooser, create an {@link android.content.Intent} using {@link
234android.content.Intent#createChooser createChooser()} and pass it to {@link
235android.app.Activity#startActivity startActivity()}. For example:</p>
236
237<pre>
238Intent intent = new Intent(Intent.ACTION_SEND);
239...
240
Scott Main159a5ff2013-07-30 12:06:38 -0700241// Always use string resources for UI text.
242// This says something like "Share this photo with"
Scott Maind0413012013-07-19 19:04:45 -0700243String title = getResources().getString(R.string.chooser_title);
Scott Main1cf92552012-04-20 15:46:49 -0700244// Create and start the chooser
245Intent chooser = Intent.createChooser(intent, title);
246startActivity(chooser);
247</pre>
248
249<p>This displays a dialog with a list of apps that respond to the intent passed to the {@link
250android.content.Intent#createChooser createChooser()} method and uses the supplied text as the
251dialog title.</p>
252
253
Scott Mainba8f4352012-03-29 23:03:13 -0700254