9

I have seen numerous answers on here about creating an intent filter for a custom file extension, but none of them seem to be answering my question:

I have an intent filter that works right now... when I browse for my file or when I open it from an email attachment, my app will appear in the list. The file itself has a custom extension of "tgtp", but it is basically just an xml file.

The problem I am having is that although this intent filter works, it also appears to add my app to every chooser for every type of file on my phone. An example would be if I clear my contacts app defaults and click on one of my contacts, it says my app can open it.

I've tried dozens of different combinations of intent filters with different schemes, mime types, etc... and some still let me open the file if i browse with a file browser, but I specifically need to be able to open email attachments and open as file browser. I am yet to find an intent filter(s) that allow me to do that without making my app available for every other intent chooser.

Here is my current intent-filter that uses my app to open everything:

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

Thank you in advance

Nick
  • 1,262
  • 1
  • 17
  • 32

4 Answers4

16

The only way to solve this problem is add scheme and host attributes to your intent filter:

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

That is because in documentation says that android:pathPattern only works if has an scheme and host defined. http://developer.android.com/guide/topics/manifest/data-element.html

Hope it helps.

sabadow
  • 5,095
  • 3
  • 34
  • 51
  • 2
    And of course this is something I've read numerous times but still failed to do it... This worked like a charm. I think I was confused because of the dozens of questions like this with dozens of different answers. Thank you for pointing out the simple and well documented soluction:) – Nick Mar 05 '12 at 16:49
  • This worked for you? I have EXACTLY the same circumstances and needs as the issue stated above. When my intent filter has scheme, mimeType, and host as shown in this answer- it does not work at all for any scenario. If I remove the mimeType from your answer, then the solution works for files opened in a File Explorer. I still need to be able to open these type files as attachments in email. Was this answer generalized and I need to actually provide certain mimeTypes and hosts, or was I supposed to put exactly what is shown (because that did not work) – gauglerb Jan 04 '14 at 21:02
  • Really it is a best answer.I was searching about it last 2 days but lot of answers are there and most of them not working and so much complicated,but u defined it in few lines.Now i want to make my app a default app for .mp3 file,So when user click on a mp3 file my app should open and play that file..how it is possible?? – neeraj kirola Aug 27 '14 at 11:23
  • This won't open the custom attachment in Gmail, which needs **android:host="gmail-ls"** – IgorGanapolsky Oct 20 '17 at 15:42
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
  • 680
  • 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:30
  • Why do you stop at four ".*m"s? I don't understand the significance. Does that limit you to four m's before the "message" pattern? – JoshNaro Oct 15 '14 at 16:20
  • 1
    @JoshNaro Hi, Josh. I stopped at four ".*m"s because I didn't feel like typing any more. =) I put ellipses under that line to try to imply that you would continue with that pattern for as much accuracy as you desired. If you were to stop at the four ".*m"s, then you would, indeed, be limited to four "m"s before the message pattern. This is certainly not a pretty solution, but it is the only work around for the limitation introduced by PatternMatcher's failure that I have found thus far. – benjamin davis Oct 20 '14 at 14:14
0

I have the exact same problem, and in my case, both other answers don't work. The closest I came is when I combine both benjamin and sabadow's answers, -and- leave out the dot in the extension, so like this: (i'm using my custom ".trk" extension)

        <!-- For opening/viewing only trk-files: (works in google drive and "File Manager", not  gmail) -->
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <action android:name="android.intent.action.SEND" />
            <action android:name="android.intent.action.SEND_MULTIPLE" />
            <action android:name="android.intent.action.SENDTO" />

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

            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*t.*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*t.*t.*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*t.*t.*t.*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*t.*t.*t.*t.*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*t.*t.*t.*t.*t.*trk" android:host="*" />
            <data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*t.*t.*t.*t.*t.*t.*t.*trk" android:host="*" />
        </intent-filter>          
        <!-- For catching attachments in Gmail: (also triggers non-trk-files that aren't associated with some other app, but not non-trk-files that already have one of more associations, strangely) -->
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <action android:name="android.intent.action.SEND" />
            <action android:name="android.intent.action.SEND_MULTIPLE" />
            <action android:name="android.intent.action.SENDTO" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:mimeType="*/*" android:scheme="content" />
        </intent-filter>
        <!-- For catching share actions from apps: (also triggered by sharing actions for all other file types) -->
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />

            <data android:mimeType="application/*" />
        </intent-filter>

It's a bit long, but you might not need all lines, like the SENDTO and SEND_MULTIPLE actions. I just need it to work in all cases where it could work. Sadly it also triggers in some, but not all, other cases.

0

One possible answer is shown here . Basically, try the following intent filter inside the desired activity tag to open:

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

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

    <data android:host="*" />
    <data android:mimeType="application/octet-stream" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\..*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\.yourextension" />
    <data android:scheme="content" />
</intent-filter>
Ráfagan
  • 2,165
  • 2
  • 15
  • 22