So I have som data that I have converted to a string. While I have found how to attach something from the SD-card to a mail, I cant figure out how to directly convert my string to a mail-attachment without involving the SD-card. In case it holds significance, I have read some data from a database, converted it to csv-format, and now wants to attach it as a csv-file.
Cheers,
I have the same problem, i try to send a file without saving it in filesystem.
I tried to add a data uri al stream extra like this:
String fileContent = "File Content";
emailIntent.putExtra(Intent.EXTRA_STREAM,
Uri.parse("data://text/plain;base64,"+
_utils.Strings.base64_encode(fileContent)));
I used my own class to create the base64 content, but i think it will also work with:
http://developer.android.com/reference/android/util/Base64.html
It was a success in that case, that saw the atached "file" in my e-mail client.
But there are 2 problems:
1. I don`t know how to define a name for this file
2. an error occours when i try to send the file and I get a mail without attachment at the other end.
UPDATE 2015-05-13:
The mail app displays following error for my attachent:
E/Gmail(11511): java.io.FileNotFoundException: No content provider: data://text/plain;base64,
I think that means my phone is yust missing an content provider which can handle data uris.
So I think we have to create ContentProvider (see: http://developer.android.com/guide/topics/providers/content-provider-creating.html)
And implement a
openOutputStream(android.net.Uri)
to return the content of the data uri.
create a temporary file using the file API's and then you can go ahead and put it as extra in the email intent like this
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(csvFile));
Related
I have a video that I save to .../Movies/MyApp/abcde.mp4. So I know where it is. When I load it through my app using an implicit intent to ACTION_GET_CONTENT, the path is returned as content:/media/external/video/media/82 when I do
data.getData().toString()
The problem with that path is that it works when I try to access it with MediaRecorder as
mVideoView.setVideoURI(Uri.parse(mVideoStringPath))
However if I try to convert it to a path in another thread (for a job queue), the file is not found
new File(mVideoStringPath)
when I use the technique (copy and paste) described at How to get file path in onActivityResult in Android 4.4, still get the error
java.lang.RuntimeException: Invalid image file
Also per my logging, the new technique shows the path to the video as
video path: /storage/emulated/0/Movies/MyApp/abc de.mp4
notice the space in abc de.mp4. that indeed is the name of the file. And the phone's camera app has no trouble playing
However if I try to convert it to a path in another thread (for a job queue), the file is not found
That is because it is not a path to a file. It is a Uri, which is an opaque handle to some data.
How to get actual path to video from onActivityResult
You don't. You use the Uri. There is no requirement that the Uri point to a file. There is no requirement that the Uri, if it happens to represent a file, represent one that you have direct filesystem access to.
you need to escape the space the the file path in order to construct a File object from it.
filepath.replace(" ", "\\ ");
I want to send a text file in an email letter.
But the thing is that I want this file to be private for my application, and I want to give read permission only for the email app.
So, i use code:
for getting file path:
logFilePath = activity.getDir("my_logs", Context.MODE_PRIVATE) + "/log.txt";
for adding file to the email:
Uri logUri = Uri.fromFile(new File(logFilePath));
mail.putExtra(android.content.Intent.EXTRA_STREAM, logUri);
mail.setType("text/plain");
The file is created, I can see that it is attached to the letter, when I send it, but when I receive the letter there is no attachment.
I tried this options:
mail.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.grantUriPermission("com.google.android.gm", logUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
But the result is the same. I tried to
mail.setData(logUri);
Because I thought that may be the intent world read flag affects only the Data field, but the result was the same.
Then I tried to change the directory permission:
activity.getDir("my_logs", Context.MODE_WORLD_READABLE) + "/log.txt";
But it gave no effect.
The
activity.getCacheDir() + "/log.txt";
is not working too.
The only option that is working is
activity.getExternalCacheDir() + "/log.txt";
So, as I can see, the file in the internal memory is not readable for the email application no matter how I try.
Is there a way to make it readable?
Or may be there is a way to make private directory/file in the external memory?
We should use a content provider in that case. There is a pre-defined content provider for sharing files, very easy to implement: http://developer.android.com/reference/android/support/v4/content/FileProvider.html
I am using Dropbox chooser for Android.
mDropboxChooser.forResultType(DbxChooser.ResultType.FILE_CONTENT)
.launch(SendActivity.this,
DBX_CHOOSER_REQUEST_CODE);
and in onActivityResult I get the url
DbxChooser.Result result = new DbxChooser.Result(data);
Uri u = result.getLink();
but I am not sure how can I get file bytes using this Uri.
Adding Andy Res's answer as an answer, because he's right. :-)
I think you are supposed to use that Uri to open an input stream
connection, that is from where you'll get the bytes, presumably making
a HttpUriRequest.
EDIT
Also note that you should get a "direct" link, not a "preview" link if you want to download the file contents.
The final objective will be clear shortly.
I want to create a file object and instead of getting data from a real physical file I want to provide the buffer myself.
Then, I want to use this file, which does not really exist in the sdcard or anywhere outside my app, give it a name and send it by email as an attachment (using the EXTRA_STREAM).
I found the following bit of code, by Adriaan Koster (#adriaankoster), the post Write byte[] to File in Java
// convert byte[] to File
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
File fileFromBytes = (File) ois.readObject();
bis.close();
ois.close();
System.out.println(fileFromBytes);
I used it to create this function
private File fileFromBytes(byte[] buf) {
File f = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(bis);
f = (File) ois.readObject();
bis.close();
ois.close();
}
catch (Exception e) {}
return f;
}
and here is where I am stuck, because when I use it:
// When sent as body the mail is sent OK
// emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, dump());
// When I try to attach the mail is empty
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, fileFromBytes(dump().getBytes()));
I know from examples I've seen the second argument should be an URI, but: How do I create a virtual URI to fit my file?
EDIT:
The option to attach data directly from within the application is important to certain kind of applications. Namely, security & banking applications that do not want to move sensitive data around too much. Surely if the data does not reach the sdcard and goes directly to a mail attachment it is harder to sniff than within the application memory.
This is not my specific case, but I wanted to point out that this capability is important to have.
The first thing you'll want to do, I imagine, is create a ContentProvider. You can see an example implementation here
https://github.com/dskinner/AndroidWeb/blob/master/src/org/tsg/web/WebContentProvider.java
where in the above link's case, you would add this to your AndroidManifest.xml
<provider
android:name="org.tsg.web.WebContentProvider"
android:authorities="your.package.name" />
Now, you'll have a content uri available for use, content://your.package.name/.
The portion of the above ContentProvider your interested in, again I imagine, is the openFile method. When sharing data by intent across apps, certain things are expected. In your case, you're looking to share some byte data that's meant to be attached to the email.
So if you pass in a content uri to the email app such as content://your.package.name/foo with the appropriate intent flags, then openFile will get called on your ContentProvider. In this case, you can inspect the end of the uri segment to see foo was requested, and return appropriately.
The next issue you bring up is not having the file actually on disk. While I can't vouch for the method you used above (though it looks kosher), what you need to be returning is a ParcelFileDescriptor from your ContentProvider. If you look at the link I provided, you could possibly try to use that as a sample to get the file descriptor from your File object (my knowledge waivers here), but I imagine, the data simply wont be available at that point.
What you do bring up is security though. It's important to note that you can write data to disk privately so only the app has access to the data. I believe, but you might want to double check on this, if that data is private to the app, you can expose it via the ContentProvider and possibly lock down who and how the provider gets used, who can call it, etc. You may want to dig into android docs for that portion or look at some other SO questions.
Anyway, good luck.
Create the file in the application's cache directory. It will be created in the internal filesystem. Use 'getCacheDir()' API for getting the path to the cache dir. Write the data into this dir and then get the URI from the File object using ' Uri.fromFile (File file) '. When you are finished with the file, delete it.
Your application's cache is only available to your app, hence its safe to use for your purpose.
You can do some encryption if the data is too critical.
I think in order to do this, you are going to have to expose a ContentProvider, which will allow you handle a URI. The email application should then openInputStream on your URI, at which point you return an InputStream on your in-memory data.
I've not tried it, but in theory this should work.
i was busy with adding attachment to mail and i can send mail with attachment.
if you want to take a look: can not send mail with attachment in Android
I'm trying to post a notification that lets the user open a locally stored file. My code looks like this:
Intent notificationIntent = new Intent(Intent.ACTION_VIEW);
notificationIntent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(filename));
notificationIntent.setData(uri);
Where "filename" is the full path to a locally stored file, usually in the /mnt/sdcard/download directory. The files I want to display are of various types: images, PDF documents, HTML, etc.
This works, but sometimes Android tries to open the file as the wrong type. For example, a jpeg file will open in a web browser view and instead of seeing the image, I see the binary data from the file displayed as text. Other times it works file. For example, some PDF files correctly open in a PDF viewer and some do not.
I'm not sure why this is. The documentation says I should not have to pass an explicit content type. If I do set the content type explicitly, things seem to work fine. The problem is, I don't always know what the content type should be (the file is downloaded from an external source and can be anything, and no, the MIME type is not in the HTTP headers, I checked for that).
What can I do here? Is there some function I can call with a filename to have Android return me the best content type for that file? Moreover, why is this not happening automatically when the Intent is processed?
Thanks.
You've most likely figured this out; I'm posting in case someone else is stuck on this. I do the following to get the mime-type of the file:
//Get the file path
Uri path = Uri.fromFile(file);
MimeTypeMap type_map = MimeTypeMap.getSingleton();
//Get the extension from the path
String extension = MimeTypeMap.getFileExtensionFromUrl(path.toString());
extension = extension.toLowerCase();
if (extension.contains(".")) {
extension = extension.substring(extension.lastIndexOf("."));
}
String mime_type = type_map.getMimeTypeFromExtension(extension);