I want to be able to download a file with a particular extension from the 'net, and have it passed to my application to deal with it, but I haven't been able to figure out the intent filter. The filetype is not included in the mimetypes, and I tried using
<data android:path="*.ext" />
but I couldn't get that to work.
Intent filters are declared in the Android manifest file.
Each intent filter specifies the type of intents it accepts based on the intent's action, data, and category. The system delivers an implicit intent to your app component only if the intent can pass through one of your intent filters.
An intent is an object that can hold the os or other app activity and its data in uri form.It is started using startActivity(intent-obj).. \n whereas IntentFilter can fetch activity information on os or other app activities.
An intent filter is an expression in an app's manifest file that specifies the type of intents that the component would like to receive. For instance, by declaring an intent filter for an activity, you make it possible for other apps to directly start your activity with a certain kind of intent.
Here is how I defined my activity in my AndroidManifest.xml to get this to work.
<activity android:name="com.keepassdroid.PasswordActivity">
<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:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.kdb" />
<data android:host="*" />
</intent-filter>
</activity>
The scheme
of file
indicates that this should happen when a local file is opened (rather than protocol like HTTP).
mimeType
can be set to */*
to match any mime type.
pathPattern
is where you specify what extension you want to match (in this example .kdb
). The .*
at the beginning matches any squence of characters. These strings require double escaping, so \\\\.
matches a literal period. Then, you end with your file extension. One caveat with pathPattern is that .*
is not a greedy match like you would expect if this was a regular expression. This pattern will fail to match paths that contain a .
before the .kdb
. For a more detailed discussion of this issue and a workaround see here
Finally, according to the Android documentation, both host
and scheme
attributes are required for the pathPattern
attribute to work, so just set that to the wildcard to match anything.
Now, if you select a .kdb
file in an app like Linda File Manager, my app shows up as an option. I should note that this alone does not allow you to download this filetype in a browser, since this only registers with the file scheme. Having an app like Linda File Manager on your phone resisters itself generically allowing you to download any file type.
There's a lot of misinformation on this topic, not least from Google's own documentation. The best, and given the strange logic, possibly the only real documentation is the source code.
The intent filter implementation has logic that almost defies description. The parser code is the other relevant piece of the puzzle.
The following filters get pretty close to sensible behaviour. The path patterns do apply, for "file"
scheme intents.
The global mime type pattern match will match all types so long as the file extension matches. This isn't perfect, but is the only way to match the behaviour of file managers like ES File Explorer, and it is limited to intents where the URI/file extension matches.
I haven't included other schemes like "http"
here, but they will probably work fine on all these filters.
The odd scheme out is "content"
, for which the extension is not available to the filter. But so long as the provider states your MIME type (E.g. Gmail will pass on the MIME type for the attachment unimpeded), the filter will match.
Gotchas to be aware of:
scheme
AND the host
must be specified for path
rules to match (contrary to Google's API guide, currently).""
, which is filtered very differently to null
, is impossible to match explicitly, and can only be matched by the risky "*/*"
filter."*/*"
filter will NOT match Intents with a null
MIME type - that requires a separate filter for this specific case with no MIME type at all."content"
scheme can only be matched by MIME type, because the original file name isn't available in the intent (at least with Gmail)."data"
elements is (almost) irrelevant to the interpretation, with the specific exception of host
and port
- which do pair together. Everything else has no specific association within a "data"
element or between "data"
elements.With all this in mind, here's an example with comments:
<!--
Capture content by MIME type, which is how Gmail broadcasts
attachment open requests. pathPattern and file extensions
are ignored, so the MIME type *MUST* be explicit, otherwise
we will match absolutely every file opened.
-->
<intent-filter
android:icon="@drawable/icon"
android:label="@string/app_name"
android:priority="50" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.my-type" />
</intent-filter>
<!--
Capture file open requests (pathPattern is honoured) where no
MIME type is provided in the Intent. An Intent with a null
MIME type will never be matched by a filter with a set MIME
type, so we need a second intent-filter if we wish to also
match files with this extension and a non-null MIME type
(even if it is non-null but zero length).
-->
<intent-filter
android:icon="@drawable/icon"
android:label="@string/app_name"
android:priority="50" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<!--
Work around Android's ugly primitive PatternMatcher
implementation that can't cope with finding a . early in
the path unless it's explicitly matched.
-->
<data android:pathPattern=".*\\.my-ext" />
<data android:pathPattern=".*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>
<!--
Capture file open requests (pathPattern is honoured) where a
(possibly blank) MIME type is provided in the Intent. This
filter may only be necessary for supporting ES File Explorer,
which has the probably buggy behaviour of using an Intent
with a MIME type that is set but zero-length. It's
impossible to match such a type except by using a global
wildcard.
-->
<intent-filter
android:icon="@drawable/icon"
android:label="@string/app_name"
android:priority="50" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<data android:mimeType="*/*" />
<!--
Work around Android's ugly primitive PatternMatcher
implementation that can't cope with finding a . early in
the path unless it's explicitly matched.
-->
<data android:pathPattern=".*\\.my-ext" />
<data android:pathPattern=".*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>
I must admit that the simple task of opening attachments from emails and files from the filesystem on Android has been one of the more maddening experiences ever. It is easy to handle too many files or too few. But getting it just right is hard. Most of the solutions posted on stackoverflow didn't work correctly for me.
My requirements were:
Probably the best way to go about this task is to specify a custom MIME Type for your attachments. And you will probably also choose to have a custom file extension. So let's say that our app is called "Cool App" and we generate file attachments that have ".cool" at the end.
This is the closest I got got to my goal and it works... satisfactory.
<!-- Register to handle email attachments -->
<!-- WARNING: Do NOT use android:host="*" for these as they will not work properly -->
<intent-filter>
<!-- needed for properly formatted email messages -->
<data
android:scheme="content"
android:mimeType="application/vnd.coolapp"
android:pathPattern=".*\\.cool" />
<!-- needed for mangled email messages -->
<data
android:scheme="content"
android:mimeType="application/coolapp"
android:pathPattern=".*\\.cool" />
<!-- needed for mangled email messages -->
<data
android:scheme="content"
android:mimeType="application/octet-stream"
android:pathPattern=".*\\.cool" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<!-- Register to handle file opening -->
<intent-filter>
<data android:scheme="file"
android:mimeType="*/*"
android:pathPattern=".*\\.cool"
android:host="*"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
Notes:
pathPattern
seems to be more or less ignored for attachments (when using android:scheme="content"
). If somebody gets the pathPattern to respond only to certain patterns I would be thrilled to see how.android:host="*"
attribute.intent-filter
blocks are merged but I haven't verified this.android:scheme="http"
can be used. Note that certain browsers might mess up the android:mimeType
so experiment with android:mimeType="*/*"
and check in the debugger what is actually passed through and then tighten the filtering to not end up being that annoying app that handles everything.intent-filter
was tested with the Samsung's "My Files" app on a Galaxy S3. The FX Explorer still refuses to properly open the file and I also noticed that the app icon is not used for the files. Again, if anyone gets that to work please comment below.I hope you will find this useful and that you won't have to waste days going through all possible combinations. There is room for improvement so comments are welcome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With