Android folds multiple ideas, (to name some: invoking other applications, invoking other components, events, actions, publish and subscribe), in to what is called an "Intent".

At the simplest level you can use an intent to start an application that you write. Imagine you write an application whose startign screen or activity is called MY_SCREEN. Then you can have other programs invoke that screen by calling this function:


public static invokeMyApplication(Activity parentActivity)
{
   String actionName= "com.your-company.your-app.intent.action.MY_SCREEN";
   Intent intent = new Intent(actionName);
   parentActivity.startActivity(intent);
}

The name of an action follows Java-style naming convention. For built in android actions such as Intent.ACTION_VIEW you would put android.intent.action.VIEW here. Or you can use the defined constant in your code: Intent.ACTION_VIEW. Custom actions should generally use a prefix matching the package name.

However the comes after your java package name is arbitrary but if you were to follow the android convention then it should ".intent.action.YOUR_ACTION_NAME".

To make this work your application have to announce in androidmanifest.xml that it can be invoked for this action. Here is an example


<activity android:name="MyApplication" android:label="@string/my_application_label">
   <intent-filter>
      <action android:name="com.your-company.your-app.intent.action.MY_SCREEN" />
   </intent-filter>
</activity>

Available Intents in Android

As Android comes with a predefined set of applications, it is reasonable to assume that there are some prefabricated applications out there that we can quickly invoke and test our understanding of intents. That is indeed the case. The following url


http://code.google.com/android/reference/available-intents.html

documents the available intents. These include

Here is some sample code that exercises each of these applications


public class IntentsUtils 
{
    public static void invokeWebBrowser(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_VIEW);
       intent.setData(Uri.parse("http://www.google.com"));
       activity.startActivity(intent);
    }
    public static void invokeWebSearch(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
       intent.setData(Uri.parse("http://www.google.com"));
       activity.startActivity(intent);
    }
    public static void dial(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_DIAL);
       activity.startActivity(intent);
    }
    
    public static void call(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_CALL);
       intent.setData(Uri.parse("tel:904-905-5646"));
       activity.startActivity(intent);
    }
    public static void showMapAtLatLong(Activity activity) 
    {
       Intent intent = new Intent(Intent.ACTION_VIEW);
       //geo:lat,long?z=zoomlevel&q=question-string
       intent.setData(Uri.parse("geo:0,0?z=4&q=business+near+city"));
       activity.startActivity(intent);
    }
    
    public static void tryOneOfThese(Activity activity)
    {
       IntentsUtils.call(activity);
    }
}

Intents and Data Uris

we have covered simplest of the intents where all we need is the name of an action. The ACTION_DIAL activity above falls under this criteria just like the "MY_SCREEN" example we started with. So to invoke the dialler all we need is the action of the dialler and nothing else. So let us reconsider that example:


    public static void dial(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_DIAL);
       activity.startActivity(intent);
    }

However if you notice other intents above you will see that they take an additional parameter called "Data" which normally points to a Uri. Let us take a look at the CALL activity


    public static void call(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_CALL);
       intent.setData(Uri.parse("tel:904-905-5646"));
       activity.startActivity(intent);
    }

For example one can not call a phone number unless they know what the phone number is. So invoking a "ACTION_CALL" would be useless unless we tell what number to call. This is what gets passed through the Data uri. so we now know that an "intent" has atleast two parts

  1. Action
  2. Data

Action is pointed by a string constant as we discussed earlier usually prefixed by the java package name. The Data portion is always a string representing a uri. The format of this uri could be specific to each Activity that is invoked by that action. In this case the "CALL" action decides what kind of data uri it would expect. From the Uri it extracts the telephone number.

The activity can also use the Uri as a pointer to a data source and extract the data from the data source and use that data instead. This would be the case for media such as audio and video or images.

Generic Actions

The actions Intent.ACTION_CALL and Intent.ACTION_DIAL could easily lead us to a wrong assumption that there is a one to one relationship between an action and what it invokes. To disprove this let us extract a counter example from the sample code above:


    public static void invokeWebBrowser(Activity activity)
    {
       Intent intent = new Intent(Intent.ACTION_VIEW);
       intent.setData(Uri.parse("http://www.google.com"));
       activity.startActivity(intent);
    }

If you notice, the action is simply stated as ACTION_VIEW. How does Android know which activity to invoke in response to such a generic action. Well android under these cases rely more heavily on the nature of the Uri. In this case it looks at the scehme of the uri which happens to be "http" and inquires all the registered activities to see which ones understand this scheme. Out of these it inquires which ones can handle the "VIEW" and then invokes that activity. For this to work the browser activity should have registered a VIEW intent against the data scheme of "http". That intent declaration may look like


<intent-filter>
   <action android:name="android.intent.action.VIEW" />
   <data android:scheme="http"/>
   <data android:scheme="https"/>
</intent-filter>

You can learn more about the data options by looking at the XML definition for the Data element at


http://code.google.com/android/reference/android/R.styleable.html#AndroidManifestData

The child elements or attributes of data include


host
mimeType
path
pathPattern
pathPrefix
port
scheme

The one that is often used is the mime type. For example the following IntentFilter for the activity that displays (views) a list of notes indicate the mime type as a directory of notes.


<intent-filter>
   <action android:name="android.intent.action.VIEW" />
   <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>

Where as the screen that displays a single note declares its intent filter as handling of type "a single note item"


<intent-filter>
   <action android:name="android.intent.action.INSERT" />
   <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>

Using Extra Info

Intent provides another facility to pass data between senders and receivers of an intent. This data is sometimes refered as "Extra" data. This "extra" data that an "Intent" carries with it is a set of key value pairs. The keys are recommended to start with the package name. The value can be any fundamental data type or an arbitrary object as long as it implements the Parcelable interface. So in that sense a bundle is a maping from string keys to various Parcelable type values.

A Parcelable interface allows classes to write their instances to and restored from a Parcel. A Parcel is a container for a message (data and object references) that can be sent through an IBinder. A Parcel can contain both flattened data that will be unflattened on the other side of the IPC (using the various methods here for writing specific types, or the general Parcelable interface), and references to live IBinder objects that will result in the other side receiving a proxy IBinder connected with the original IBinder in the Parcel.

Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.

There are a number of methods available on the "Intent" class to set and get this extra open ended data. Underneath an "Intent" stores this extra data as a single "Bundle". With that information most of the methods related to "extra" information would make sense.

start with


public static void exerciseExtraInfo(Intent intent)
{
   //Get the Bundle from this intent
   Bundle extraBundle = intent.getExtras();
   
   //
   Bundle anotherBundle = new Bundle();
   ...
   intent.putExtras(anotherBundle);
}

Here is what "putExtras" does. It checks to see if there is currently a bundle in the intent. If it is there it adds the additional keys and values from the new bundle to this existing bundle. If the bundle doesn't exist it will create a new one and adds the stuff from the new bundle to that bundle. So it is important to note that it doesn't reference the incoming bundle rather replicates it. Which means if you were to change the passed in bundle it won't change the bundle inside the Intent.

A number of methods exist to add fundamental types to the bundle. Here is a sample that adds simple data types to the "extra" data


putExtra(String name, boolean value);
putExtra(String name, int value);
putExtra(String name, double value);
putExtra(String name, String value);
....
....
and more

And here are some not so simple extras


//simple array support
putExtra(String name, int[] values);
putExtra(String name, float[] values);

//Serializable objects
putExtra(String name, Serializable value);

//Parcelable support
putExtra(String name, Parcelable value);

//Add another bundle at a given key
//Bundles in bundles
putExtra(String name, Bundle value);

//Add bundles from another intent
//copy of bundles
putExtra(String name, Intent anotherIntent);

//Explicit Array List support
putIntegerArrayListExtra(String name, ArrayList arrayList);
putParcelableArrayListExtra(String name, ArrayList arrayList);
putStringArrayListExtra(String name, ArrayList arrayList);

On the receiving side there are equivalent methods that start with "get" to get retrieve information from the extra bundle based on key names.

The "Intent" class defines a number of Extra key strings that go with certain actions. Here are some examples

EXTRA_ALARM_COUNT: Used as an int extra field in AlarmManager intents to tell the application being invoked how many pending alarms are being delievered with the intent. For one-shot alarms this will always be 1. For recurring alarms, this might be greater than 1 if the device was asleep or powered off at the time an earlier alarm would have been delivered. Constant Value: "android.intent.extra.ALARM_COUNT"

EXTRA_EMAIL: A String[] holding e-mail addresses that should be delivered to. Constant Value: "android.intent.extra.EMAIL"

EXTRA_SUBJECT: A constant string holding the desired subject line of a message. Constant Value: "android.intent.extra.SUBJECT"

EXTRA_BCC: A String[] holding e-mail addresses that should be blind carbon copied. Constant Value: "android.intent.extra.BCC"

EXTRA_CC: A String[] holding e-mail addresses that should be carbon copied. Constant Value: "android.intent.extra.CC"

EXTRA_DONT_KILL_APP: Used as an boolean extra field in ACTION_PACKAGE_REMOVED or ACTION_PACKAGE_CHANGED intents to override the default action of restarting the application. Constant Value: "android.intent.extra.DONT_KILL_APP"

EXTRA_INTENT: An Intent describing the choices you would like shown with ACTION_PICK_ACTIVITY. Constant Value: "android.intent.extra.INTENT"

EXTRA_KEY_EVENT: A KeyEvent object containing the event that triggered the creation of the Intent it is in. Constant Value: "android.intent.extra.KEY_EVENT"

EXTRA_PHONE_NUMBER: A String holding the phone number originally entered in ACTION_NEW_OUTGOING_CALL, or the actual number to call in a ACTION_CALL. Constant Value: "android.intent.extra.PHONE_NUMBER"

EXTRA_SHORTCUT_ICON: The name of the extra used to define the icon, as a Bitmap, of a shortcut. Used in conjunction with ACTION_CREATE_SHORTCUT action. Constant Value: "android.intent.extra.shortcut.ICON

EXTRA_SHORTCUT_ICON_RESOURCE: The name of the extra used to define the icon, as a ShortcutIconResource, of a shortcut. Constant Value: "android.intent.extra.shortcut.ICON_RESOURCE"

EXTRA_SHORTCUT_INTENT: The name of the extra used to define the Intent of a shortcut. Constant Value: "android.intent.extra.shortcut.INTENT"

EXTRA_SHORTCUT_NAME: The name of the extra used to define the name of a shortcut. Constant Value: "android.intent.extra.shortcut.NAME"

EXTRA_STREAM: A content: URI holding a stream of data associated with the Intent, used with ACTION_SEND to supply the data being sent. Constant Value: "android.intent.extra.STREAM"

EXTRA_TEXT: A constant CharSequence that is associated with the Intent, used with ACTION_SEND to supply the literal data to be sent. Note that this may be a styled CharSequence, so you must use Bundle.getCharSequence() to retrieve it. Constant Value: "android.intent.extra.TEXT"

EXTRA_TEMPLATE: The initial data to place in a newly created record. Use with ACTION_INSERT. The data here is a Map containing the same fields as would be given to the underlying ContentProvider.insert() call. Constant Value: "android.intent.extra.TEMPLATE"

EXTRA_TITLE: A CharSequence dialog title to provide to the user when used with a ACTION_CHOOSER. Constant Value: "android.intent.extra.TITLE"

EXTRA_UID: Used as an int extra field in ACTION_UID_REMOVED intents to supply the uid the package had been assigned. Also an optional extra in ACTION_PACKAGE_REMOVED or ACTION_PACKAGE_CHANGED for the same purpose. Constant Value: "android.intent.extra.UID"

Using components to directly invoke an Activity

In Android Activity, Service, ContentProvider and Application are considered application components. They all implement ComponentCallbacks. As an implementer of ComponentCallbacks they are expected to support two call back apis: onConfigurationChanged and onLowMemory.

The signatures of these methods are


public void onConfigurationChanged(Configuration newConfig);
public void onLowMemory();

onConfigurationChanged is called by the system when the device configuration changes while that component is running. Note that, unlike activities, other components are never restarted when a configuration changes: they must always deal with the results of the change, such as by re-retrieving resources.

onLowMemory() is called when the overall system is running low on memory, and would like actively running process to try to tighten their belt. While the exact point at which this will be called is not defined, generally it will happen around the time all background processes have been killed, that is before reaching the point of killing processes hosting service and foreground UI that we would like to avoid killing. Applications that want to be nice can implement this method to release any caches or other unnecessary resources they may be holding on to. The system will perform a gc after returning from this method.

An Activity being a component we can specify the name of this component or class name as an argument to the Intent and use start activity on the intent to start the target activity identified by the component name.

In a similar manner a target service component can be started using the "startService" method on the context class.

There are a number of methods available on the Intent class to specify a component.


setComponent(ComponentName name);
setClassName(String packageName, String classNameInThatPackage);
setClassName(Context context, String classNameInThatContext);
setClass(Context context, Class classObjectInThatContext);

Ultimately they are all shortcuts for calling one method


setComponent(ComponentName name);

Curiously ComponentName is a class which basically wraps a package name and a classname together. Although a component name is expected to point to a component implementing a "component" contract, the constructor of ComponentName does not do any particular checks to ensure that.

For example the following code invokes the "contacts" activity that gets shipped with the emulator


Intent intent = new Intent(); 
intent.setComponent(new ComponentName( 
     "com.android.contacts" 
    ,"com.android.contacts.DialtactsContactsEntryActivity"); 
intent.setFlags(....) 
startActivity(intent) 

Notice that the package name and the classname are fully qualified and used in turn to construct the ComponentName before passing to the intent class.

However it must be noted that this is not the recommended way to invoke other appications. The approach is fine for activities that are are inside an application. But for applications or activities that need to be invoked from outside they should go through the action and data uri route.

Best practice for component designers

If you look at the design for the contacts application in Android you will notice some patterns for designing with intents. In the example above we have used an explicit way to invoke the contacts application.

To make this easier the "android.provider.contacts" package defines three Intent related classes. These are


contacts.Intents
contacts.Intents.Insert //nested class
contacts.Intents.UI //nested class

The top level class "Intents" defines the primary Intents that the contacts application will respond to and also the events it generates as it does its work.

The nested class Intents.Insert defines the supporing intents and other constants to insert new records. The Intents.UI nested class defines a number of ways invoking the UI. The intents here also clarifies the extra information needed to invoke the intents including key names and their expected value types.

As you design your own content providers and activites that act upon those content providers you may want to follow this pattern for making intents explicit.

What are categories and how are they used

Categories is a way to classify activities. As activities are designed, they may have certain capabilities that will restrict them or enable them under some circumstances. These common characteristics of these activities are declared through categories. Let us look at some known categories


CATEGORY_DEFAULT 
CATEGORY_BROWSABLE 
CATEGORY_TAB 
CATEGORY_ALTERNATIVE 
CATEGORY_SELECTED_ALTERNATIVE 
CATEGORY_LAUNCHER 
CATEGORY_HOME 
CATEGORY_PREFERENCE 
CATEGORY_GADGET 
CATEGORY_TEST 
CATEGORY_EMBED

let us examine a few of these categories whose meaning is obvious. Take for insnace GADGET category. Activities enabled for this category, can be embedded inside of another activity that is hosting gadgets. The implication is that such an activity needs to be bound by certain contracts. In a similar manner The EMBED category declares that an activity is capable of being embedded in a parent activity.

Here is an explanation for each of these categories.

CATEGORY_DEFAULT:Set if the activity should be an option for the default action (center press) to perform on a piece of data. Setting this will hide from the user any activities without it set when performing an action on some data. Note that this is normal -not- set in the Intent when initiating an action -- it is for use in intent filters specified in packages. Constant Value: "android.intent.category.DEFAULT"

CATEGORY_BROWSABLE: Activities that can be safely invoked from a browser must support this category. For example, if the user is viewing a web page or an e-mail and clicks on a link in the text, the Intent generated execute that link will require the BROWSABLE category, so that only activities supporting this category will be considered as possible actions. By supporting this category, you are promising that there is nothing damaging (without user intervention) that can happen by invoking any matching Intent. Constant Value: "android.intent.category.BROWSABLE"

CATEGORY_TAB: Intended to be used as a tab inside of an containing TabActivity.

CATEGORY_ALTERNATIVE: Set if the activity should be considered as an alternative action to the data the user is currently viewing. See also CATEGORY_SELECTED_ALTERNATIVE for an alternative action that applies to the selection in a list of items. Supporting this category means that you would like your activity to be displayed in the set of alternative things the user can do, usually as part of the current activity's options menu. You will usually want to include a specific label in the of this action describing to the user what it does.

The action of IntentFilter with this category is important in that it describes the specific action the target will perform. This generally should not be a generic action (such as ACTION_VIEW, but rather a specific name such as "com.android.camera.action.CROP. Only one alternative of any particular action will be shown to the user, so using a specific action like this makes sure that your alternative will be displayed while also allowing other applications to provide their own overrides of that particular action.

CATEGORY_EMBED: Capable of running inside a parent activity container. However this is being removed in favor of more explicit categories such as CATEGORY_GADGET

CATEGORY_SELECTED_ALTERNATIVE: Set if the activity should be considered as an alternative selection action to the data the user has currently selected. This is like CATEGORY_ALTERNATIVE, but is used in activities showing a list of items from which the user can select, giving them alternatives to the default action that will be performed on it.

CATEGORY_LAUNCHER: Should be displayed in the top-level launcher.

CATEGORY_HOME: This is the home activity, that is the first activity that is displayed when the device boots.

CATEGORY_PREFERENCE: This activity is a development preference panel.

CATEGORY_GADGET: This activity can be embedded inside of another activity that is hosting gadgets.

CATEGORY_TEST: To be used as a test (not part of the normal user experience).

CATEGORY_MONKEY: This activity may be exercised by the monkey or other automated test tools.

CATEGORY_OPENABLE: Used to indicate that a GET_CONTENT intent only wants URIs that can be opened with ContentResolver.openInputStream. Openable URIs must support the columns in OpenableColumns when queried, though it is allowable for those columns to be blank.

Categories and Intents

When you use an intent to start an activity, you can specify the kind of activity to choose by specifying a category. Or you can also search for activites that match a certain category.

Here is an example to retrieve a set of main activities that match the category of CATEGORY_SAMPLE_CODE. PackageManager is a key class that allows discovery of activities that match a certain intent with out invoking them. A programmer can cycle through the received activities and invoke them as see fit based on the ResolveInfo api.


Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);

Following the same logic we can also get a list of all launchable applications by populating an intent with a category of CATEGORY_LAUNCHER. The sample code for this is below


//Get me all launchable applications
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List mApps = getPackageManager().queryIntentActivities(mainIntent, 0);

In fact we can do better. Let us go ahead and start an activity based on the Intent above. There are going to be more than one activity matching the intent. Which activity is Android going to start? Android instead presents a chooser dialog listing all possible activities. The title of this dialog says "Complete action using".


   public static void invokeAMainApp(Activity activity)
   {
      Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
      mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
      activity.startActivity(mainIntent);
   }

Here is another example of using an intent to go to a home page.


//Go to home screen
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_HOME);
startActivity(mainIntent);

You can also write your own home page instead of one that comes with Android and declare that activity to be of category HOME and then the code above will give you an option to open your home activity as there are now more than one home activities registered.


//Replace the home screen with yours 
<intent-filter> 
   <action android:value="android.intent.action.MAIN" /> 
   <category android:value="android.intent.category.HOME"/> 
   <category android:value="android.intent.category.DEFAULT" /> 
</intent-filter> 

Also note that when we launch these intents, they are still being launched as a new instance that is part of the same task/stack. If we want to launch it as a separate task (or bring the currently running instance of the app to the foreground) like the home app does, then we need to set the NEW_TASK_LAUNCH flag in the Intent.

The rules for resolving Intents to their components

So far we have discussed a number of aspects about intents. To recap we talked about actions, data uris, extra infos, and finally categories. Given these aspects Android uses the following algorithm to resolve the intents to activities or more specifically components:

At the top of the hierarchy, with an air of exclusivity, is the Component name attached to an intent. If this is set, then every other aspect or attribute of the intent is ignored and that component is chosen for execution.

If an intent indicates an action then the target activity must have that action listed as one it supports in the manifest file.

If an intent specifies a data uri, the type is retrieved from this uri, if not already supplied in the Intent. Like the action, if a type is included in the intent (either explicitly or implicitly in its data), then this must be listed by the component as one it handles.

For data that is not a content: URI and where no explicit type is included in the Intent, instead the scheme of the intent data (such as http: or mailto:) is considered. Again like the action, if we are matching a scheme it must be listed by the component as one it can handle.

The categories, if supplied, must all be listed by the activity as categories it handles. That is, if you include the categories CATEGORY_LAUNCHER and CATEGORY_ALTERNATIVE, then you will only resolve to components with an intent that lists both of those categories. Activities will very often need to support the CATEGORY_DEFAULT so that they can be found by Context.startActivity().

How should your applications declare intents

As you write new applications for Android you will want to declare intents for each of the activities you have in that application. Let us examine the notepad application to draw a pattern of these intent declarations.


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.notepad">
     <application android:icon="@drawable/app_notes"
             android:label="@string/app_name">

         <provider class=".NotePadProvider"
                 android:authorities="com.google.provider.NotePad" />

         <activity class=".NotesList" android:label="@string/title_notes_list">
             <intent-filter>
                 <action android:value="android.intent.action.MAIN" />
                 <category android:value="android.intent.category.LAUNCHER" />
             </intent-filter>
             <intent-filter>
                 <action android:value="android.intent.action.VIEW" />
                 <action android:value="android.intent.action.EDIT" />
                 <action android:value="android.intent.action.PICK" />
                 <category android:value="android.intent.category.DEFAULT" />
                 <type android:value="vnd.android.cursor.dir/vnd.google.note" />
             </intent-filter>
             <intent-filter>
                 <action android:value="android.intent.action.GET_CONTENT" />
                 <category android:value="android.intent.category.DEFAULT" />
                 <type android:value="vnd.android.cursor.item/vnd.google.note" />
             </intent-filter>
         </activity>

         <activity class=".NoteEditor" android:label="@string/title_note">
             <intent-filter android:label="@string/resolve_edit">
                 <action android:value="android.intent.action.VIEW" />
                 <action android:value="android.intent.action.EDIT" />
                 <category android:value="android.intent.category.DEFAULT" />
                 <type android:value="vnd.android.cursor.item/vnd.google.note" />
             </intent-filter>

             <intent-filter>
                 <action android:value="android.intent.action.INSERT" />
                 <category android:value="android.intent.category.DEFAULT" />
                 <type android:value="vnd.android.cursor.dir/vnd.google.note" />
             </intent-filter>
         </activity>

         <activity class=".TitleEditor" android:label="@string/title_edit_title"
                 android:theme="@android:style/Theme.Dialog">
             <intent-filter android:label="@string/resolve_title">
                 <action android:value="com.android.notepad.action.EDIT_TITLE" />
                 <category android:value="android.intent.category.DEFAULT" />
                 <category android:value="android.intent.category.ALTERNATIVE" />
                 <category android:value="android.intent.category.SELECTED_ALTERNATIVE" />
                 <type android:value="vnd.android.cursor.item/vnd.google.note" />
             </intent-filter>
         </activity>

     </application>
 </manifest>
 

As you can see there are three activities in this application that are exposed for public consumption. They are


NotesList
NoteEditor
TitleEditor

NotesList is the main entry point of the application listing all the notes in the database of notes. NoteEditor is the screen that allows you the content of a given note. A TitleEditor is the screen that allows you to edit the title of a note. You will want to put an icon in the launcher of android so that the notes application can be invoked. To facilitate this the main activity NotesList declares an intent as follows:


<intent-filter>
 <action android:value="android.intent.action.MAIN" />
 <category android:value="android.intent.category.LAUNCHER" />
</intent-filter>

This allows Android to add this activity as a launchable activity. List activity is can also be invoked explicitly by some other program to view or edit a collection of notes in the notepad.


 <intent-filter>
    <action android:value="android.intent.action.VIEW" />
    <action android:value="android.intent.action.EDIT" />
    <action android:value="android.intent.action.PICK" />
    <category android:value="android.intent.category.DEFAULT" />
    <type android:value="vnd.android.cursor.dir/vnd.google.note" />
 </intent-filter>

By declaring a "PICK" action the NotesList activity is allowing the user to pick an item from the collection and return to the caller. This activity is also capable of returning the data for a given note item by allowing the user to pick one of the items of a note using the following intent. As you can see for these generic supported actions the main key is the mime type of the data. So an activity defines a set of allowed actions for each mime type in a separate filter.


<intent-filter>
 <action android:value="android.intent.action.GET_CONTENT" />
 <category android:value="android.intent.category.DEFAULT" />
 <type android:value="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>

Let's look at the NotesEditor activity to see how it defines its intent filters


 <activity class=".NoteEditor" android:label="@string/title_note">
    <intent-filter android:label="@string/resolve_edit">
       <action android:value="android.intent.action.VIEW" />
       <action android:value="android.intent.action.EDIT" />
       <category android:value="android.intent.category.DEFAULT" />
       <type android:value="vnd.android.cursor.item/vnd.google.note" />
    </intent-filter>

    <intent-filter>
       <action android:value="android.intent.action.INSERT" />
       <category android:value="android.intent.category.DEFAULT" />
       <type android:value="vnd.android.cursor.dir/vnd.google.note" />
    </intent-filter>
 </activity>

In the first intent filter it allows you to see and edit a single note. In the second filter it allows you to insert a note in to a directory of notes.

Finally lets look at the title editor


 <activity class=".TitleEditor" android:label="@string/title_edit_title"
       android:theme="@android:style/Theme.Dialog">
    <intent-filter android:label="@string/resolve_title">
       <action android:value="com.android.notepad.action.EDIT_TITLE" />
       <category android:value="android.intent.category.DEFAULT" />
       <category android:value="android.intent.category.ALTERNATIVE" />
       <category android:value="android.intent.category.SELECTED_ALTERNATIVE" />
       <type android:value="vnd.android.cursor.item/vnd.google.note" />
    </intent-filter>
 </activity>

This activity allows you to show a set of menu items to edit a title of a note. Notice that the action is a specific type and not a generic action.

Given these definitions here is what you can do with intents outside of this application

{ action=android.app.action.MAIN }: matches all of the activities that can be used as top-level entry points into an application.

{ action=android.app.action.MAIN, category=android.app.category.LAUNCHER }: is the actual intent used by the Launcher to populate its top-level list.

{ action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes }: displays a list of all the notes under "content://com.google.provider.NotePad/notes", which the user can browse through and see the details on.

{ action=android.app.action.PICK data=content://com.google.provider.NotePad/notes }: provides a list of the notes under "content://com.google.provider.NotePad/notes", from which the user can pick a note whose data URL is returned back to the caller.

{ action=android.app.action.GET_CONTENT type=vnd.android.cursor.item/vnd.google.note }: is similar to the pick action, but allows the caller to specify the kind of data they want back so that the system can find the appropriate activity to pick something of that data type.

{ action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes/{ID} }: shows the user the content of note {ID}.

{ action=android.app.action.EDIT data=content://com.google.provider.NotePad/notes/{ID} }: allows the user to edit the content of note {ID}.

{ action=android.app.action.INSERT data=content://com.google.provider.NotePad/notes }: creates a new, empty note in the notes list at "content://com.google.provider.NotePad/notes" and allows the user to edit it. If they keep their changes, the URI of the newly created note is returned to the caller.

{ action=com.android.notepad.action.EDIT_TITLE data=content://com.google.provider.NotePad/notes/{ID} }: displays and allows the user to edit the title associated with note {ID}.

Exercising ACTION_PICK intent

So far we have exercised intents or actions that mainly invoke another activity and not expect any result back. Let us look at an activity that is a bit more involved and which returns a value as a result of that activity. ACTION_PICK is one such action. Here is what the documentation says about ACTION_PICK:

ACTION_PICK picks an item from the data, returning what was selected. The intent invoking ACTION_PICK should carry with it a URI containing a directory of data (vnd.android.cursor.dir/*) from which to pick an item. This should be set using the setData() on the intent. The output from the action will be a URI of the item that was picked.

For all actions and intents that return data like this we cannot use startActivity() because startActivity() does not return any result. The reason why startActivity can not return result is because it opens the new activity as a modal dialog in a separate thread and leaves the main thread for attending events in the main ui thread. In other words "startActivity" is an asynchronous call with any call back to indicate what happened in the invoked activity. There is a variation on this method called startActivityForResult() that comes with a call back.

Let us look at the signature of this method from the Activity class:


public void startActivityForResult(Intent intent, int requestCode) 

This method launches an activity for which you would like a result when it finished. When this activity exits, your onActivityResult() method will be called with the given requestCode. Using a negative requestCode is the same as calling startActivity(Intent) (the activity is not launched as a sub-activity).

Note that this method should only be used with Intent protocols that are defined to return a result. In other protocols (such as ACTION_MAIN or ACTION_VIEW), you may not get the result when you expect. For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.

The result will come back to the activity through an overriden method called onActivityResult. The signature of this method is


protected void onActivityResult(int requestCode, int resultCode, Intent data) 

Called when an activity you launched exits, giving you the requestCode you started it with, the resultCode it returned, and any additional data from it. The resultCode will be RESULT_CANCELED if the activity explicitly returned that, didn't return any result, or crashed during its operation. You will receive this call immediately before onResume() when your activity is re-starting.

When an activity exits, it can call setResult(int) to return data back to its parent. It must always supply a result code, which can be the standard results RESULT_CANCELED, RESULT_OK, or any custom values starting at RESULT_FIRST_USER. In addition, it can optionally return back an Intent containing any additional data it wants. All of this information appears back on the parent's Activity.onActivityResult(), along with the integer identifier it originally supplied. If a child activity fails for any reason (such as crashing), the parent activity will receive a result with the code RESULT_CANCELED.

Let us look at some samplecode demonstrating this


Intent pickIntent = new Intent(Intent.ACTION_PICK);
pickIntent.setData(Uri.parse("content://contacts"));
int requestCode = 1;
activity.startActivityForResult(pickIntent,requestCode);

protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent)
{
	if (requestCode == 1)
	{
		if (resultCode == RESULT_OK)
		{
			Uri outputUri = outputIntent.getData();
			//Log it out
			Log.d("test",outputUri.toString());
			//Do something with the uri including viewing it
			outputIntent.setAction(Intent.VIEW);
			startActivity(outputIntent);
		}
	}
}

The constants RESULT_OK, RESULT_CANCEL, RESULT_FIRST_USER are all defined in the activity class. The numerical values of these constants are


RESULT_OK = -1;
RESULT_CANCEL = 0;
RESULT_FIRST_USER = 1;

The constant RESULT_FIRST_USER is used as a starting number for user defined activity results.

To make this work the implementer should have code that explicitly addresses the needs of a PICK. Notice how this is done in the sample note pad application. When the item is selected in the list of items, the intent that invoked the activity is checked to see if it is a PICK intent. If it is the data uri is set in a new intent and returned through setResult().


@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
	Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
	
	String action = getIntent().getAction();
	if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
		// The caller is waiting for us to return a note selected by
		// the user.  The have clicked on one, so return it now.
		setResult(RESULT_OK, new Intent().setData(uri));
	} else {
		// Launch activity to view/edit the currently selected item
		startActivity(new Intent(Intent.ACTION_EDIT, uri));
	}
}

Exercising GET_CONTENT action

ACTION_GET_CONTENT allows the user to select a particular kind of data and return it. This is different than ACTION_PICK in that here we just say what kind of data is desired, not a URI of existing data from which the user can pick. A ACTION_GET_CONTENT could allow the user to create the data as it runs (for example taking a picture or recording a sound), let them browser over the web and download the desired data, etc.

Notice how the activity that displays a list of notes in the notepad application declares itself in response to PICK and GET_CONTENT:


<intent-filter>
	<action android:name="android.intent.action.VIEW" />
	<action android:name="android.intent.action.EDIT" />
	<action android:name="android.intent.action.PICK" />
	<category android:name="android.intent.category.DEFAULT" />
	<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
<intent-filter>
	<action android:name="android.intent.action.GET_CONTENT" />
	<category android:name="android.intent.category.DEFAULT" />
	<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>

For a PICK action you need to specify the uri which will yield a mime type of "directory of note" indicated by dir/note which will then resolve to this list activity.

The get_content action is defined in a separate filter identified by not a directory of notes but just an "item" of a note indicated by "item/note". For a GET_CONTENT you will not specify the URI.

The sample code then will look like


Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("vnd.android.cursor.item/vnd.google.note");
int requestCode = 1;
activity.startActivityForResult(pickIntent,requestCode);

Knowing the mime type android will then launch the best application to select that kind of data for you.

GET_CONTENT action also allows another way of picking a data uri. For instance, you may be interested in any of a set of types of content that you can pick. For example, an e-mail application that wants to allow the user to add an attachment to an e-mail message can use this action to bring up a list of all of the types of content the user can attach.

In this case, you should wrap the GET_CONTENT intent with a chooser (through createChooser(Intent, CharSequence)), which will give the proper interface for the user to pick how to send your data and allow you to specify a prompt indicating what they are doing. You will usually specify a broad MIME type (such as image/* or */*), resulting in a broad range of content types the user can select from.

When using such a broad GET_CONTENT action, it is often desireable to only pick from data that can be represented as a stream. This is accomplished by requiring the CATEGORY_OPENABLE in the Intent.

To reiterate the input to an ACTION_GET_CONTENT is the desired MIME type to retrieve. No URI is supplied in the intent, as there are no constraints on where the returned data originally comes from. You may also include the CATEGORY_OPENABLE if you can only accept data that can be opened as a stream. The result of invoking this action is a URI of the item that was picked. This must be a content: URI so that any receiver can access it.

List of of useful actions defined in Intent

Here is a quick sample of actions that the Intent class defines


ACTION_MAIN 
ACTION_VIEW
ACTION_ATTACH_DATA 
ACTION_EDIT 
ACTION_PICK 
ACTION_CHOOSER 
ACTION_GET_CONTENT 
ACTION_DIAL 
ACTION_CALL 
ACTION_SEND 
ACTION_SENDTO 
ACTION_ANSWER 
ACTION_INSERT
ACTION_DELETE 
ACTION_RUN 
ACTION_SYNC 
ACTION_PICK_ACTIVITY 
ACTION_SEARCH 
ACTION_WEB_SEARCH 
ACTION_FACTORY_TEST 

The details of each of these actions are

ACTION_ALL_APPS: List all available applications

ACTION_MAIN: Invoke the main screen of an application.

ACTION_VIEW : Show an activity that is capable of seeing a uri. Input is the uri of the data to be shown.

ACTION_ATTACH_DATA: Used to indicate that some piece of data should be attached to some other place. For example, image data could be attached to a contact. It is up to the recipient to decide where the data should be attached; the intent does not specify the ultimate destination. Input is the Uri of the data to be attached. It has no output.

ACTION_EDIT : A generic action for editing data at a given input uri. no output.

ACTION_PICK : Picks the uri of a data item from a directory of data items. Input is the data uri for the directory of items. the output is the data uri of a specific item.

ACTION_CHOOSER :Activity Action: Display an activity chooser, allowing the user to pick what they want to before proceeding. This can be used as an alternative to the standard activity picker that is displayed by the system when you try to start an activity with multiple possible matches, with these differences in behavior:

You can specify the title that will appear in the activity chooser. The user does not have the option to make one of the matching activities a preferred activity, and all possible activities will always be shown even if one of them is currently marked as the preferred activity.

This action should be used when the user will naturally expect to select an activity in order to proceed. An example if when not to use it is when the user clicks on a "mailto:" link. They would naturally expect to go directly to their mail app, so startActivity() should be called directly: it will either launch the current preferred app, or put up a dialog allowing the user to pick an app to use and optionally marking that as preferred.

In contrast, if the user is selecting a menu item to send a picture they are viewing to someone else, there are many different things they may want to do at this point: send it through e-mail, upload it to a web service, etc. In this case the CHOOSER action should be used, to always present to the user a list of the things they can do, with a nice title given by the caller such as "Send this photo with:".

As a convenience, an Intent of this form can be created with the createChooser(Intent, CharSequence) function.

Input: No data should be specified. get*Extra must have a EXTRA_INTENT field containing the Intent being executed, and can optionally have a EXTRA_TITLE field containing the title text to display in the chooser.

ACTION_GET_CONTENT: Similar to PICK but uses the data type instead of the data uri.

ACTION_DIAL : Show the dialler allowing a user to dial a number. Can pass a phone uri to prepopulate the dialler. No output.

ACTION_CALL : Make a call based on a phone uri. You may need permissions to call a number like this. You should use DIAL where needed. Emergency numbers can be dialled only through DIAL.

ACTION_SEND:Deliver some data to someone else. Who the data is being delivered to is not specified; it is up to the receiver of this action to ask the user where the data should be sent. When launching a SEND intent, you should usually wrap it in a chooser (through createChooser(Intent, CharSequence)), which will give the proper interface for the user to pick how to send your data and allow you to specify a prompt indicating what they are doing.

The intent should specify the MIME type of the data being sent. get*Extra can have either a EXTRA_TEXT or EXTRA_STREAM field, containing the data to be sent. If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the MIME type of the data in EXTRA_STREAM. Use */* if the MIME type is unknown (this will only allow senders that can handle generic data streams).

Optional standard extras, which may be interpreted by some recipients as appropriate, are: EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC, EXTRA_SUBJECT.

ACTION_SENDTO: Send a message to someone specified by the data.

ACTION_ANSWER: Handle an incoming phone call. No inputs and outputs.

ACTION_INSERT : Insert an empty item into a given container. Needs a data uri pointing to the directory of items. Output is the uri of the data that was inserted.

ACTION_INSERT_OR_EDIT: Pick an existing item, or insert a new item, and then edit it. Input is the desired MIME type of the item to create or edit. The extras can contain type specific data to pass through to the editing/creating activity. Output is the URI of the item that was picked.

ACTION_DELETE : Delete what is pointed to by a Uri. Input is the data uri that is to be deleted. No outputs.

ACTION_SEARCH: invoke search activity using extra string information

ACTION_WEB_SEARCH: Opens a web page to search

ACTION_BUG_REPORT: show activity to report a bug. no inputs or outputs.

ACTION_SET_WALLPAPER: Show settings for chosing a wall paper

ACTION_VOICE_COMMAND: Start voice command

Here are some broadcast actions

ACTION_BATTERY_CHANGED: Charge level of the battery changed

ACTION_BATTERY_LOW: Battery is low

ACTION_BOOT_COMPLETED: This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.

ACTION_CALL_BUTTON: The user pressed the "call" button to go to the dialer or other appropriate UI for placing a call. no inputs and outputs.

ACTION_CAMERA_BUTTON: The "Camera Button" was pressed. Includes a single extra field, EXTRA_KEY_EVENT, containing the key event that caused the broadcast.

ACTION_DATE_CHANGED: The date has changed.

ACTION_MEDIA_BUTTON: Media button was pressed. Includes a single extra field, EXTRA_KEY_EVENT, containing the key event that caused the broadcast.

ACTION_MEDIA_EJECT: User has expressed the desire to remove the external storage media. Applications should close all files they have open within the mount point when they receive this intent. The path to the mount point for the media to be ejected is contained in the Intent.mData field.

ACTION_MEDIA_MOUNTED: External media is present and mounted at its mount point. The path to the mount point for the removed media is contained in the Intent.mData field. The Intent contains an extra with name "read-only" and Boolean value to indicate if the media was mounted read only.

ACTION_PACKAGE_ADDED: A new package has been installed on the device. Name of the package will be in the intent.

ACTION_PACKAGE_CHANGED: A named package has been changed either by enabling a component or disabling.

ACTION_PACKAGE_INSTALL: A trigger to download and eventual installation of a package. The data part of the intent contains the uri of the package to download.

ACTION_PACKAGE_REMOVED: A named package has been removed.

ACTION_PROVIDER_CHANGED: Some content providers have parts of their namespace where they publish new events or items that the user may be especially interested in. For these things, they may broadcast this action when the set of interesting items change. For example, GmailProvider sends this notification when the set of unread mail in the inbox changes.

The data of the intent identifies which part of which provider changed. When queried through the content resolver, the data URI will return the data set in question.

The intent will have the following extra values:

count - The number of items in the data set. This is the same as the number of items in the cursor returned by querying the data URI. This intent will be sent at boot (if the count is non-zero) and when the data set changes. It is possible for the data set to change without the count changing (for example, if a new unread message arrives in the same sync operation in which a message is archived). The phone should still ring/vibrate/etc as normal in this case.

ACTION_SCREEN_OFF: Screen turned off

ACTION_SCREEN_ON: Screen turned on

ACTION_TIMEZONE_CHANGED: Time zone has changed. The id of the new time zone will be the extra info.

ACTION_TIME_CHANGED: The time was set.

ACTION_TIME_TICK: Sent every minute.

ACTION_UID_REMOVED: User id removed from the system. The user ID number is stored in the extra data under EXTRA_UID.

ACTION_WALLPAPER_CHANGED: Wall paper has changed.

Intent Flags

Intents use a set of flags to control the behavior of how new activities are invoked. Here is a brief look at these flags

FLAG_ACTIVITY_BROUGHT_TO_FRONT: This flag is not normally set by application code, but set for you by the system as described in the launchMode documentation for the singleTask mode.

FLAG_ACTIVITY_CLEAR_TOP : If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.

The currently running instance of task B in the above example will either receiving the new intent you are starting here in its onNewIntent() method, or be itself finished and restarting with the new intent. If it has declared its launch mode to be "multiple" (the default) it will be finished and re-created; for all other launch modes it will receive the Intent in the current instance.

This launch mode can also be used to good effect in conjunction with FLAG_ACTIVITY_NEW_TASK: if used to start the root activity of a task, it will bring any currently running instance of that task to the foreground, and then clear it to its root state. This is especially useful, for example, when launching an activity from the notification manager.

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: If set, the new activity is not kept in the list of recently launched activities.

FLAG_ACTIVITY_FORWARD_RESULT :If set and this intent is being used to launch a new activity from an existing one, then the reply target of the existing activity will be transfered to the new activity. This way the new activity can call setResult(int) and have that result sent back to the reply target of the original activity.

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY: If set, this activity is being launched from history (longpress home key).

FLAG_ACTIVITY_MULTIPLE_TASK :Do not use this flag unless you are implementing your own top-level application launcher. Used in conjunction with FLAG_ACTIVITY_NEW_TASK to disable the behavior of bringing an existing task to the foreground. When set, a new task is always started to host the Activity for the Intent, regardless of whether there is already an existing task running the same thing. Because the default system does not include graphical task management, you should not use this flag unless you provide some way for a user to return back to the tasks you have launched.

This flag is ignored if FLAG_ACTIVITY_NEW_TASK is not set.

FLAG_ACTIVITY_NEW_TASK :If set, this activity will become the start of a new task on this history stack. A task (from the activity that started it to the next task activity) defines an atomic group of activities that the user can move to. Tasks can be moved to the foreground and background; all of the activities inside of a particular task always remain in the same order. See the Application Model documentation for more details on tasks.

This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them.

When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK for a flag to disable this behavior.

This flag can not be used when the caller is requesting a result from the activity being launched.

FLAG_ACTIVITY_NO_HISTORY : If set, the new activity is not kept in the history stack.

FLAG_ACTIVITY_PREVIOUS_IS_TOP : If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately.

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED :If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed.

FLAG_ACTIVITY_SINGLE_TOP : If set, the activity will not be launched if it is already running at the top of the history stack.

FLAG_DEBUG_LOG_RESOLUTION : A flag you can enable for debugging: when set, log messages will be printed during the resolution of this intent to show you what has been found to create the final resolved list.

FLAG_FROM_BACKGROUND : Can be set by the caller to indicate that this Intent is coming from a background operation, not from direct user interaction.

FLAG_GRANT_READ_URI_PERMISSION: If set, the recipient of this Intent will be granted permission to perform read operations on the Uri in the Intent's data.

FLAG_GRANT_WRITE_URI_PERMISSION : If set, the recipient of this Intent will be granted permission to perform write operations on the Uri in the Intent's data.

FLAG_RECEIVER_REGISTERED_ONLY : If set, when sending a broadcast only registered receivers will be called -- no BroadcastReceiver components will be launched.

Definitions for EXTRA Info

EXTRA_TEMPLATE :The initial data to place in a newly created record. Use with ACTION_INSERT. The data here is a Map containing the same fields as would be given to the underlying ContentProvider.insert() call.

EXTRA_TEXT :A constant CharSequence that is associated with the Intent, used with ACTION_SEND to supply the literal data to be sent. Note that this may be a styled CharSequence, so you must use Bundle.getCharSequence() to retrieve it.

EXTRA_TITLE :A CharSequence dialog title to provide to the user when used with a ACTION_CHOOSER.

EXTRA_UID :Used as an int extra field in ACTION_UID_REMOVED intents to supply the uid the package had been assigned. Also an optional extra in ACTION_PACKAGE_REMOVED or ACTION_PACKAGE_CHANGED for the same purpose.

The string keys for these extras start with "android.intent.extra.*"

satya - Saturday, February 05, 2011 11:03:40 AM

Directly invoking an intent


private void invokeTabNav()
{
   Intent i = new Intent(this,ActionBarActivity.class);
   startActivity(i);
}