am 71e8f4c1: Merge "docs: add 101 class about intents, Interacting with Other Apps" into ics-mr1

* commit '71e8f4c152a84ff420dcf834bc0acd73644f0cb0':
  docs: add 101 class about intents, Interacting with Other Apps
This commit is contained in:
Scott Main
2012-04-11 11:35:52 -07:00
committed by Android Git Automerger
5 changed files with 701 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,244 @@
page.title=Allowing Other Apps to Start Your Activity
parent.title=Interacting with Other Apps
parent.link=index.html
trainingnavtop=true
previous.title=Getting a Result from an Activity
previous.link=result.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#AddIntentFilter">Add an Intent Filter</a></li>
<li><a href="#HandleIntent">Handle the Intent in Your Activity</a></li>
<li><a href="#ReturnResult">Return a Result</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li>
</ul>
</div>
</div>
<p>The previous two lessons focused on one side of the story: starting another app's activity from
your app. But if your app can perform an action that might be useful to another app,
your app should be prepared to respond to action requests from other apps. For instance, if you
build a social app that can share messages or photos with the user's friends, it's in your best
interest to support the {@link android.content.Intent#ACTION_SEND} intent so users can initiate a
"share" action from another app and launch your app to perform the action.</p>
<p>To allow other apps to start your activity, you need to add an <a
href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>
element in your manifest file for the corresponding <a
href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a> element.</p>
<p>When your app is installed on a device, the system identifies your intent
filters and adds the information to an internal catalog of intents supported by all installed apps.
When an app calls {@link android.app.Activity#startActivity
startActivity()} or {@link android.app.Activity#startActivityForResult startActivityForResult()},
with an implicit intent, the system finds which activity (or activities) can respond to the
intent.</p>
<h2 id="AddIntentFilter">Add an Intent Filter</h2>
<p>In order to properly define which intents your activity can handle, each intent filter you add
should be as specific as possible in terms of the type of action and data the activity
accepts.</p>
<p>The system may send a given {@link android.content.Intent} to an activity if that activity has
an intent filter fulfills the following criteria of the {@link android.content.Intent} object:</p>
<dl>
<dt>Action</dt>
<dd>A string naming the action to perform. Usually one of the platform-defined values such
as {@link android.content.Intent#ACTION_SEND} or {@link android.content.Intent#ACTION_VIEW}.
<p>Specify this in your intent filter with the <a
href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a> element.
The value you specify in this element must be the full string name for the action, instead of the
API constant (see the examples below).</p></dd>
<dt>Data</dt>
<dd>A description of the data associated with the intent.
<p>Specify this in your intent filter with the <a
href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element. Using one
or more attributes in this element, you can specify just the MIME type, just a URI prefix,
just a URI scheme, or a combination of these and others that indicate the data type
accepted.</p>
<p class="note"><strong>Note:</strong> If you don't need to declare specifics about the data
{@link android.net.Uri} (such as when your activity handles to other kind of "extra" data, instead
of a URI), you should specify only the {@code android:mimeType} attribute to declare the type of
data your activity handles, such as {@code text/plain} or {@code image/jpeg}.</p>
</dd>
<dt>Category</dt>
<dd>Provides an additional way to characterize the activity handling the intent, usually related
to the user gesture or location from which it's started. There are several different categories
supported by the system, but most are rarely used. However, all implicit intents are defined with
{@link android.content.Intent#CATEGORY_DEFAULT} by default.
<p>Specify this in your intent filter with the <a
href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a>
element.</p></dd>
</dl>
<p>In your intent filter, you can declare which criteria your activity accepts
by declaring each of them with corresponding XML elements nested in the <a
href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>
element.</p>
<p>For example, here's an activity with an intent filter that handles the {@link
android.content.Intent#ACTION_SEND} intent when the data type is either text or an image:</p>
<pre>
&lt;activity android:name="ShareActivity">
&lt;intent-filter>
&lt;action android:name="android.intent.action.SEND"/>
&lt;category android:name="android.intent.category.DEFAULT"/>
&lt;data android:mimeType="text/plain"/>
&lt;data android:mimeType="image/*"/>
&lt;/intent-filter>
&lt;/activity>
</pre>
<p>Each incoming intent specifies only one action and one data type, but it's OK to declare multiple
instances of the <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
&lt;action>}</a>, <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
&lt;category>}</a>, and <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
&lt;data>}</a> elements in each
<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
&lt;intent-filter>}</a>.</p>
<p>If any two pairs of action and data are mutually exclusive in
their behaviors, you should create separate intent filters to specify which actions are acceptable
when paired with which data types.</p>
<p>For example, suppose your activity handles both text and images for both the {@link
android.content.Intent#ACTION_SEND} and {@link
android.content.Intent#ACTION_SENDTO} intents. In this case, you must define two separate
intent filters for the two actions because a {@link
android.content.Intent#ACTION_SENDTO} intent must use the data {@link android.net.Uri} to specify
the recipient's address using the {@code send} or {@code sendto} URI scheme. For example:</p>
<pre>
&lt;activity android:name="ShareActivity">
&lt;!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
&lt;intent-filter>
&lt;action android:name="android.intent.action.SENDTO"/>
&lt;category android:name="android.intent.category.DEFAULT"/>
&lt;data android:scheme="sms" />
&lt;data android:scheme="smsto" />
&lt;/intent-filter>
&lt;!-- filter for sending text or images; accepts SEND action and text or image data -->
&lt;intent-filter>
&lt;action android:name="android.intent.action.SEND"/>
&lt;category android:name="android.intent.category.DEFAULT"/>
&lt;data android:mimeType="image/*"/>
&lt;data android:mimeType="text/plain"/>
&lt;/intent-filter>
&lt;/activity>
</pre>
<p class="note"><strong>Note:</strong> In order to receive implicit intents, you must include the
{@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods {@link
android.app.Activity#startActivity startActivity()} and {@link
android.app.Activity#startActivityForResult startActivityForResult()} treat all intents as if they
contained the {@link android.content.Intent#CATEGORY_DEFAULT} category. If you do not declare it, no
implicit intents will resolve to your activity.</p>
<p>For more information about sending and receiving {@link android.content.Intent#ACTION_SEND}
intents that perform social sharing behaviors, see the lesson about <a
href="{@docRoot}training/sharing/receive.html">Receiving Content from Other Apps</a>.</p>
<h2 id="HandleIntent">Handle the Intent in Your Activity</h2>
<p>In order to decide what action to take in your activity, you can read the {@link
android.content.Intent} that was used to start it.</p>
<p>As your activity starts, call {@link android.app.Activity#getIntent()} to retrieve the
{@link android.content.Intent} that started the activity. You can do so at any time during the
lifecycle of the activity, but you should generally do so during early callbacks such as
{@link android.app.Activity#onCreate onCreate()} or {@link android.app.Activity#onStart()}.</p>
<p>For example:</p>
<pre>
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get the intent that started this activity
Intent intent = getIntent();
Uri data = intent.getData();
// Figure out what to do based on the intent type
if (intent.getType().indexOf("image/") != -1) {
// Handle intents with image data ...
} else if (intent.getType().equals("text/plain")) {
// Handle intents with text ...
}
}
</pre>
<h2 id="ReturnResult">Return a Result</h2>
<p>If you want to return a result to the activity that invoked yours, simply call {@link
android.app.Activity#setResult(int,Intent) setResult()} to specify the result code and result {@link
android.content.Intent}. When your operation is done and the user should return to the original
activity, call {@link android.app.Activity#finish()} to close (and destroy) your activity. For
example:</p>
<pre>
// Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();
</pre>
<p>You must always specify a result code with the result. Generally, it's either {@link
android.app.Activity#RESULT_OK} or {@link android.app.Activity#RESULT_CANCELED}. You can then
provide additional data with an {@link android.content.Intent}, as necessary.</p>
<p class="note"><strong>Note:</strong> The result is set to {@link
android.app.Activity#RESULT_CANCELED} by default. So, if the user presses the <em>Back</em>
button before completing the action and before you set the result, the original activity receives
the "canceled" result.</p>
<p>If you simply need to return an integer that indicates one of several result options, you can set
the result code to any value higher than 0. If you use the result code to deliver an integer and you
have no need to include the {@link android.content.Intent}, you can call {@link
android.app.Activity#setResult(int) setResult()} and pass only a result code. For example:</p>
<pre>
setResult(RESULT_COLOR_RED);
finish();
</pre>
<p>In this case, there might be only a handful of possible results, so the result code is a locally
defined integer (greater than 0). This works well when you're returning a result to an activity
in your own app, because the activity that receives the result can reference the public
constant to determine the value of the result code.</p>
<p class="note"><strong>Note:</strong> There's no need to check whether your activity was started
with {@link
android.app.Activity#startActivity startActivity()} or {@link
android.app.Activity#startActivityForResult startActivityForResult()}. Simply call {@link
android.app.Activity#setResult(int,Intent) setResult()} if the intent that started your activity
might expect a result. If the originating activity had called {@link
android.app.Activity#startActivityForResult startActivityForResult()}, then the system delivers it
the result you supply to {@link android.app.Activity#setResult(int,Intent) setResult()}; otherwise,
the result is ignored.</p>

View File

@ -0,0 +1,64 @@
page.title=Interacting with Other Apps
trainingnavtop=true
startpage=true
next.title=Sending the User to Another App
next.link=sending.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>Dependencies and prerequisites</h2>
<ul>
<li>Basic understanding of the Activity lifecycle (see <a
href="{@docRoot}training/basics/activity-lifecycle/index.html">Managing the Activity
Lifecycle</a>)</li>
</ul>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li>
<li><a
href="http://android-developers.blogspot.com/2009/11/integrating-application-with-intents.html">
Integrating Application with Intents (blog post)</a></li>
<li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent
Filters</a></li>
</ul>
</div>
</div>
<p>An Android app typically has several <a
href="{@docRoot}guide/topics/fundamentals/activities.html">activities</a>. Each activity displays a
user interface that allows the user to perform a specific task (such as view a map or take a photo).
To take the user from one activity to another, your app must use an {@link
android.content.Intent} to define your app's "intent" to do something. When you pass an
{@link android.content.Intent} to the system with a method such as {@link
android.app.Activity#startActivity startActivity()}, the system uses the {@link
android.content.Intent} to identify and start the appropriate app component. Using intents even
allows your app to start an activity that is contained in a separate app.</p>
<p>An {@link android.content.Intent} can be <em>explicit</em> in order to start a specific component
(a specific {@link android.app.Activity} instance) or <em>implicit</em> in order to start any
component that can handle the intended action (such as "capture a photo").</p>
<p>This class shows you how to use an {@link android.content.Intent} to perform some basic
interactions with other apps, such as start another app, receive a result from that app, and
make your app able to respond to intents from other apps.</p>
<h2>Lessons</h2>
<dl>
<dt><b><a href="sending.html">Sending the User to Another App</a></b></dt>
<dd>Shows how you can create implicit intents to launch other apps that can perform an
action.</dd>
<dt><b><a href="result.html">Getting a Result from an Activity</a></b></dt>
<dd>Shows how to start another activity and receive a result from the activity.</dd>
<dt><b><a href="filters.html">Allowing Other Apps to Start Your Activity</a></b></dt>
<dd>Shows how to make activities in your app open for use by other apps by defining
intent filters that declare the implicit intents your app accepts.</dd>
</dl>

View File

@ -0,0 +1,182 @@
page.title=Getting a Result from an Activity
parent.title=Interacting with Other Apps
parent.link=index.html
trainingnavtop=true
previous.title=Sending the User to Another App
previous.link=sending.html
next.title=Allowing Other Apps to Start Your Activity
next.link=filters.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#StartActivity">Start the Activity</a></li>
<li><a href="#ReceiveResult">Receive the Result</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li>
</ul>
</div>
</div>
<p>Starting another activity doesn't have to be one-way. You can also start another activity and
receive a result back. To receive a result, call {@link android.app.Activity#startActivityForResult
startActivityForResult()} (instead of {@link android.app.Activity#startActivity
startActivity()}).</p>
<p>For example, your app can start a camera app and receive the captured photo as a result. Or, you
might start the People app in order for the user to select a
contact and you'll receive the contact details as a result.</p>
<p>Of course, the activity that responds must be designed to return a result. When it does, it
sends the result as another {@link android.content.Intent} object. Your activity receives it in
the {@link android.app.Activity#onActivityResult onActivityResult()} callback.</p>
<p class="note"><strong>Note:</strong> You can use explicit or implicit intents when you call
{@link android.app.Activity#startActivityForResult startActivityForResult()}. When starting one of
your own activities to receive a result, you should use an explicit intent to ensure that you
receive the expected result.</p>
<h2 id="StartActivity">Start the Activity</h2>
<p>There's nothing special about the {@link android.content.Intent} object you use when starting
an activity for a result, but you do need to pass an additional integer argument to the {@link
android.app.Activity#startActivityForResult startActivityForResult()} method.</p>
<p>The integer argument is a "request code" that identifies your request. When you receive the
result {@link android.content.Intent}, the callback provides the same request code so that your
app can properly identify the result and determine how to handle it.</p>
<p>For example, here's how to start an activity that allows the user to pick a contact:</p>
<pre>
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
</pre>
<h2 id="ReceiveResult">Receive the Result</h2>
<p>When the user is done with the subsequent activity and returns, the system calls your activity's
{@link android.app.Activity#onActivityResult onActivityResult()} method. This method includes three
arguments:</p>
<ul>
<li>The request code you passed to {@link
android.app.Activity#startActivityForResult startActivityForResult()}.</li>
<li>A result code specified by the second activity. This is either {@link
android.app.Activity#RESULT_OK} if the operation was successful or {@link
android.app.Activity#RESULT_CANCELED} if the user backed out or the operation failed for some
reason.</li>
<li>An {@link android.content.Intent} that carries the result data.</li>
</ul>
<p>For example, here's how you can handle the result for the "pick a contact" intent:</p>
<pre>
&#64;Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
// Do something with the contact here (bigger example below)
}
}
}
</pre>
<p>In this example, the result {@link android.content.Intent} returned by
Android's Contacts or People app provides a content {@link android.net.Uri} that identifies the
contact the user selected.</p>
<p>In order to successfully handle the result, you must understand what the format of the result
{@link android.content.Intent} will be. Doing so is easy when the activity returning a result is
one of your own activities. Apps included with the Android platform offer their own APIs that
you can count on for specific result data. For instance, the People app (Contacts app on some older
versions) always returns a result with the content URI that identifies the selected contact, and the
Camera app returns a {@link android.graphics.Bitmap} in the {@code "data"} extra (see the class
about <a href="{@docRoot}training/camera/index.html">Capturing Photos</a>).</p>
<h4>Bonus: Read the contact data</h4>
<p>The code above showing how to get a result from the People app doesn't go into
details about how to actually read the data from the result, because it requires more advanced
discussion about <a href="{@docRoot}guide/topics/providers/content-providers.html">content
providers</a>. However, if you're curious, here's some more code that shows how to query the
result data to get the phone number from the selected contact:</p>
<pre>
&#64;Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request it is that we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// Get the URI that points to the selected contact
Uri contactUri = data.getData();
// We only need the NUMBER column, because there will be only one row in the result
String[] projection = {Phone.NUMBER};
// Perform the query on the contact to get the NUMBER column
// We don't need a selection or sort order (there's only one result for the given URI)
// CAUTION: The query() method should be called from a separate thread to avoid blocking
// your app's UI thread. (For simplicity of the sample, this code doesn't do that.)
// Consider using {@link android.content.CursorLoader} to perform the query.
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst();
// Retrieve the phone number from the NUMBER column
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column);
// Do something with the phone number...
}
}
}
</pre>
<p class="note"><strong>Note:</strong> Before Android 2.3 (API level 9), performing a query
on the {@link android.provider.ContactsContract.Contacts Contacts Provider} (like the one shown
above) requires that your app declare the {@link
android.Manifest.permission#READ_CONTACTS} permission (see <a
href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>). However,
beginning with Android 2.3, the Contacts/People app grants your app a temporary
permission to read from the Contacts Provider when it returns you a result. The temporary permission
applies only to the specific contact requested, so you cannot query a contact other than the one
specified by the intent's {@link android.net.Uri}, unless you do declare the {@link
android.Manifest.permission#READ_CONTACTS} permission.</p>

View File

@ -0,0 +1,211 @@
page.title=Sending the User to Another App
parent.title=Interacting with Other Apps
parent.link=index.html
trainingnavtop=true
next.title=Getting a Result from an Activity
next.link=result.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#Build">Build an Implicit Intent</a></li>
<li><a href="#Verify">Verify There is an App to Receive the Intent</a></li>
<li><a href="#StartActivity">Start an Activity with the Intent</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li>
</ul>
</div>
</div>
<p>One of Android's most important features is an app's ability to send the user to another app
based on an "action" it would like to perform. For example, if
your app has the address of a business that you'd like to show on a map, you don't have to build
an activity in your app that shows a map. Instead, you can send a out a request to view the address
using an {@link android.content.Intent}. The Android system then starts an app that's able to view
the address on a map.</p>
<p>As shown in the first class, <a href="{@docRoot}training/basics/firstapp/index.html">Building
Your First App</a>, you must use intents to navigate between activities in your own app. You
generally do so with an <em>explicit intent</em>, which defines the exact class name of the
component you want to start. However, when you want to have a separate app perform an action, such
as "view a map," you must use an <em>implicit intent</em>.</p>
<p>This lesson shows you how to create an implicit intent for a particular action, and how to use it
to start an activity that performs the action in another app.</p>
<h2 id="Build">Build an Implicit Intent</h2>
<p>Implicit intents do not declare the class name of the component to start, but instead declare an
action to perform. The action specifies the thing you want to do, such as <em>view</em>,
<em>edit</em>, <em>send</em>, or <em>get</em> something. Intents often also include data associated
with the action, such as the address you want to view, or the email message you want to send.
Depending on the intent you want to create, the data might be a {@link android.net.Uri},
one of several other data types, or the intent might not need data at all.</p>
<p>If your data is a {@link android.net.Uri}, there's a simple {@link
android.content.Intent#Intent(String,Uri) Intent()} constructor you can use define the action and
data.</p>
<p>For example, here's how to create an intent to initiate a phone call using the {@link
android.net.Uri} data to specify the telephone number:</p>
<pre>
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
</pre>
<p>When your app invokes this intent by calling {@link android.app.Activity#startActivity
startActivity()}, the Phone app initiates a call to the given phone number.</p>
<p>Here are a couple other intents and their action and {@link android.net.Uri} data
pairs:</p>
<ul>
<li>View a map:
<pre>
// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
</pre>
</li>
<li>View a web page:
<pre>
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
</pre>
</li>
</ul>
<p>Other kinds of implicit intents require "extra" data that provide different data types,
such as a string. You can add one or more pieces of extra data using the various {@link
android.content.Intent#putExtra(String,String) putExtra()} methods.</p>
<p>By default, the system determines the appropriate MIME type required by an intent based on the
{@link android.net.Uri} data that's included. If you don't include a {@link android.net.Uri} in the
intent, you should usually use {@link android.content.Intent#setType setType()} to specify the type
of data associated with the intent. Setting the MIME type further specifies which kinds of
activities should receive the intent.</p>
<p>Here are some more intents that add extra data to specify the desired action:</p>
<ul>
<li>Send an email with an attachment:
<pre>
Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment");
// You can also attach multiple items by passing an ArrayList of Uris
</pre>
</li>
<li>Create a calendar event:
<pre>
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
</pre>
<p class="note"><strong>Note:</strong> This intent for a calendar event is supported only with API
level 14 and higher.</p>
</li>
</ul>
<p class="note"><strong>Note:</strong> It's important that you define your {@link
android.content.Intent} to be as specific as possible. For example, if you want to display an image
using the {@link android.content.Intent#ACTION_VIEW} intent, you should specify a MIME type of
{@code image/*}. This prevents apps that can "view" other types of data (like a map app) from being
triggered by the intent.</p>
<h2 id="Verify">Verify There is an App to Receive the Intent</h2>
<p>Although the Android platform guarantees that certain intents will resolve to one of the
built-in apps (such as the Phone, Email, or Calendar app), you should always include a
verification step before invoking an intent.</p>
<p class="caution"><strong>Caution:</strong> If you invoke an intent and there is no app
available on the device that can handle the intent, your app will crash.</p>
<p>To verify there is an activity available that can respond to the intent, call {@link
android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()} to get a list
of activities capable of handling your {@link android.content.Intent}. If the returned {@link
java.util.List} is not empty, you can safely use the intent. For example:</p>
<pre>
PackageManager packageManager = {@link android.content.Context#getPackageManager()};
List&lt;ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
</pre>
<p>If <code>isIntentSafe</code> is <code>true</code>, then at least one app will respond to
the intent. If it is <code>false</code>, then there aren't any apps to handle the intent.</p>
<p class="note"><strong>Note:</strong> You should perform this check when your activity first
starts in case you need to disable the feature that uses the intent before the user attempts to use
it. If you know of a specific app that can handle the intent, you can also provide a link for the
user to download the app (see how to <a
href="{@docRoot}guide/publishing/publishing.html#marketintent">link to an app on Google
Play</a>).</p>
<h2 id="StartActivity">Start an Activity with the Intent</h2>
<div class="figure" style="width:200px">
<img src="{@docRoot}images/training/basics/intents-choice.png" alt="" />
<p class="img-caption"><strong>Figure 1.</strong> Example of the selection dialog that appears
when more than one app can handle an intent.</p>
</div>
<p>Once you have created your {@link android.content.Intent} and set the extra info, call {@link
android.app.Activity#startActivity startActivity()} to send it to the system. If the system
identifies more than one activity that can handle the intent, it displays a dialog for the user to
select which app to use, as shown in figure 1. If there is only one activity that handles the
intent, the system immediately starts it.</p>
<pre>
startActivity(intent);
</pre>
<p>Here's a complete example that shows how to create an intent to view a map, verify that an
app exists to handle the intent, then start it:</p>
<pre>
// Build the intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// Verify it resolves
PackageManager packageManager = {@link android.content.Context#getPackageManager()};
List&lt;ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
// Start an activity if it's safe
if (isIntentSafe) {
startActivity(mapIntent);
}
</pre>