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.

Advertisements

7 Comments »

  1. […] an Intent Filter is being declared in the context of an Activity the priority attribute cannot have a value greater than zero unless the Activity being declared is part of a […]

    Pingback by The Android Intent Based APIs: Part Four – Activities And Intents « Just An Application — February 3, 2011 @ 2:56 am

  2. […] The Intents which an Activity will start in response to are specified using Intent Filters. […]

    Pingback by The Android Intent Based APIs: Part Four – Activities And Intents « Just An Application — February 3, 2011 @ 2:56 am

  3. […] set of Intents an Activity can handle are specified by declaring intent-filter elements as children of the activity element used to declare the Activity itself in the […]

    Pingback by The Android Intent Based APIs: Part Four – Activities And Intents « Just An Application — February 3, 2011 @ 2:56 am

  4. […] can specify the Intents that can be used to interact with a given Service by defining one or more intent-filter elements as children of the service element used to define the Service […]

    Pingback by The Android Intent Based APIs: Part Five – Services And Intents « Just An Application — February 16, 2011 @ 7:47 pm

  5. […] for all those Services with an associated Intent Filter which matches the Intent, as defined by the IntentFilter.match() […]

    Pingback by The Android Intent Based APIs: Part Five – Services And Intents « Just An Application — February 16, 2011 @ 7:47 pm

  6. […] intent-filter […]

    Pingback by The Android Intent Based APIs: Part Six – Broadcast Intents « Just An Application — February 17, 2011 @ 2:52 pm

  7. […] A BroadcastReceiver can be registered with an associated Intent Filter. […]

    Pingback by The Android Intent Based APIs: Part Six – Broadcast Intents « Just An Application — February 17, 2011 @ 2:52 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: