Android: Attaching files from internal cache to Gmail
Note: the method described in the post works well for Gmail, but apparently has some issues with other ACTION_SEND handlers (e.g. the MMS composer). A workaround is described in the comments.
I’ve just spent the day modifying one of my Android applications so that it no longer requires the use of the SD card; making it use the internal cache for what little storage is required. Everything went pretty smoothly, until I got to a part of the app that tries to share some data by sending an email with an attachment via Gmail (using an ACTION_SEND intent). Then things started behaving very oddly.
What I saw was that the Compose activity would launch correctly and my file would be shown as attached (as an example, I’ve attached a text file called Test.txt here); however when I sent the message, the attachment was not on the received email:
Or even shown in my Gmail sent folder.
A quick browse through the log showed the reason:
02-28 21:01:28.434: E/Gmail(19673): file:// attachment paths must point to file:///mnt/sdcard. Ignoring attachment file:///data/data/com.stephendnicholas.gmailattach/cache/Test.txt
So, it looks like this is something Gmail has explicitly ruled out; though I’m not sure why. At this point I could easily get all moany and ranty, but today was a glass half full day and so it was time for a workaround.
After a few false starts and a lot of searching, what I actually ended up doing was using a ContentProvider to provide access to the file from my application’s internal cache; as apparently Gmail can happily resolve attachments this way.
Unfortunately there wasn’t much example code to help me on my way, which is why I’ve decided to include a simple example here. There’s four main parts to this:
The ContentProvider that provides access to the files from the application’s internal cache. Complete code, with comments, is shown below:
As you can see, all you really need to do is to overwrite the openFile(...) method. Although you can also override the query(...) method to provide more information to the application that calls you (it would make this example unnecessarily complicated, but I’m happy to provide code on request).
To make this provider available to use, you need to add a line to your AndroidManifest.xml defining the class and the authority (symbolic name) used to reference it:
Note: this needs to go inside the <application>...</application> definition in your AndroidManifest.xml.
The utility method that creates a file in the internal cache:
The utility method that creates the intent to send the content via Gmail (explicitly using Gmail, rather than using a chooser):
The code that calls 2 & 3 to do something on a button press. Triggered in my dummy app by a button click:
Hopefully that’s all pretty straight forward, however feel free to ask any questions in the comments and I’ll help where I can.
The full source is now available as a complete (albeit very simple) Android app on github: Gmail Attacher.