Android Intents and Filters
An Android Intent is an abstract description of an operation to be performed. It can be used to start an activity via startActivity
, send a broadcast via broadcastIntent
to any interested broadcast receiver components, or communicate with a background service via startService(Intent)
or bindService(Intent, ServiceConnection, int)
.
The Intent itself (an Intent object) is a passive data structure holding an abstract description of an operation to be performed.
For example, if you have an activity that needs to open an email client and send an email using an Android device. For this purpose, your activity sends an ACTION_SEND
intent with a suitable selector to the Android intent handler. The specified selector provides a suitable interface for the user to decide how to send his email data.
Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));
email.putExtra(Intent.EXTRA_EMAIL, recipients);
email.putExtra(Intent.EXTRA_SUBJECT, subject.getText().toString());
email.putExtra(Intent.EXTRA_TEXT, body.getText().toString());
startActivity(Intent.createChooser(email, "Choose an email client from..."));
The above syntax calls the startActivity
method to launch the email activity, and the code execution result looks like this:
For example, if you have an activity that needs to open a URL in a browser on an Android device. For this purpose, your activity sends an ACTION_WEB_SEARCH
intent to the Android intent handler to open the given URL in the browser. The intent handler parses through a series of activities and selects the one that best fits your intent, in this case, the web browser activity. The intent handler passes your web address to the web browser and launches the web browser activity.
String q = "https://www.tutorialpro.org";
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, q);
startActivity(intent);
The above example will search for "www.tutorialpro.org" on the Android search engine and display the results on an activity.
Each component—activity, service, broadcast receiver—has a separate mechanism to pass intents.
Number | Method and Description |
---|---|
1 | Context.startActivity() : The intent is passed to this method to start a new activity or make an existing activity do something new. |
2 | Context.startService() : The intent is passed to this method to initialize a service or provide new information to a persistent service. |
3 | Context.sendBroadcast() : The intent is passed to this method, and the message is delivered to all interested broadcast receivers. |
Intent Object
The Intent object is a bundle of information that is used by the component that receives the intent, like the Android system.
The Intent object includes the following components, depending on what is to be communicated or performed.
Action
This is a mandatory part of the Intent object, represented as a string. In broadcast intents, the action occurs and is reported. The action largely determines how the rest of the intent is organized. The Intent class defines a number of action constants for different intents. Here is a list of Android Intent Standard Actions.
The action in the Intent object can be set via the setAction()
method and read via the getAction()
method.
Data
Add data specifications to the intent filter. This specification can be just a data type (like the MIME type attribute), a URI, or include both the data type and URI. The URI is specified by separate attributes for different parts.
These attributes specifying the URL format are optional but also interdependent:
- If the intent filter does not specify a scheme, all other URI attributes are ignored.
- If the filter does not specify a host, the port attribute and all path attributes are ignored.
The setData()
method specifies data only as a URI, setType()
specifies it only as a MIME type, and setDataAndType()
specifies it as both a URI and MIME type. The URI is read via getData()
, and the type is read via getType()
.
Here are some examples of action/data pairs:
Number | Action/Data Pair and Description |
---|---|
1 | ACTION_VIEW content://contacts/people/1 : Displays information for the user with ID 1. |
2 | ACTION_DIAL content://contacts/people/1 : Displays the dialer with the data of user 1 filled in. |
3 | ACTION_VIEW tel:123 : Displays the dialer with the given number filled in. |
4 | ACTION_DIAL tel:123 : Displays the dialer with the given number filled in. |
5 | ACTION_EDIT content://contacts/people/1 : Edits information for the user with ID 1. |
6 | ACTION_VIEW content://contacts/people/ : Displays a list of users for viewing. |
7 | ACTION_SET_WALLPAPER : Displays wallpaper settings. |
8 | ACTION_SYNC : Synchronizes data, default value: android.intent.action.SYNC . |
9 | ACTION_SYSTEM_TUTORIAL : Launches the platform-defined tutorial (default tutorial or startup tutorial). |
10 | ACTION_TIMEZONE_CHANGED : Notifies when the time zone has changed. |
11 | ACTION_UNINSTALL_PACKAGE : Runs the default uninstaller. |
Category
The category is an optional part of the intent, a string containing additional information about the kind of component that should handle the intent. addCategory()
adds a category to the Intent object, removeCategory()
removes a previously added category, and getCategories()
gets all the categories set on the Intent object. Here is a list of Android Intent Standard Categories.
See the intent filter section below to understand how we use categories to select the appropriate activity for a corresponding intent.
Extra Data
This is additional information that is passed to the component that needs to handle the intent, described as key-value pairs. putExtras()
sets them, and getExtras()
reads them. Here is a list of Android Intent Standard Extra Data.
Flags
These flags are optional parts of the intent, indicating how the Android system should launch an activity and how to treat it after it is launched, among other things.
Number | Flag and Description |
---|---|
1 | FLAG_ACTIVITY_CLEAR_TASK : If set in an intent and passed to Context.startActivity , this flag will cause any existing task associated with the activity to be cleared before the activity is started. The activity will become the root of a new task, and all old activities are finished. This flag can be used in conjunction with FLAG_ACTIVITY_NEW_TASK . |
2 | FLAG_ACTIVITY_CLEAR_TOP : If set, the activity will be started in the current task. This does not start a new activity instance; instead, all activities above it are closed, and this intent is delivered as a new intent to the existing (now on top) activity. |
3 | FLAG_ACTIVITY_NEW_TASK : This flag is generally used to achieve "launcher" style behavior: to provide a data structure that the user can perform a task on and launch a fully independent activity. |
Component Name
The component name object is an optional field representing an activity, service, or broadcast receiver class. If set, the intent object is delivered to an instance of the designated class; otherwise, Android uses other information in the intent to locate a suitable target. The component name is set via setComponent()
, setClass()
, or setClassName()
, and retrieved via getComponent()
.
Types of Intents
Android supports two types of intents.
Explicit Intents
Explicit intents are used to connect the internal world of an application, assuming you need to connect one activity to another, we can use explicit intent, the figure below shows connecting the first activity to the second activity by clicking a button.
These intents specify the target component by name and are generally used for internal messages within an application—for example, an activity starting a subordinate activity or a sibling activity. For example:
// Explicit intent by specifying its class name
Intent i = new Intent(FirstActivity.this, SecondActivity.class);
// Start the target activity
startActivity(i);
Implicit Intents
These intents do not name a target, and the component name field is left blank. Implicit intents are often used to activate components in other applications. For example:
Intent read1 = new Intent();
read1.setAction(android.content.Intent.ACTION_VIEW);
read1.setData(ContactsContract.Contacts.CONTENT_URI);
startActivity(read1);
The above code will result in the following:
The target component that receives the intent can use the getExtras()
method to retrieve the additional data sent by the source component. For example:
// Get the bundle object at appropriate location in your code
Bundle extras = getIntent().getExtras();
// Unpack the data using keys
String value1 = extras.getString("Key1");
String value2 = extras.getString("Key2");
Example
The following example demonstrates using Android intents to start various built-in Android application functionalities.
Step | Description |
---|---|
1 | Create an Android application using Android Studio IDE, named IntentFilter , with the package com.tutorialpro.intentfilter . Ensure the target SDK and compile SDK are the latest versions of Android. |
2 | Modify the src/com.tutorialpro.intentfilter/MainActivity.java file, adding code to define two listeners for the two buttons "Start Browser" and "Start Phone". |
3 | Modify the res/layout/activity_main.xml layout file, adding three buttons within a linear layout. |
4 | Start the Android emulator to run the application and verify the results of the changes made. |
Here is the content of the src/com.tutorialpro.intentfilter/MainActivity.java
file:
package com.tutorialpro.intentfilter;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void startBrowser(View view) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
startActivity(i);
}
public void startPhone(View view) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("tel:9510300000"));
startActivity(i);
}
}
import android.widget.Button;
public class MainActivity extends ActionBarActivity {
Button b1, b2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1 = (Button) findViewById(R.id.button);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("https://www.tutorialpro.org"));
startActivity(i);
}
});
b2 = (Button) findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("tel:9510300000"));
startActivity(i);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Content of the res/layout/activity_main.xml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Intent Example"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textSize="30dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="www.tutorialpro.org"
android:textColor="#ff87ff09"
android:textSize="30dp"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageButton"
android:src="@drawable/ic_launcher"
android:layout_below="@+id/textView2"
android:layout_centerHorizontal="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:layout_below="@+id/imageButton"
android:layout_alignRight="@+id/imageButton"
android:layout_alignEnd="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Launch Browser"
android:id="@+id/button"
android:layout_alignTop="@+id/editText"
android:layout_alignRight="@+id/textView1"
android:layout_alignEnd="@+id/textView1"
android:layout_alignLeft="@+id/imageButton"
android:layout_alignStart="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Launch Phone"
android:id="@+id/button2"
android:layout_below="@+id/button"
android:layout_alignLeft="@+id/button"
android:layout_alignStart="@+id/button"
android:layout_alignRight="@+id/textView2"
android:layout_alignEnd="@+id/textView2" />
</RelativeLayout>
Content of the res/values/strings.xml file, defining two new constants:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Intent Filter</string>
<string name="action_settings">Settings</string>
</resources>
Content of the default AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutorialpro.intentfilter"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Base.Theme.AppCompat" >
<activity
android:name="com.tutorialpro.intentfilter.MainActivity"
android:label="@string/app_name" >
<intent-filter>
Let's run the modified Intent filter application. I assume you have already created an AVD while setting up the environment. Open your activity file in the project and click on the toolbar.
Now click the "Launch Browser" button, which will start a browser based on the configuration and display https://www.tutorialpro.org as follows:
Similarly, you can click the "Launch Phone" button to open the phone interface, which will allow you to dial the given phone number.
Intent Filters
You have seen how to use intents to call another activity. The Android operating system uses filters to specify a set of activities, services, and broadcast receivers that can handle an intent, based on the action, category, and data pattern specified in the intent. The <intent-filter> element is used in the manifest file to list the actions, categories, and data types for activities, services, and broadcast receivers.
The following example shows a part of the AndroidManifest.xml file, specifying that the activity com.tutorialpro.intentfilter.CustomActivity can be invoked by setting the action, category, and data:
<activity android:name=".CustomActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="com.example.MyApplication.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
When an activity is defined by the above filter, other activities can invoke this activity using android.intent.action.VIEW, the com.tutorialpro.intentfilter.LAUNCH action, and providing the android.intent.category.DEFAULT category.
There are cases where an intent will be passed to multiple activities or services through filters, and the user will be asked which component to launch. If no target component is found, an exception will occur.
Before invoking an activity, Android performs a series of checks:
- The filter <intent-filter> must list one or more actions and cannot be empty; the filter must contain at least one action.
- The filter <intent-filter> may list zero, one, or more categories. If no categories are mentioned, Android passes this test. If multiple categories are mentioned, the intent passes the type test if every intent object's category matches one in the filter.
Example
The following example is a modification of the above example. Here, we will see how Android resolves conflicts if an intent calls two defined activities; how to use filters to call a custom activity; and if no suitable activity is defined for the intent, an exception will occur.
Step | Description |
---|---|
1 | Create an Android application using Android Studio IDE and name it Intent filter, with the package name com.tutorialpro.intentfilter. Ensure that the target SDK and compile SDK are the latest versions of Android. |
2 | Modify the src/com.tutorialpro.intentfilter/MainActivity.java file, adding code to define three listeners for the three buttons defined in the layout file. |
3 | Add the src/com.tutorialpro.intentfilter/CustomActivity.java file to contain an activity that can be invoked by different intents. |
4 | Modify the res/layout/activity_main.xml file to add three buttons in a linear layout. |
5 | Add the res/layout/custom_view.xml layout file, adding a simple TextView to display data passed through the intent. |
6 | Modify the AndroidManifest.xml file, adding <intent-filter> definitions to invoke the custom activity. |
7 | Start the Android emulator to run the application and verify the results of the changes made. |
Here is the content of src/com.tutorialpro.intentfilter/MainActivity.java:
package com.tutorialpro.intentfilter;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends ActionBarActivity {
Button b1,b2,b3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1=(Button)findViewById(R.id.button);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW,Uri.parse("https://www.tutorialpro.org"));
startActivity(i);
}
});
b2=(Button)findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent("com.tutorialpro.intentfilter.LAUNCH",Uri.parse("https://www.tutorialpro.org"));
startActivity(i);
}
});
b3=(Button)findViewById(R.id.button3);
b3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent("com.tutorialpro.intentfilter.LAUNCH",Uri.parse("https://www.tutorialpro.org"));
startActivity(i);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Here is the content of src/com.tutorialpro.intentfilter/CustomActivity.java:
package com.tutorialpro.intentfilter;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;
public class CustomActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_view);
TextView label = (TextView) findViewById(R.id.show_data);
Uri url = getIntent().getData();
label.setText(url.toString());
}
}
Below is the content of the res/layout/activity_main.xml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Intent Example"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textSize="30dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="www.tutorialpro.org"
android:textColor="#ff87ff09"
android:textSize="30dp"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageButton"
android:src="@drawable/ic_launcher"
android:layout_below="@+id/textView2"
android:layout_centerHorizontal="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:layout_below="@+id/imageButton"
android:layout_alignRight="@+id/imageButton"
android:layout_alignEnd="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Browser with View Action"
android:id="@+id/button"
android:layout_alignTop="@+id/editText"
android:layout_alignRight="@+id/textView1"
android:layout_alignEnd="@+id/textView1"
android:layout_alignLeft="@+id/imageButton"
android:layout_alignStart="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Browser with Launch Action"
android:id="@+id/button2"
android:layout_below="@+id/button"
android:layout_alignLeft="@+id/button"
android:layout_alignStart="@+id/button"
android:layout_alignRight="@+id/textView2"
android:layout_alignEnd="@+id/textView2" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Exception Case"
android:id="@+id/button3"
android:layout_below="@+id/button2"
android:layout_alignLeft="@+id/button2"
android:layout_alignStart="@+id/button2"
android:layout_alignRight="@+id/textView2"
android:layout_alignEnd="@+id/textView2" />
</RelativeLayout>
Below is the content of the res/layout/custom_view.xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/show_data"
android:layout_width="fill_parent"
android:layout_height="400dp"/>
</LinearLayout>
Below is the content of the res/values/strings.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">My Application</string>
<string name="action_settings">Settings</string>
</resources>
Below is the content of the AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutorialpro.intentfilter"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Base.Theme.AppCompat" >
<activity
android:name="com.tutorialpro.intentfilter.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tutorialpro.intentfilter.CustomActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="com.tutorialpro.intentfilter.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
</application>
</manifest>
Let's run the newly modified Intent filter application. I assume you have already created an AVD when setting up the environment. Open the activity file in your project and click on the toolbar. Click on the first button "Launch Browser with View Action". Here, we define our custom activity to include "android.intent.action.VIEW", and the Android system has already defined a default activity to handle the VIEW action to launch the web browser. Therefore, Android displays the following options to select the activity you want to launch:
If you choose the browser, Android will launch the web browser and open the www.tutorialpro.org website. If you select the IntentDemo option, Android will launch the CustomActivity, which does nothing but capture and display the passed data in a TextView.
Now, go back using the back button and click on the "Launch Browser with Launch Action" button. Here, Android uses an application filter to select the defined activity and simply launches the custom activity.
Use the back button again to return and click on the "Exception Condition" button. Here, Android attempts to find a valid filter given by the intent, but does not find a defined valid activity. Since we used https instead of http for the data and provided the correct action, Android generates an exception as follows: