Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 1 | page.title=Sending the User to Another App |
| 2 | parent.title=Interacting with Other Apps |
| 3 | parent.link=index.html |
| 4 | |
| 5 | trainingnavtop=true |
| 6 | next.title=Getting a Result from an Activity |
| 7 | next.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 Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 20 | <li><a href="#AppChooser">Show an App Chooser</a></li> |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 21 | </ol> |
| 22 | |
| 23 | <h2>You should also read</h2> |
| 24 | <ul> |
Joe Malin | 45edbb7 | 2013-08-26 14:55:54 -0700 | [diff] [blame] | 25 | <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li> |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 26 | </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 |
| 32 | based on an "action" it would like to perform. For example, if |
| 33 | your app has the address of a business that you'd like to show on a map, you don't have to build |
Scott Main | cb0b2df | 2012-08-09 11:49:50 -0700 | [diff] [blame] | 34 | an activity in your app that shows a map. Instead, you can create a request to view the address |
| 35 | using an {@link android.content.Intent}. The Android system then starts an app that's able to show |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 36 | the address on a map.</p> |
| 37 | |
Scott Main | cb0b2df | 2012-08-09 11:49:50 -0700 | [diff] [blame] | 38 | <p>As explained in the first class, <a href="{@docRoot}training/basics/firstapp/index.html">Building |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 39 | Your First App</a>, you must use intents to navigate between activities in your own app. You |
| 40 | generally do so with an <em>explicit intent</em>, which defines the exact class name of the |
| 41 | component you want to start. However, when you want to have a separate app perform an action, such |
| 42 | as "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 |
| 45 | to 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 |
| 52 | action 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 |
| 54 | with the action, such as the address you want to view, or the email message you want to send. |
| 55 | Depending on the intent you want to create, the data might be a {@link android.net.Uri}, |
| 56 | one 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 |
| 59 | android.content.Intent#Intent(String,Uri) Intent()} constructor you can use define the action and |
| 60 | data.</p> |
| 61 | |
| 62 | <p>For example, here's how to create an intent to initiate a phone call using the {@link |
| 63 | android.net.Uri} data to specify the telephone number:</p> |
| 64 | |
| 65 | <pre> |
| 66 | Uri number = Uri.parse("tel:5551234"); |
| 67 | Intent 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 |
| 71 | startActivity()}, 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 |
| 74 | pairs:</p> |
| 75 | |
| 76 | <ul> |
| 77 | <li>View a map: |
| 78 | <pre> |
| 79 | // Map point based on address |
| 80 | Uri 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 |
| 83 | Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); |
| 84 | </pre> |
| 85 | </li> |
| 86 | <li>View a web page: |
| 87 | <pre> |
| 88 | Uri webpage = Uri.parse("http://www.android.com"); |
| 89 | Intent 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, |
| 95 | such as a string. You can add one or more pieces of extra data using the various {@link |
| 96 | android.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 |
| 100 | intent, you should usually use {@link android.content.Intent#setType setType()} to specify the type |
| 101 | of data associated with the intent. Setting the MIME type further specifies which kinds of |
| 102 | activities 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> |
| 109 | Intent emailIntent = new Intent(Intent.ACTION_SEND); |
| 110 | // The intent does not have a URI, so declare the "text/plain" MIME type |
| 111 | emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); |
| 112 | emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients |
| 113 | emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject"); |
| 114 | emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text"); |
Scott Main | fd51698 | 2012-07-03 16:25:52 -0700 | [diff] [blame] | 115 | emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")); |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 116 | // You can also attach multiple items by passing an ArrayList of Uris |
| 117 | </pre> |
| 118 | </li> |
| 119 | <li>Create a calendar event: |
| 120 | <pre> |
| 121 | Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); |
| 122 | Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30); |
| 123 | Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30); |
| 124 | calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); |
| 125 | calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); |
| 126 | calendarIntent.putExtra(Events.TITLE, "Ninja class"); |
| 127 | calendarIntent.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 |
| 130 | level 14 and higher.</p> |
| 131 | </li> |
| 132 | </ul> |
| 133 | |
| 134 | <p class="note"><strong>Note:</strong> It's important that you define your {@link |
| 135 | android.content.Intent} to be as specific as possible. For example, if you want to display an image |
| 136 | using 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 |
| 138 | triggered 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 |
| 145 | built-in apps (such as the Phone, Email, or Calendar app), you should always include a |
| 146 | verification step before invoking an intent.</p> |
| 147 | |
| 148 | <p class="caution"><strong>Caution:</strong> If you invoke an intent and there is no app |
| 149 | available 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 |
| 152 | android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()} to get a list |
| 153 | of activities capable of handling your {@link android.content.Intent}. If the returned {@link |
| 154 | java.util.List} is not empty, you can safely use the intent. For example:</p> |
| 155 | |
| 156 | <pre> |
| 157 | PackageManager packageManager = {@link android.content.Context#getPackageManager()}; |
| 158 | List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); |
| 159 | boolean 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 |
| 163 | the 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 |
| 166 | starts in case you need to disable the feature that uses the intent before the user attempts to use |
| 167 | it. If you know of a specific app that can handle the intent, you can also provide a link for the |
| 168 | user to download the app (see how to <a |
Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 169 | href="{@docRoot}distribute/googleplay/promote/linking.html">link to your product on Google |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 170 | Play</a>).</p> |
| 171 | |
| 172 | |
| 173 | <h2 id="StartActivity">Start an Activity with the Intent</h2> |
| 174 | |
Scott Main | 159a5ff | 2013-07-30 12:06:38 -0700 | [diff] [blame] | 175 | <div class="figure" style="width:200px;margin-top:-10px"> |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 176 | <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 |
| 178 | when 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 |
| 182 | android.app.Activity#startActivity startActivity()} to send it to the system. If the system |
| 183 | identifies more than one activity that can handle the intent, it displays a dialog for the user to |
| 184 | select which app to use, as shown in figure 1. If there is only one activity that handles the |
| 185 | intent, the system immediately starts it.</p> |
| 186 | |
| 187 | <pre> |
| 188 | startActivity(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 |
| 192 | app exists to handle the intent, then start it:</p> |
| 193 | |
| 194 | <pre> |
| 195 | // Build the intent |
| 196 | Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); |
| 197 | Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); |
| 198 | |
| 199 | // Verify it resolves |
| 200 | PackageManager packageManager = {@link android.content.Context#getPackageManager()}; |
| 201 | List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0); |
| 202 | boolean isIntentSafe = activities.size() > 0; |
Joe Malin | 45edbb7 | 2013-08-26 14:55:54 -0700 | [diff] [blame] | 203 | |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 204 | // Start an activity if it's safe |
| 205 | if (isIntentSafe) { |
| 206 | startActivity(mapIntent); |
| 207 | } |
| 208 | </pre> |
| 209 | |
| 210 | |
| 211 | |
Scott Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 212 | <h2 id="AppChooser">Show an App Chooser</h2> |
| 213 | |
Scott Main | 159a5ff | 2013-07-30 12:06:38 -0700 | [diff] [blame] | 214 | <div class="figure" style="width:200px;margin-top:-10px"> |
Scott Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 215 | <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="" /> |
Scott Main | 159a5ff | 2013-07-30 12:06:38 -0700 | [diff] [blame] | 216 | <p class="img-caption"><strong>Figure 2.</strong> A chooser dialog.</p> |
Scott Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 217 | </div> |
| 218 | |
| 219 | <p>Notice that when you start an activity by passing your {@link android.content.Intent} to {@link |
| 220 | android.app.Activity#startActivity startActivity()} and there is more than one app that responds to |
| 221 | the intent, the user can select which app to use by default (by selecting a checkbox at the bottom |
| 222 | of the dialog; see figure 1). This is nice when performing an action for which the user |
| 223 | generally wants to use the same app every time, such as when opening a web page (users |
Scott Main | 159a5ff | 2013-07-30 12:06:38 -0700 | [diff] [blame] | 224 | likely 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 Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 227 | prefer a different app each time—such as a "share" action, for which users might have several |
Scott Main | 159a5ff | 2013-07-30 12:06:38 -0700 | [diff] [blame] | 228 | apps through which they might share an item—you should explicitly show a chooser dialog |
| 229 | as shown in figure 2. The chooser dialog |
| 230 | forces the user to select which app to use for the action every time (the user cannot select a |
Scott Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 231 | default app for the action).</p> |
| 232 | |
| 233 | <p>To show the chooser, create an {@link android.content.Intent} using {@link |
| 234 | android.content.Intent#createChooser createChooser()} and pass it to {@link |
| 235 | android.app.Activity#startActivity startActivity()}. For example:</p> |
| 236 | |
| 237 | <pre> |
| 238 | Intent intent = new Intent(Intent.ACTION_SEND); |
| 239 | ... |
| 240 | |
Scott Main | 159a5ff | 2013-07-30 12:06:38 -0700 | [diff] [blame] | 241 | // Always use string resources for UI text. |
| 242 | // This says something like "Share this photo with" |
Scott Main | d041301 | 2013-07-19 19:04:45 -0700 | [diff] [blame] | 243 | String title = getResources().getString(R.string.chooser_title); |
Scott Main | 1cf9255 | 2012-04-20 15:46:49 -0700 | [diff] [blame] | 244 | // Create and start the chooser |
| 245 | Intent chooser = Intent.createChooser(intent, title); |
| 246 | startActivity(chooser); |
| 247 | </pre> |
| 248 | |
| 249 | <p>This displays a dialog with a list of apps that respond to the intent passed to the {@link |
| 250 | android.content.Intent#createChooser createChooser()} method and uses the supplied text as the |
| 251 | dialog title.</p> |
| 252 | |
| 253 | |
Scott Main | ba8f435 | 2012-03-29 23:03:13 -0700 | [diff] [blame] | 254 | |