Just An Application

December 16, 2010

The Android Intent Based APIs: Part Three – Intent Filters

Filed under: Android, IntentFilters, Intents, Java, Mobile Java — Tags: , , , , — Simon Lewis @ 9:37 pm

An Intent Filter specifies a set of values to be matched against Intents.

Values may be specified to match against any or all of the following parts of an Intent

  • the action

  • the data

  • the data type

  • the categories

1. Actions

An Intent Filter may specify zero or more actions to match against the action specified by an Intent.

2. Data

An Intent Filter may specify

  • a non-empty set of schemes, or

  • a non-empty set of schemes and a non-empty set of authorities, or

  • a non-empty set of schemes and a non-empty set of authorities and a non-empty set of paths

to match against the data specified by an Intent.

Although it is also possible for an Intent Filter to specify the following,

  • a non-empty set of authorities only, or

  • a non-empty set of paths only, or

  • a non-empty set of authorities and a non-empty set of paths only

they will NOT be used when matching against the data specified by an Intent.

2.2 Schemes

A scheme specifies a case-sensitive URI scheme to match against the scheme of a data URI specified by an Intent

2.3 Authorities

An authority specifies a host, and optionally a port, to match the authority part of a network data URI specified by an Intent.

2.4 Paths

A path to match against the data URI specified by an Intent can be specified as

  • a literal, which the path part of the data URI must be equal to,

  • a prefix, which the path part of the data URI must start with, or

  • a simple pattern, which the path part of the data URI must match

The syntax of a simple pattern is as follows

  • The expression <char>'*' matches zero or more occurences of <char>

  • The character '.' matches any character.

  • The character '\' escapes the following character.

3. Data Types

An IntentFilter can specify zero or more MIME types to match against the type of the data specified by an Intent.

4. Categories

An Intent Filter can specify zero or more categories to match against the set of categories specified by an Intent.

5. The intent-filter XML Element

An Intent Filter can be specified in the manifest of an Application using the

    intent-filter

element.

5.1 Attributes

All the attributes of this element pertain to the Application Component which declares it rather than to the Intent Filter itself.

5.1.1 The icon Attribute

If present the icon attribute specifies a drawable resource which the system should use to visually identify the Application Component with which this Intent Filter declaration is associated.

5.1.2 The label Attribute

If present the label attribute specifies a string resource which the system should use to label the Application Component with which this Intent Filter declaration is associated.

5.1.3 The priority Attribute

If present the priority attribute specifies an integer value to be used by the system if it is necessary to compute an ordering on a set of Application Components all of which have associated Intent Filters which match a given Intent.

5.2 Child Elements

5.2.1 The action Element

The action element has a single attribute

    name

which specifies the action. This attribute must be present.

There are no child elements.

The element must appear at least once. It may appear multiple times.

5.2.2 The category Element

The category element has a single attribute

    name

which specifies the category. This attribute must be present.

There are no child elements.

The element may appear zero or more times.

5.2.3 The data Element

The data element may appear zero or more times.

It has no child elements. All values are specified using attributes.

The exact set of attributes associated with an individual data element is not significant.

For example, these three elements

    <data scheme="http"/>

    <data host="justanapplication.wordpress.com"/>
	
    <data pathPrefix="/2010"/>

are equivalent to this one.

    <data scheme="http" host="justanapplication.wordpress.com" pathPrefix="/2010"/>

The values specified by each element are aggregated to make up the IntentFilter’s sets of schemes, authorities, paths and types.

The validity of the authority and path sets that result are governed by the rules defined here.

5.2.3.1 The Attributes

5.2.3.1.1 Specifying A Scheme

A scheme can be specified using the scheme attribute.

5.2.3.1.2 Specifying An Authority

The host and port parts of an authority can be specified using the host and port attributes respectively.

A data element may have a host attribute without an associated port attribute. However, if a data element does not have a host attribute, but it does have a port attribute, then the port attribute is ignored.

5.2.3.1.3 Specifying A Path

A path can be specified as a

using the

  • path
  • pathPrefix, or
  • pathPattern

attributes respectively.

All three attributes may be present on the same element.

5.2.3.1.3 Specifying A Data Type

A data type can be specified by using mimeType attribute.

The value of the attribute must be a valid MIME type of the form <type>/<sub-type>. It is an error if it is not.

6. The IntentFilter class

An Application can specify an Intent Filter at runtime using an instance of the class

    android.content.IntentFilter

The system itself uses sub-classes of this class to represent both statically and dynamically specified Intent Filters associated with Application Components.

An IntentFilter instance may contain

  • a set of actions

  • a set of schemes

  • a set of authorities

  • a set of paths

  • a set of MIME types

  • a set of categories

6.1 Construction

The IntentFilter class has four public constructors

    public IntentFilter()

    public IntentFilter(String action)
	
    public IntentFilter(String action, String dataType)
	
    public IntentFilter(IntentFilter o)

An instance of IntentFilter is mutable so only the default constructor is strictly necessary, but IntentFilters with a single action are fairly heavily used by the system itself hence at least one of the convenience constructors.

6.2 Actions

An action can be added to an IntentFilter’s set of actions using the method

    public final void addAction(String action)

The format of the action argument is not checked, although it cannot be null.

6.3 Data

6.3.1 Schemes

A scheme can be added to an IntentFilter’s set of schemes using the method

    public final void addDataScheme(String scheme)

The format of the scheme argument is not checked, although it cannot be null.

6.3.2 Authorities

An authority can be added to an IntentFilter’s set of authorities using the method

    public final void addDataAuthority(String host, String port)

The host argument may start with the wildcard character ('*') in which case it specifies a suffix to match. It cannot be null.

The port may be null. If it is not then it must be a representation of an integer capable of being parsed by the Integer method

    public int parseInt(String string)

or a NumberFormatException will be thrown.

Whether adding an authority using this method will actually have any effect on the matching of an Intent’s data URI depends on the rules outlined here.

6.3.3 Paths

A path can be added to the IntentFilter’s set of paths using the method

    public final void addDataPath(String path, int type)

The value of the type argument must be one of the following android.os.PatternMatcher class constants

  • PATTERN_LITERAL

  • PATTERN_PREFIX

  • PATTERN_SIMPLE_GLOB

and it specifies that the path argument is to be interpreted as a

respectively.

Whether adding a path using this method will actually have any effect effect on the matching of an Intent’s data URI depends on the rules outlined here.

6.4 Data Types

A MIME type can be added to the IntentFilter’s set of data types using the method

    public final void addDataType(String type)

Unlike the methods used to set explicitly the data type of an Intent, the format of the type argument is verified.

It must be of the form

    <type> '/' <sub-type>

Both the type and the sub-type must at least of length one.

Both the type and the sub-type can be the wildcard character '*', in which case it specifies the wildcard type which matches any type.

Alternatively only the sub-type may be the wildcard character in which it case it matches any sub-type of the given type.

6.5 Categories

A category can be added to the IntentFilter’s set of categories using the method

    public final void addCategory(String category)

The format of the category argument is not checked, although it cannot be null.

7. Matching

An IntentFilter can be used to match the following constituents of an Intent, either individually or collectively.

  • the action

  • the data

  • the data type

  • the categories

7.1 Method Return Values

Some IntentFilter matching methods return an integer status, a negative value indicating that the match failed, a positive value that the match succeeded.

7.1.1 Matching Failures

A matching failure is specified using the value of one of the IntentFilter class constants

Class Constant Value Reason
NO_MATCH_TYPE -1 type did not match
NO_MATCH_DATA -2 data did not match
NO_MATCH_ACTION -3 action did not match
NO_MATCH_CATEGORY -4 categories did not match

7.1.2 Matching Success

The integer value returned when a match succeeded can comprise two parts.

The top twelve bits always specifies the match category, that is, what matched, and the bottom sixteen bits may specify a quality adjustment

The possible values of the match category part are defined by the following class constants

Class Constant Value
MATCH_CATEGORY_EMPTY 0x100000
MATCH_CATEGORY_SCHEME 0x200000
MATCH_CATEGORY_HOST 0x300000
MATCH_CATEGORY_PORT 0x400000
MATCH_CATEGORY_PATH 0x500000
MATCH_CATEGORY_TYPE 0x600000

Although the constant returned is dependent on what matched in a given context, the distinction being made may not be that useful.

For example, the documentation for MATCH_CATEGORY_HOST reads

The filter matched an intent with the same data URI scheme and authority host.

which is true when it is returned from matchData() but not matchDataAuthority().

The documentation for MATCH_CATEGORY_TYPE reads

The filter matched an intent with the same data MIME type.

which is true as far as it goes.

MATCH_CATEGORY_TYPE is only ever returned by the method matchData() and it certainly will not return it if the IntentFilter does not match the given type, but it can mean anything from there was only a type given and it matched up to everything matched, that is, scheme, host, port, path and type all matched.

The IntentFilter class constants

    MATCH_ADJUSTMENT_MASK

and

    MATCH_CATEGORY_MASK

specify the bit masks to use to extract the respective parts.

7.2 Matching Against An Action

An IntentFilter can be used to match against an action using the IntentFilter method

    public final boolean matchAction(String action)

This method will return true if and only if the action is not null and it is a member of the IntentFilter’s set of actions.

Note

The method documentation is actually contradictory. It states that

If the filter does not specify any actions, the match will always fail.

which is correct.

It then goes on to say that it returns

True if the action is listed in the filter or the filter does not specify any actions. [Emphasis added]

the second part of which is not.

7.3 Matching Against A Data Type, Scheme, and URI

An IntentFilter can be used to match against a data type, scheme and URI using the IntentFilter method

    public final int matchData(String type, String scheme, Uri data)

The method first attempts to match against the scheme and the URI and then, against the type.

7.3.1 Matching The Scheme And URI

7.3.2.1 Case: Non-Empty Set Of Schemes

If the IntentFilter specifies one or more schemes then the match will succeed

  • if the scheme argument is non-null and it is a member of the IntentFilter’s set of schemes, or

  • it is null and the empty String (“”) is a member of the IntentFilter’s set of schemes.

7.3.2.1.1 Case: Non-Empty Set Of Schemes And Non-Empty Set Of Authorities

If the IntentFilter specifies one or more schemes and the scheme matching succeeds, then if it also specifies one or more authorities, the match will succeed if one of the specified authorities matches the authority part of the URI. The matching is done using the matchDataAuthority() method.

7.3.2.1.1.1 Case: Non-Empty Set Of Schemes And Non-Empty Set Of Authorities And Non-Empty Set Of Paths

If the IntentFilter specifies one or more schemes and the scheme matching succeeds, and it specifies one or more authorities and the authority matching succeeds, then if it also specifies one or more paths the match will succeed if the data URI has a path part which at least one of the specified paths matches.

7.3.2.2 Case: Empty Set Of Schemes And Non-Empty Set Of Types

If the IntentFilter does not specify any schemes then the match will succeed if the value of the scheme argument is one of the following

  • null

  • “” (the empty String)

  • “content”

  • “file”

7.3.2 Matching The Type

If the matching of the scheme and URI succeeds then the type is matched.

7.3.2.1 Case: Non-Empty Set Of Types

If the IntentFilter specifies one or more types then the match will succeed if one of the specified types matches the type argument.

A specified type will match the type argument

  • if it is equal to it

  • if it is the wildcard type (*/*)

  • if it is a type/wildcard pair (<type>/*) which matches.

For example, given

    IntentFilter f1 = new IntentFilter();
        
    f1.addDataType("image/png");
	
    IntentFilter f2 = new IntentFilter();
            
    f2.addDataType("*/*");
	
    IntentFilter f3 = new IntentFilter();
            
    f3.addDataType("image/*");

the following matches all succeed

    f1.matchData("image/png", null, null) // returns 0x608000

    f2.matchData("image/png", null, null) // returns 0x608000

    f3.matchData("image/png", null, null) // returns 0x608000

Rather less obviously the match will also succeed if the type argument is

  • the wildcard type (*/*), or

  • a type/wildcard pair (<type>/*) which matches a type/sub-type pair specified by the IntentFilter.

For example given

    IntentFilter f = new IntentFilter();
        	
    f.addDataType("image/png");

then the following both succeed

    f.matchData("*/*", null, null)     // returns 0x608000

    f.matchData("image/*", null, null) // returns 0x608000

The format of the type argument is not checked but if it is not in the type/sub-type format the match will fail.

For example, given the same IntentFilter as above

    IntentFilter f = new IntentFilter();
        	
    f.addDataType("image/png");

then this fails

    f.matchData("image", null, null) // returns -1

despite the fact that there is an argument for saying that image and image/* are pretty much the same thing,

It is worth noting this because when the data type of an Intent is set explicitly the format is not checked, so it quite feasible to set it to something like image.

7.3.2.2 Case: Empty Set Of Types And Non-Empty Set Of Schemes

If the IntentFilter does not specify any types then the match will only succeed if the type argument is null.

7.3.3 Edge Case (Strange But True): Empty Set Of Schemes And Empty Set Of Types

The method actually looks for this edge case first.

If the IntentFilter does not specify any schemes or types and the data and type arguments are both null then the match will succeed for any value of the scheme argument.

For example

    new IntentFilter().matchData(null, "http", null) // returns  0x108000

and also

    new IntentFilter().matchData(null, "not really a scheme at all", null) // returns 0x108000

If the data and type arguments are not both null the match will fail.

7.4 Matching Against A Data Authority

An IntentFilter can be used to match against the authority part of a URI using the IntentFilter method

    public final int matchDataAuthority(Uri data)

The match will succeed if the IntentFilter specifies one or more authorities, the URI specifies a host, or a host and a port, and at least one of the specfied authorities matches the host, or host and port, specified by the URI.

An authority will match the URI if

  • the URI specifies a host and a port, the authority specifies a host and a port, and they match, or

  • the URI specifies a host, it may or may not specify a port, the authority only specifies a host, and the specified hosts match

Note

Although the documentation is adamant that

[the] host name in the Android framework is case-sensitive, unlike formal RFC host names

nobody seems to have told the source code of this method which is using the String method

    public int compareToIgnoreCase(String string)

to do the matching of the hosts, so given

    IntentFilter f = new IntentFilter();
        
    f.addDataAuthority("justanapplication.wordpress.com", null);

and

    Uri uriLC  = new Uri.Builder().scheme("http").authority("justanapplication.wordpress.com").build();
    Uri uriMC  = new Uri.Builder().scheme("http").authority("JustAnApplication.WordPress.Com").build();
    Uri uriUC  = new Uri.Builder().scheme("http").authority("JUSTANAPPLICATION.WORDPRESS.COM").build();

then the following all succeed

    f.matchDataAuthority(uriLC) // returns 0x300000
	
    f.matchDataAuthority(uriMC) // returns 0x300000
	
    f.matchDataAuthority(uriUC) // returns 0x300000

7.5 Matching Against A Set Of Categories

An IntentFilter can be used to match against a set of categories using the IntentFilter method

    public final String matchCategories(Set<String> categories)

The match will succeed if the set specified by the categories argument is equal to, or a sub-set of, the set of categories specified by the IntentFilter.

If the match fails the method will return the first category in the categories argument which is not a member of the set of categories specified by the IntentFilter.

If the match succeeds then the method will return null.

For example, assuming there are four categories defined by the class constants

  • CATEGORY_FOO

  • CATEGORY_BAR

  • CATEGORY_BAZ

  • CATEGORY_MUMBLE

five Intents constructed as follows

    Intent i0 = new Intent();
    Intent i1 = new Intent().
                    addCategory(
                        CATEGORY_FOO);
    Intent i2 = new Intent(i1).
                    addCategory(
                        CATEGORY_BAR);
    Intent i3 = new Intent(i2).
                    addCategory(
                        CATEGORY_BAZ);
    Intent i4 = new Intent(i3).
                    addCategory(
                        CATEGORY_MUMBLE);

and an IntentFilter constructed as follows

    IntentFilter f = new IntentFilter();
        
    f.addCategory(CATEGORY_FOO);
    f.addCategory(CATEGORY_BAR);
    f.addCategory(CATEGORY_BAZ);

then the following

    f.matchCategories(i0.getCategories())    // null
	
    f.matchCategories(new HashSet<String>()) // empty set

    f.matchCategories(i1.getCategories())    // sub-set

    f.matchCategories(i2.getCategories())    // sub-set

    f.matchCategories(i3.getCategories())    // equals

will all match and return null, and this

    f.matchCategories(i4.getCategories())

will not match and will return the value of CATEGORY_MUMBLE.

Note especially that if the set of categories to match is null or empty then the match will always succeed.

7.6 Matching Against An Intent

An IntentFilter can be used to match against all the constituent parts of an Intent using the IntentFilter method


    public final int match(
                         String      action, 
                         String      type, 
                         String      scheme,
                         Uri         data, 
                         Set<String> categories, 
                         String      logTag) 

It is this method that the system uses to match IntentFilters against the parts of an Intent.

The method uses the matchAction(), matchData() and matchCategories() methods in combination to determine whether there is a match, but with one subtle difference.

While this will fail

    new IntentFilter().matchAction(null)   // returns false

this will not

    new IntentFilter().match(null, null, null, null, null, null)   // returns 0x108000

Copyright (c) 2010 By Simon Lewis. All Rights Reserved.

December 12, 2010

The Android Intent Based APIs: Part Two – The Intent class

Filed under: Android, Intents, Java, Mobile Java — Tags: , , , — Simon Lewis @ 11:50 am

An Intent is represented by an instance of the class

    android.content.Intent

1. Construction

The Intent class defines no less than six constructors.

  • Intent()

  • Intent(Intent o)

  • Intent(String action)

  • Intent(String action, Uri uri)

  • Intent(Context packageContext, Class cls)

  • Intent(String action, Uri uri, Context packageContext, Class cls)

Intent instances are mutable so only the default constructor is actually necessary. The other five are effectively convenience constructors. The same effect could be achieved by using the default constructor and setting the other values explicitly.

Note also that it is not possible to construct an Intent with a specific data type, or set of categories or flags, or with extras. The Intent must be created first and then the data type and/or categories and/or flags and/or extras set using the appropriate accessors.

2. Constituent Parts

2.1 Action

An Intent’s action is represented by a String which specifies a qualified name.

An Intent can be constructed with a specific action, using either this, this, or this, or the action can be set explicitly using the method

    public Intent setAction(String action)

2.2 Data And Data Type

An Intent’s data is represented by an instance of the class

    android.net.Uri

An Intent’s data type is a MIME type which is represented by a String of the form

    <type> '/' <sub-type>

as per RFC 2045, at least that is the theory. In practice, not so much, as there is no validation being done, at least not at the point the data type is set.

Note that both URI and MIME type comparison is case-sensitive in the context of Intents.

2.2.1 Setting

An Intent’s data URI can be set using the method

    public Intent setData(Uri data)

If the scheme of the data URI is

    content 

then the MIME type of the data specified is derived from the URI.

For any other scheme the data type is null by default.

The data URI can be set in conjunction with an explict type using the method

    public Intent setDataAndType(Uri data, String type)

Conversely an Intent’s data type can be set without setting its data URI using the method

    public Intent setType(String type)

This method and the setData(Uri) method are mutually exclusive. Setting the type will unset the data URI and vice-versa.

2.2.2 Getting

The method

    public Uri getData()

returns the Intent’s data URI if any.

There is also a convenience method

    public Uri getDataString()

which returns the data URI as an encoded String, as well as one

    public String getScheme()

which returns the scheme, if any, of the data URI.

The method

    public String getType()

will return the Intent’s data type, but if and only if it was set explicitly using either the method setDataAndType() or the method setType().

2.3 Categories

An Intent’s categories are represented by a Set of Strings, each String being a qualified name

A category can be added to the Intent’s set of categories using the method

    public Intent addCategory(String category)

or removed using the method

    public void removeCategory(String category)

The method

    public Set<String> getCategories()

can be used to get the set itself, and strangely enough the return value is the actual set held by the Intent.

The method documentation contains the admonishment

Do not modify!

which is not quite as effective as simply not returning the actual set in the first place.

2.4 Flags

An Intent’s flags are represented by specific bits set within an integer value.

An Intent’s flags can be set using the method

    public Intent setFlags(int flags)

Alternatively a flag can be added to the Intent’s current set of flags using the method

    public Intent addFlags(int flags)

2.5 Extras

There are a plethora of methods for setting, getting, replacing, and removing an Intent’s extras.

2.5.1 Setting

Setting the value of an extra can be done using a method of the form


    public Intent putExtra(String key, Type value);

where Type can be any one of the following.

  • Bundle

  • CharSequence

  • Parcelable

  • Parcelable[]

  • Serializable

  • String

  • String[]

  • boolean

  • boolean[]

  • byte

  • byte[]

  • char

  • char[]

  • double

  • double[]

  • float

  • float[]

  • int

  • int[]

  • long

  • long[]
  • short

  • short[]

As if this was not sufficient there are also methods of the form


    public Intent putTypeArrayListExtra(String key, ArrayList<? extends Type> value);

where Type can be any one of the following

  • CharSequence

  • Integer

  • Parcelable

  • String

And for good measure it also possible to set multiple extras simultaneously using either the method


   public Intent putExtras(Bundle extras)

or the method


   public Intent putExtras(Intent src)

2.5.2 Getting

There are corresponding methods for getting the value of an extra.

If the extra is an object type then the corresponding method is of the form.


    public Type getTypeExtra(String name)

If there is no extra of the given name the method will return null.

If the extra is an array type then the corresponding method is of the form.


    public Type[] getTypeArrayExtra(String name)

If there is no extra of the given name the method will return null.

If the extra is a primitive type then the corresponding method is of the form.


    public Type getTypeExtra(String name, Type defaultValue)

If there is no extra of the given name the method will return the supplied default value.

All of an Intent’s extras can be obtained as a Bundle by calling the method


    public Bundle getExtras ()

2.5.3 Replacing And Removing

It is possible to replace all of an Intent’s extras with those contained in a given Bundle using the method


    public Intent replaceExtras(Bundle extras)

or with all the extras from another Intent using the method


    public Intent replaceExtras(Intent src)

Passing null to the first method or an Intent with no extras to the second will result in the removal of all the Intent’s extras.

A specific extra can be removed from an Intent using the method


    public void removeExtra (String name)

2.6 Component

An Intent can be constructed with the name of the Component to which it should be sent specified explicitly, see this, or this, or it can be set explicitly using one of the following methods.

  • public Intent setClass(Context packageContext, Class<?> cls)

  • public Intent setClassName(Context packageContext, String className)

  • public Intent setClassName(String packageContext, String className)

  • public Intent setComponent(ComponentName component)

The first three methods are convenience methods. They are simply wrappers around the corresponding ComponentName constructors.

2.7 Package

It is possible to constrain the set of Components to which an Intent can be sent using the method

    public Intent setPackage(String packageName)

The argument specifies the name of the Application package to search for Components to which the Intent should be sent.

3. Cloning And Copying

An Intent can be copied using the copy constructor, or it can be cloned using the

    public Object clone() 

method, which amounts to the same thing as it simply calls the copy constructor.

There is also a

    public Intent cloneFilter() 

method, which, in the words of the method documentation, makes

a clone of only the parts of the Intent that are relevant for filter matching: the action, data, type, component, and categories.

In practice what this amounts to is that the resulting Intent does not contain either the flags or the extras from the original Intent.

There is also a more elaborate method

    public int fillIn(Intent other, int flags) 

which can be used to selectively copy parts of another Intent.

The flags specified by the the following class constants can be bitwise or-ed and passed as the flags argument.

  • FILL_IN_ACTION

  • FILL_IN_CATEGORIES

  • FILL_IN_COMPONENT

  • FILL_IN_DATA

  • FILL_IN_PACKAGE

The basic principle of operation is that the value of a constituent part in the other Intent will be copied if it is not null, and

  • the corresponding part in the Intent on which the method is called is null, or

  • the flag corresponding to that part is set in the flags argument.

To make life more interesting this is not true for the Intent’s flags which are bitwise or-ed together come what may, or the component which will only be copied if the corresponding flag, FILL_IN_COMPONENT in this case, is set in the flags argument.

The return value is a set of flags identifying which parts were actually set.

4. Equality

The Intent class does not override the

    public boolean equals(Object o)

and

    public int hashCode()

methods, so using Intents as keys in a Hashtable, for example, is not a good idea.

Instead it defines the methods

    public boolean filterEquals(Object other)

and

    public int filterHashCode()

The methods are documented as using only the

action, data, type, class, and categories

for the purposes of testing for equality, or computing the hash code, but in each case this is not entirely true. Each method also acts upon the component and package parts if present.

5. URIs

One of the more arcane pieces of functionality supported by Intents is the ability to turn an Intent into a URI and vice-versa.

It is left as an exercise for the reader to identify those places, if any, in the system where this functionality is actually used.

5.1 Converting An Intent to a URI

An Intent can be converted to a URI using the method

    public String toUri(int flags)

The resulting URI is basically the data URI of the Intent with a new fragment suffix.

For example,


    new Intent(
        "xper.action.TO_URI", 
        new Uri.Builder().
            scheme(
                "http").
            authority(
                "justanapplication.wordpress.com").
        build()).
    toUri(0))

returns the string

    https://justanapplication.wordpress.com#Intent;action=xper.action.TO_URI;end

There is only one non-zero value which can be passed as the flags argument. It is defined by the class constant


    URI_INTENT_SCHEME

Using it causes the resulting URI to have the intent scheme.

For example,


    new Intent(
        "xper.action.TO_URI", 
        new Uri.Builder().
            scheme(
                "http").
            authority(
                "justanapplication.wordpress.com").
        build()).
    toUri(Intent.URI_INTENT_SCHEME))

returns the string

    intent://justanapplication.wordpress.com#Intent;scheme=http;action=xper.action.TO_URI;end

If the Intent does not contain a data URI then only the fragment is returned, although it is arguable whether a fragment on its own is actually a legal URI.

The fragment will specify everything present in the Intent although in the case of extras only primitive types and Strings will be included.

5.2 Constructing An Intent From a URI

An Intent can be constructed from a URI by using the method

    public static Intent parseUri(String uri, int flags)

Like the toUri(int) method the only legal non-zero value for the flags argument is the value of URI_INTENT_SCHEME.

If the URI does not end with a fragment in the format generated by the toUri(int) method then it will be used as the data URI of the resulting Intent.

The round trip from Intent to URI string to Intent is not guaranteed to be exact. Given an Intent i, then

    i.filterEquals(Intent.parseUri(i.toUri(0), 0))

may return either true or false depending upon the contents of i.

6. Class Constants

6.1 Pre-defined Actions

A large number of actions are predefined by the system using class constants of the form

    ACTION_<name>

The documentation for each definition specifies its semantics when used by the system.

Applications can also define their own actions as they see fit. There are numerous examples through out the Android source code.

6.2 Pre-defined Categories

A number of categories are predefined by the system using class constants of the form

    CATEGORY_<name>

Applications can also define their own categories, but they cannot be used to affect the behaviour
of the system in the same way as some of the pre-defined categories do.

6.3 Pre-defined Extra Keys

A number of extra keys are predefined by the system using class constants of the form

    EXTRA_<name>

Applications can re-use these if they choose or define their own as necessary. As with actions there are numerous examples through out the Android source code.

6.4 Flags

The values which can be bitwise-or-ed together and passed to the setFlags(int) method are defined
by class constants of the form

    FLAG_<name>

The set of possible values is effectively fixed by the system. Depending upon the underlying implementation it might be possible for an Application to use some of the currently unused values for its own purposes, but this is obviously not a good idea, and also unnecessary given the ability to specify arbitrary data via extras.

7. The Source Bounds Mystery

In addition to the parts described above an Intent may contain one additional thing, an instance of android.graphics.Rect.

There is a method to get it

    public Rect getSourceBounds()

and a method to set it

    public void setSourceBounds(Rect r)

There is even a flag

    FILL_IN_SOURCE_BOUNDS

that can be used in conjunction with the fillIn(Intent,int) method.

It is copied by the copy constructor and represented in the URI string created from an Intent but what exactly is it for ?

According to the method documentation it specifies

the bounds of the sender of this Intent, in screen coordinates

It is not a historical artefact since it was added to Android 2.1, API Level 7 so its only been around for about the last year.

Given that extras can be used to pass almost anything at all and most definitely a Rect, why add a dedicated field for something which has such limited applicability ?

A brute force search of the Android source code turns up a handful of places where it is being used. In one place it looks as though it is being used as a replacement for using an extra, but on the face of it there does not seem to be a compelling reason why, especially given that other data is still being transferred as extras.

To possibly misquote someone or other it looks not unlike a hack.


Copyright (c) 2010 By Simon Lewis. All Rights Reserved.

December 5, 2010

The Android Intent Based APIs: Part One – Intents

Filed under: Android, Intents, Java, Mobile Java — Tags: , , , , — Simon Lewis @ 10:16 am

1. The Intent Model

  • An Intent is a message which can be sent between Android application components. The components can be in different Applications, or in the same one.

  • An Intent can function as either an operation, that is, it causes something to happen, or an event, that is, it indicates that something has happened.

  • An action is a unique identifier which can be used to specify either an operation to be performed by the recipient, or an event that has occurred, depending upon the context

  • A category is a unique identifier which is used by the system to specify a role within the Android Application/Component model that can be played by the recipient of an Intent.

  • A component can specify the Intents it wishes to receive using a filter.

  • A filter can specify the Intents to be received in terms of actions and/or categories.

  • When a category is specified by a component in a filter it specifies to the system the role or roles the component can play within the Application/Component model.

  • A component can specify that it should only receive Intents from components that are contained within applications that have been granted a specific permission.

  • An Intent can be sent to a single component, or to multiple components, depending upon the context in which it is used.

  • A component can specify the destination of an Intent explicitly using a component name.

  • An implicit Intent is an Intent which does does not contain the name of the component to which it should be sent

  • An explicit Intent is an Intent which contains the name of the component to which it should be sent

  • If the destination of an Intent is not explicitly specified, then the component or components to which it should be sent is/are determined dynamically using Intent resolution.

  • The system will, if necessary, automatically start an application containing a component which is the destination of an Intent.

  • A component can specify that an Intent only be sent to a component or components that has/have been granted a specific permission.

  • An Intent can contain

    • an action

    • data

    • the type of the data

    • a category or categories

    • the name of the component to which it should be sent

    • a collection of arbitrary data termed extras

    • a set of flags

  • Qualified names are used as unique identifiers.

  • A qualified name is akin to a Java package name or fully scoped class name, that is, it is a name of the form

    
        <qualified-name> := <prefix>  identifier
    
        <prefix>         := <qualified-name> '.' | <empty>
    	
    
  • Subject to the constraints imposed by the system on the ways in which Intents can be used, Applications are free to define the semantics of Intents in any way they choose.

2. Intent Constituents

2.1 Action

An Intent may contain an action. If present it is specified using a qualified name

The system pre-defines a number of actions but Applications can also define additional ones if they choose.

2.2 Data

An Intent may contain data. This is a somewhat misleading term since, if present, it is actually specified using a URI.

The URI can be used to identify what an operation should be performed upon, or what an event refers to.

2.3 Categories

An Intent may contain a set of categories. When specified by an Intent these are primarily used by the intent resolution process as part of the selection criteria.

A category is specified by a qualified name.

The system pre-defines a number of categories. Applications can define additional categories if they choose, but they cannot be made to affect the behaviour of the system in the same way as the built-in ones.

2.4 Component

An Intent may contain the name of the component to which it should be sent. If present this is specified as a package/class name pair.

2.5 Extras

An Intent may contain arbitrary data in the form of key/value pairs. Each key is specified as a qualified name. A value may be any of the primitive data types, a character sequence, a string, a parcelable object or a serializable object, or an array of any of these types, with the exception of serializable objects.

The system pre-defines a number of extras keys but Applications can also define additional ones if they choose.

2.6 Flags

An Intent can contain a set of flags. These are a form of meta-data and are not intended for use by the recipient(s) of the Intent. Instead they are used to affect aspects of the system’s behaviour with respect to the handling of the Intent and its recipient or recipients.

The set of flags that can be used is defined by the system. Applications cannot define their own flags.

3. Intent Resolution

The system determines the recipient or recipients(s) of an implicit Intent using the criteria specified by the currently defined set of component filters.

In addition to actions and categories a component’s filter may also specify as selection criteria

  • data types

  • data URI schemes

  • data URI authorities

  • data URI paths either as literals or patterns

For any given implicit Intent there is no guarantee that a matching component or components will be found.


Copyright (c) 2010 By Simon Lewis. All Rights Reserved.

Blog at WordPress.com.