• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps [Tutorial] Associate App with file extension

mherrmann

Lurker
Hi,

has anybody ever really figured out how intent filters with the <data> element work? I have an app that I want to associate with a particular file ending (.pdt, say). The intent-filter sub-element <data> allows one to do this.

If I have understood the Android Documentation on the subject (search for "Data test") correctly, each Intent object that is evaluated by the intent filter can have a Uri (such as content://com.example.project:200/folder/subfolder/etc) or a MIME type (such as text/plain) set, or both. One weird thing is that an Intent object with both a MIME type and a Uri set can only be matched by a filter that also specifies both a MIME type and a Uri. Another weird thing is that according to the documentation, an Intent object that contains a Uri but no MIME type cannot contain any actual data, so must be a Uri like mailto: or tel:.

By reasoning about the above, here I think is what needs to be defined in order to associate an app with a particular file ending:

a. We can ignore Intent objects without a Uri or MIME type set as these cannot refer to a "file" with our file ending.

b. We can likewise ignore Intent objects with only a Uri set because as mentioned above they supposedly cannot contain any actual data.

c. From b., we know that any Intent object referring to actual data must have at least the MIME type set. In order to match based on file ending, we need to match on the path of the Uri. This can be done with the following intent-filter:

[HIGH]
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.pdt" android:mimeType="*/*" />
</intent-filter>[/HIGH]

The reason we supply a scheme and a host is that according to the documentation, the path(Pattern) is only meaningful when the other two attributes are also defined. If we don't supply them, Android ignores our pathPattern.

Now, a problem is that the * in the pathPattern is not greedy. This means that the above pathPattern won't match Uris containing more than one dot '.', such as content://foo/bar/one.two.pdt. :( Because of this, we also need to duplicate the above filter for two dots in the path, three dots etc.:

[HIGH]
<!-- Support two dots in file name: -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\..*\\.pdt" android:mimeType="*/*" />
</intent-filter>
<!-- Support three dots in file name: -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\..*\\..*\\.pdt" android:mimeType="*/*" />
</intent-filter>[/HIGH]

d. Finally, we need to match Intent objects with only a MIME type defined. For me, the following filters seem to do the trick:

[HIGH] <intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/pdt" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/octet-stream" />
</intent-filter>[/HIGH]

Yet another caveat with the documentation that however in this case actually plays to our advantage is that a <data> element with only a MIME type specified also matches Intent objects with a content: or file: Uri, in addition to Intent objects with only the MIME type set. This prevents us from potentially having to duplicate filters with different schemes, one for content: and one for file:.

And that should hopefully be it. A final point that confused me for a while: As explained on this page, duplicate <data> elements contribute to the same filter. So,

[HIGH]<intent-filter . . . >
<data android:scheme="something" android:host="project.example.com" />
. . .
</intent-filter>[/HIGH]

is equivalent to

[HIGH]<intent-filter . . . >
<data android:scheme="something" />
<data android:host="project.example.com" />
. . .
</intent-filter>[/HIGH]

It is somewhat difficult to test the file associations of an app, but this is what I have found out through some effort. Does anybody else have any experience with this, or know of something that I missed? Please let me know, the documentation available on the net is not very good (and the whole implementation of this is just confusing!).

Thanks,
Michael
 
Have you tried to add browsable like this:

[HIGH=JAVA]
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="phandroid.com" android:scheme="http"/>
</intent-filter>
[/HIGH]
 
Back
Top Bottom