97

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.

Curyous
  • 8,246
  • 12
  • 54
  • 77

15 Answers15

122

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.

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
Brian Pellin
  • 2,741
  • 3
  • 21
  • 14
  • 3
    This doesn't work here. First with mimeType="*", the package doesn't install on Android 2.1, I get a MalformedMimeTypeException. Using "*/*" fixes this, but then, this filter has no effect. I am currently testing with the Skyfire browser, which doesn't preserve the mime type of downloads, as the standard Android browser do. And when clicking on a file in the Skyfire downloads list, a simplistic VIEW intent is broadcasted with file data. And this intent filter doesn't match. – olivierg Feb 08 '11 at 12:43
  • @Brian Pellin: I was actually searching for a way to bind a mime-type to the `.kdbx` extension to allow ES file explorer to open kdbx files when I was pointed to this post. Apparently if the intent has an empty MIME type, this intent filter will not work!! Also, it's possible to have an intent with an EMPTY string as the action and just a URI. Google Docs responded to that intent, so it must be valid. – billc.cn Sep 06 '11 at 01:50
  • as another poster mentions below (+1 him, he deserves it), changing to mimeType="*/*" works. – Nick Dec 16 '11 at 16:54
  • 2
    Just to be clear, mimeType should be "\*/\*" I think some people forgot to escape their \*s – Brian Pellin Dec 22 '11 at 06:13
  • This works for Linda and OI File Manager, but does not seem to work for ES File Manager. Any ideas how to also support that one (it is a very popular one)? – Carsten Jan 18 '12 at 04:11
  • Sweet.. at last I got the answer for opening custom filetype with my own app :) This should be mark as answer.... – Tek Yin Jan 03 '13 at 07:33
  • @BrianPellin does this work with the gmail application? I cannot get it to work! – StuStirling Jan 10 '13 at 09:12
  • can you please have a look at this question? It is some what related to the question in this thread http://stackoverflow.com/questions/16441330/declaring-mime-type-for-a-custom-file-that-is-to-be-sent-via-bluetooth – neerajDorle May 10 '13 at 04:47
  • 1
    That won't work with Android 4. You should use on `` tag with four attributes. Having 4 tags is logical OR — Which worked with Android 2 — but Android 4 is more strict. See http://stackoverflow.com/questions/20650378/how-did-intent-filter-change-from-android-2-to-android-4 – Martin Dec 18 '13 at 17:26
  • Thanks! This post was very helpful! Especially the thing with the android:host="*" I had to filter .kml file and used this post.! – Moti Bartov Sep 22 '15 at 12:29
  • This approach DOES NOT work for opening gmail attachments. – IgorGanapolsky Oct 18 '17 at 18:23
  • 3
    if `\\\\.` matches a literal period, why does you not use it to form `.kdb` extension like this: `\\\\.kdb`? – Lealo Oct 19 '17 at 13:43
38

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:

  1. Be aware that nothing behaves consistently in the filters, it's a maze of special cases, and treats violation of the principle of least surprise as a design goal. None of the pattern matching algorithms follow the same syntax or behaviour. Absence of a field sometimes is a wildcard and sometimes isn't. Attributes within a data element sometimes must go together and sometimes ignore grouping. It really could have been done better.
  2. The scheme AND the host must be specified for path rules to match (contrary to Google's API guide, currently).
  3. At least ES File Explorer generates intents with a MIME type of "", which is filtered very differently to null, is impossible to match explicitly, and can only be matched by the risky "*/*" filter.
  4. The "*/*" 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.
  5. The "content" scheme can only be matched by MIME type, because the original file name isn't available in the intent (at least with Gmail).
  6. The grouping of attributes in separate "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>
Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
David Sainty
  • 1,298
  • 11
  • 10
  • Great that you stand up to the many evidenced need for \\.. over and over and other quirks. Google should have fixed this by 4.2, what the hell. Alas, I still have cases that your example doesn't seem to fix. Is there some issue with 6 cha extensions like ".gblorb" that my code works fine with 3 letters or less? – RoundSparrow hilltx Feb 08 '17 at 07:00
  • Best answer to this question and similar questions in my opinion! Sadly, as long as it is not possible to match content intents by file extension (as you point out in 5.), it is not possible to reliably filter for ALL correct intents without also matching wrong ones. This is for the case where you can not use a custom mime type. So as long as Android does not provide a solution for this it's going to be a file-chooser within the app for me... I don't want to confuse the user with inconsistent behaviour. – Benjamin Bisinger Sep 20 '17 at 10:18
  • 1
    Thanks a lot.. You just made my day.. In my case I had to change MimeType as `````` in all three options and it worked like charm for all apps including Google Drive and Gmail. – Rishabh Wadhwa May 11 '19 at 09:57
  • 1
    I'd like to thank you so much, @David Sainty . You put an end to my 24h-long agony of trying to figure out how to handle it. I tried https://stackoverflow.com/q/18577860/6110285 , https://stackoverflow.com/a/8599921/6110285 and many more which were similar. This one is the only one that worked. – pittix Apr 06 '20 at 14:03
24

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:

  • have my app handle attachments shared by my app
  • have my app handle files on filestorage that were generated by my app and have a particular extension

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:

  • The 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.
  • The Gmail app refused to list my app in the chooser if I added the android:host="*" attribute.
  • It probably still works if these intent-filter blocks are merged but I haven't verified this.
  • To handle requests from a browser when downloading a file the 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.
  • Certain File Explorers will mess up the MIME-Types for your files as well. The above 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.

omahena
  • 536
  • 4
  • 12
  • This is a working solution for me. Registering a separate for Content-Scheme and File-Scheme did the trick! Thanks! – Mehlyfication Jan 28 '15 at 14:53
  • Thanks! Worked for me. Both Gmail app and Samsung My Files app on Galaxy S6 were able to open file with my app using your solution! – Haris May 29 '15 at 03:35
  • What exactly is the "app name?" (In my case, the human-readable app name has spaces in it.) – William Jockusch Aug 18 '16 at 18:36
  • @WilliamJockusch it looks like @DavidSainty is simply storing the application name in the string resource file. Spaces should be fine. The string used for the `android:label` for the intent filter is the string that the user will see in the chooser menu. By default application name is used. – omahena Aug 22 '16 at 09:01
  • What should I use for the "Google Drive" app ? – android developer Jan 12 '19 at 12:01
  • @androiddeveloper That is really hard to say as it depends what kind of intent Google Drive app will generate. You could... Try to be "very open" to handing intents and just fill the intent filter properties with "*" values. Then when your app pops up to handle a Google Drive attachment, examine the intent that was sent and then restrict the filter according to the intent parameters you see in your app. I am not sure Android will allow this kind of intent filter... I think it will. – omahena Jan 15 '19 at 10:49
  • @omahena Never mind. I've found what, but sadly it needs a valid mimeType: ` ` . Do you know how to overcome this? – android developer Jan 15 '19 at 17:35
  • @androiddeveloper I do not... Sorry. [docs](https://developer.android.com/guide/topics/manifest/data-element#mime) say the second part of mimeType can be a wildcard. But if omitting mimeType and partial mimeType don't work... Then I am not sure what to suggest. – omahena Jan 15 '19 at 18:59
  • @omahena Indeed, and it doesn't let me this way to include only the extensions that I want to handle... – android developer Jan 15 '19 at 20:13
  • See my comment over here: https://stackoverflow.com/questions/50407193/open-custom-filetype-in-samsung-file-explorer#comment95806841_52624829 This does not work on a Samsung S8 running Android 8 unfortunately. – TomTasche Feb 03 '19 at 08:47
  • @TomTasche From your linked comment I guess it didn't work for the "My Files" / Samsung explorer on S8. It is quite possible. The Android content "push" ecosystem through intents is highly interdependent. – omahena Feb 05 '19 at 08:38
9

Brian's answer above got me 90% of the way there. To finish it off, for mime type I used

android:mimeType="*/*"

I suspect that previous posters have attempted to post the same detail, but the withough qoting the star slash star as code, stackoverflow diplays it as just a slash.

Dawson
  • 107
  • 1
  • 3
8

Rather than android:path, try android:mimeType, with a value of the MIME type of this particular piece of content. Also, android:path does not accept wildcards -- use android:pathPattern for that.

CommonsWare
  • 910,778
  • 176
  • 2,215
  • 2,253
  • "The filetype is not included in the mimetypes"? There should still be a mimetype for the type of content you're downloading, even if it doesn't use the same word. – Eric Mill Nov 15 '09 at 17:24
  • There is a mimetype for the type of content, but the file is produced by a third party application that puts a different extension on it, so I don't think it will be recognised as that mimetype. – Curyous Nov 16 '09 at 23:58
8

I've been trying to get this to work for ages and have tried basicly all the suggested solutions and still cannot get Android to recognise specific file extensions. I have an intent-filter with a "*/*" mimetype which is the only thing that seems to work and file-browsers now list my app as an option for opening files, however my app is now shown as an option for opening ANY KIND of file even though I've specified specific file extensions using the pathPattern tag. This goes so far that even when I try to view/edit a contact in my contacts list Android asks me if I want to use my app to view the contact, and that is just one of many situations where this occurs, VERY VERY annoying.

Eventually I found this google groups post with a similar question to which an actual Android framework engineer replied. She explains that android simply does not know anything about file-extensions, only MIME-types (https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0).

So from what I've seen, tried and read, Android simply cannot distinguish between file-extensions and the pathPattern tag is basicly a gigantic waste of time and energy. If you are fortunate enough to only need files of a certain mime-type (say text, video or audio), you can use an intent-filter with a mime-type. If you need a specific file-extension or a mime-type not known by Android however then you're out of luck.

If I'm wrong about any of this please tell me, so far I've read every post and tried every proposed solution I could find but none have worked.

I could write another page or two about how common these kinds of things seem to be in Android and how screwed up the developer experience is, but I'll save you my angry rantings ;). Hope I saved someone some trouble.

IgorGanapolsky
  • 23,124
  • 17
  • 109
  • 132
PeeGee85
  • 184
  • 2
  • 3
  • 1
    Upvoted you because your answer gives a useful link and the downvoter didn't leave a comment. Sorry SO can be unfriendly that way sometimes, but don't quit on it. – John Hatton Apr 10 '18 at 17:08
8

Update 2020

Android has moved towards content URIs and MIME-Types for intent filters.

The Problem

A content URI does not necessarily have to contain the file's extension or name and it will be different between different applications that are providing the content/file.

Here are some example content URIs from different email applications for the same email attachment:

Gmail -> content://com.google.android.gm.sapi/some_email@gmail.com/message_attachment_external/%23thread-a%3Ar332738858767305663/%23msg-a%3Ar-5439466788231005876/0.1?account_type=com.google&mimeType=application%2Foctet-stream&rendition=1

Outlook -> content://com.microsoft.office.outlook.fileprovider/outlookfile/data/data/com.microsoft.office.outlook/cache/file-download/file--2146063402/filename.customextention

Samsung Email App -> content://com.samsung.android.email.attachmentprovider/1/1/RAW

As can see they are all different and are not guaranteed to contain anything related to your actual file. Thus, you cannot use the android:pathPattern like most have suggested.

A work around solution for email attachments

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>

    <category android:name="android.intent.category.BROWSABLE"/>
    <category android:name="android.intent.category.DEFAULT"/>

    <data android:scheme="content"/>
    <data android:host="*"/>

    <!--  Required for Gmail and Samsung Email App  -->
    <data android:mimeType="application/octet-stream"/>

    <!--  Required for Outlook  -->
    <data android:mimeType="application/my-custom-extension"/>
</intent-filter>

Through testing I found the MIME-Types that Gmail, Outlook, and Samsung Email used and added those to my intent-filter.

Caveats/Gotchas

  • I found that with my above solution, if I opened any file that was a binary type, it would automatically launch my app. I handled this in my activity by displaying a failed state if we could not parse the file. I figured this was a pretty rare event so it would acceptable.

  • I could not find any way to launch my app via the file browser without adding <data android:mimeType="*/*"/> to my intent-filter. I couldn't use this because it would then launch my app whenever the user clicked any file on their phone (not just the custom-file-extension ones). I would not recommend adding this to your intent-filter.

Final Thoughts

  • There is currently no elegant solution for associating your app with a specific extension type in Android. This was the best that I could do in my situation.
3

None of the above work properly, for VIEW or SEND actions, if the suffix is not registered with a MIME type in Android's system=wide MIME database. The only settings I've found that fire for the specified suffix include android:mimeType="*/*", but then the action fires for ALL files. Clearly NOT what you want!

I can't find any proper solution without adding the mime and suffix to the Android mime database, so far, I haven't found a way to do that. If anyone knows, a pointer would be terrific.

hgoebl
  • 11,224
  • 7
  • 39
  • 67
3

On Android 4 the rules became more strict then they used to be. Use:

    <data
      android:host=""
      android:mimeType="*/*"
      android:pathPattern=".*\\.ext"
      android:scheme="file"
    ></data>
Martin
  • 10,876
  • 14
  • 76
  • 102
3

I've been struggling with this quite a bit for a custom file extension, myself. After a lot of searching, I found this web page where the poster discovered that Android's patternMatcher class (which is used for the pathPattern matching in Intent-Filters) has unexpected behavior when your path contains the first character of your match pattern elsewhere in the path (like if you're trying to match "*.xyz", the patternMatcher class stops if there's an "x" earlier in your path). Here's what he found for a workaround, and worked for me, although it is a bit of a hack:

PatternMatcher is used for pathPattern at IntentFilter But, PatternMatcher's algorithm is quite strange to me. Here is algorithm of Android PatternMatcher.

If there is 'next character' of '.*' pattern in the middle of string, PatternMatcher stops loop at that point. (See PatternMatcher.java of Android framework.)

Ex. string : "this is a my attachment" pattern : ".att.". Android PatternMatcher enter loop to match '.' pattern until meet the next character of pattern (at this example, 'a') So, '.' matching loop stops at index 8 - 'a' between 'is' and 'my'. Therefore result of this match returns 'false'.

Quite strange, isn't it. To workaround this - actually reduce possibility - developer should use annoying stupid pathPattern.

Ex. Goal : Matching uri path which includes 'message'.

<intent-filter>
...
<data android:pathPattern=".*message.*" />
<data android:pathPattern=".*m.*message.*" />
<data android:pathPattern=".*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*m.*message.*" />
...
</intent-filter>

This is especially issued when matching with custom file extention.

benjamin davis
  • 640
  • 6
  • 12
  • For anyone interested, an Issue has been logged at [code.google.com](https://code.google.com/p/android/issues/detail?id=69080) – benjamin davis Jun 18 '14 at 15:31
3

Brian's answer is very close, but here's a clean and error-free way to have your app invoked when trying to open a file with your own custom extension (no need for scheme or host):

<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:mimeType="*/*" />
    <data android:pathPattern="*.*\\.kdb" />
</intent-filter>
Kon
  • 25,664
  • 11
  • 56
  • 84
  • 2
    The Android documentation states that the pathPattern attribute is only meaningful if a scheme and host are specified, and I have verified this: http://developer.android.com/guide/topics/manifest/data-element.html – Brian Pellin Sep 28 '11 at 18:35
  • 4
    -1; this will match *any* file; Brian's comment is correct and with the minor modification of mimeType="*/*" his original example is perfect. – Nick Dec 16 '11 at 16:52
  • This post if from long time ago, but no "/" does not install. You need "\*/\*", which will match any file type (not sure, if you meant to say this). So your program might be asked to open videos or mp3s. I have not found a solution to this yet. – Rene Jan 22 '12 at 10:01
  • You should use one `` tag with four attributes. Your solution might work with Android 2 — but rules have become more strict: http://stackoverflow.com/questions/20650378/how-did-intent-filter-change-from-android-2-to-android-4 – Martin Dec 18 '13 at 17:28
  • What's up with the weird **pathPattern**? And `host` and `scheme` are required! – IgorGanapolsky Oct 18 '17 at 18:45
2

When an Intent meets a intent-filter, these are the intent-filter requirements: (imagine a checklist).

  • Any matching <action>
  • Any matching <category>
  • Any matching <data mimeType> (easy fix: "/")
  • Optionally:

    • Any matching <data scheme> (easy fix: <data android:scheme="file" /> <data android:scheme="content" />)

    • Any matching <data host> (easy fix: "*")

    • Any matching <data pathPattern/etc.> (for example .*\\.0cc)

Defining multiple <data $type=""> elements checks the $type box iff any <data $type=> matches the Intent.

Omitting mimeType breaks your intent-filter, even though it's seemingly redundant. Omitting <data scheme/host/pathPattern> causes your filter to match everything.

https://f-droid.org/en/packages/de.k3b.android.intentintercept/ is an app designed to receive all intents, and allows you to inspect the intent. I learned that unrecognized file extensions opened via Simple File Manager are delivered with MIME type application/octet-stream.

https://stackoverflow.com/a/4621284/2683842 reports that <data pathPattern=> .*xyz aborts at the first x it sees, and will fail immediately if not followed by yz. So /sdcard/.hidden/foo.0cc will not pass .*\\.0cc unless you try .*\\..*\\.0cc instead.

  • I did not verify whether this workaround is necessary.

End result:

<activity android:name=".Ft2NsfActivity">

    <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:scheme="content" />
        <data android:host="*" />
        <data android:pathPattern=".*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\..*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\..*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\..*\\..*\\.0cc"/>
        <data android:mimeType="*/*" />
    </intent-filter>

</activity>
nyanpasu64
  • 1,970
  • 1
  • 16
  • 27
1

If you want the files to be opened directly from Gmail, dropbox or any of the buildin android file tools, then use the following code (delete 'android:host="*"' that made the file unreachable for gmail) :

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="content" android:pathPattern=".*\\.kdb" 
          android:mimeType="application/octet-stream"/>


</intent-filter>

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="file" android:mimeType="*/*"     
          android:pathPattern=".*\\.kdb"/>
</intent-filter>

The data filter must be written in one statement as per Android version 4.x

AndreasReiff
  • 144
  • 9
  • I've been trying everything trying to get android browser download-and-open working correctly. Your solution works well for android native browser and android chrome, however android firefox still seems to open my file in a text window. It's a custom mime type and custom extension. Previously with just the extension, it only worked in firefox. Now it works everywhere except firefox (including gmail). I'm still testing it but I just wanted to flag the fact that there are a new set of cross browser issues here. – Damon Smith Mar 20 '14 at 11:14
1

Using the filter as below to open from browser, gmail & file browser (Tested). NOTE: Please do not merge two filters, that will make browser ignored your app(Tested).

        <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" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
            <data android:scheme="content" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
        </intent-filter>

        <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="http"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />
            <data android:scheme="https"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />
            <data android:scheme="ftp"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />

        </intent-filter>
Tran Hieu
  • 5,047
  • 1
  • 10
  • 10
0

Read this https://developer.android.com/training/sharing/receive , this could help to get started. then in the manifest file try the below intent filter when registering receiver in the activity to be opened

<intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="content"/>
            <category android:name="android.intent.category.BROWSABLE"/>
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="application/your_extension" />
</intent-filter>

make sure that the extension is provided without "." in it

Harsh
  • 178
  • 2
  • 11