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
Related
I'm using Xamarin, C# and Monogame and I'm taking a fully-working Desktop game and porting it over to Android.
My problem is that I have this "Content folder" that you would always use in the Desktop version of the app. But I cannot access it or any other folder through the code directly using Android.
basicShader = new Effect(game1.GraphicsDevice,System.IO.File.ReadAllBytes("Content/TextureShader.mgfxo"));
This works just fine in the Desktop app but throws System.IO.DirectoryNotFoundException:'Could not find a part of the path "/Content/TextureShader.mgfxo".' on Android.
I'd like to mention that I already had the code and the project working perfectly when it was a desktop program. I also have a private class-level variable string[] list_of_files and in the constructor, I had the line list_of_files = Directory.GetFiles("./Content","*.txt");
This is for saving and loading player data. It may have been rudimentary but I had a fully functioning program that saved and loaded data on my computer. I am transitioning this program to be an Android app and this is the only part of the project that isn't working. When I run the code as it was originally written, I get "System.IO.DirectoryNotFoundException: 'Could not find a part of the path '/Content'.' ".
I've tried playing around with trying to read the contents of different folders.
I've messed around with different paths, including the Resources folder instead.
I added <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> to my manifest.
I know that I'm trying to access internal storage, not external, so I also tried <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" /> just to see if that might work.
Nothing works.
In another stack overflow post, a guy commented:
For the people who are facing NullPointerException - you are trying to access the files in the app's internal storage which are private sorry you can't do that. –
coderpc
Jun 23, 2017 at 16:00
I cannot imagine why this would be true. Why would a programmer not be able to write a program that can access it's own internal storage? That makes no sense to me. Obviously my app needs to be able to read and write it's own internal storage! And if this is true, then how else can I save persistent data on my phone? I don't want a database or a shared thingamabobber that uses key-value pairs, I have a self-made system that works as a text file and I want to continue to use it. I refuse to believe that an Android app can't keep track of a simple .txt file in one of it's own folders, that's just too hard for me to imagine. It can't be true.
I wanted to ask the commenter about his comment but Stack Overflow wouldn't let me because I don't have over 50xp.
Just like CommonsWare sayed, you can use the Intent.ActionOpenDocument to get the uri of the file. Such as
static readonly int READ_REQUEST_CODE = 1337;
Intent intent = new Intent(Intent.ActionOpenDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType("*/*");
StartActivityForResult(intent, READ_REQUEST_CODE);
And override the OnActivityResult method:
if (requestCode == READ_REQUEST_CODE && resultCode == Result.Ok)
{
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter. Pull that uri using "resultData.getData()"
if (data != null)
{
Android.Net.Uri uri = data.Data;
DocumentFile documentFile = DocumentFile.FromSingleUri(this.ApplicationContext,uri);
// Then you can operate the file with input and output stream
}
}
More information please check the simple on the github:
https://github.com/xamarin/monodroid-samples/blob/main/StorageClient/StorageClientFragment.cs
In addition, if you can ensure the file's path. You can use the StreamWriter and the StreamReader to write and read the file. Such as:
using (StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine(content);
}
Furthermore, you can try to create the content folder and the txt file in the Android with the following code.
var filename1 = Android.App.Application.Context.GetExternalFilesDir(System.DateTime.Now.ToString("Content")).AbsolutePath;
var filename = System.IO.Path.Combine(filename1, "xxx.txt");
using (System.IO.FileStream os = new System.IO.FileStream(filename, System.IO.FileMode.Create))
{
}
The folder and the files created by this way belongs to the app and you can access it easily.
You can read the official document about the storage in the Android.
Link : https://developer.android.com/training/data-storage/shared/documents-files
Let's say I package an image with my app and I want to open it with the default image viewer/whatever image viewer the user has chosen to be the default. How would I do that?
There's already this post: Open an image using URI in Android's default gallery image viewer but many of the answers are obsolete because due to the introduction of android N, a content provider must be used.
The only answer I can find is this one:
File file = ...;
final Intent intent = new Intent(Intent.ACTION_VIEW)//
.setDataAndType(VERSION.SDK_INT >= VERSION_CODES.N ?
android.support.v4.content.FileProvider.getUriForFile(this,getPackageName() + ".provider", file) : Uri.fromFile(file),
"image/*").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
but, according to the author of this solution, this code only works for images stored externally, not ones that may be packaged with my app.
You won't be able to open an image packaged with the app (in drawable or whatever resources) through an external application. You should first copy it into (at least) an internal file storage. After that you can implement a FileProvider to provide access to this file.
Let me know if you need more details on this. Hope it helped.
I have two parts to this question: 1) what is the best solution to my need, and 2) how do I do this?
1) I have a client app which sends bundles to a service app. the bundles can break the limit on bundle size, so I need to write the actual request out and read it in on the service side. Because of this, I can't write to my private internal storage. I've used these pages heavily, and haven't had luck: http://developer.android.com/guide/topics/data/data-storage.html
http://developer.android.com/training/basics/data-storage/files.html
My current understanding is that my best path is to use this to get a public dir:
File innerDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
I then add in my filename:
String fileName = String.valueOf(request.timestamp + "_avoidRoute"+count+++".ggr");
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
fos.write(routeString.getBytes());
fos.close();
When I try to write this to disk I get the error
java.lang.IllegalArgumentException: File /storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr contains a path separator
Of course it does - I need it to have a path. I've searched online for solutions to this error which tell me to us FileOutputStream to write a full path. I did, but while my app doesn't error and appears to create the file, I'm also not able to view it on my phone in Windows Explorer, leading me to believe that it is creating a file with private permissions. So this brings me to my post and two questions:
1) Is there a different approach I should be trying to take to share large amounts of data between my client and service apps?
2) If not, what am I missing?
Thanks all for reading and trying to help!
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
This is not an appropriate use of Context's openFileOutput() method as that does not take a full path, but rather a filename within an app's private storage area.
If you are going to develop a full path yourself, as you have, then use
fos = new FileOutputStream(fullPath)
The Sharing permission setting is not applicable to the External Storage, though you will need a manifest permission to write (and implicitly read) on your creator, and the one for reading on your consumer.
Or, instead of constructing a full path, you could use your private storage with a filename and Context.MODE_WORLD_WRITEABLE (despite the being deprecated as an advisory) and pass the absolute path of the result to the other app to use with new FileInputStream(path).
Or you could use any of the other data interchange methods - content providers, local sockets, etc.
how can I use internal resource (e.g. R.drawable.myImage01) as an email attachment?
I tried the following code. It shows the file is attach but actually the email gets send without any attachment.
Context context = getApplicationContext();
String imagePath = context.getFilesDir() + "/" + "myImage01.png";
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, Uri.parse(imagePath));
Thanks
Azam
As it's an internal resource, the email client won't be able to access to that file. Thus, you have to copy the image to the SDCard, and then attach that file.
The other option would be a content provider. Use a URL like
"content://com.example.myapp/images/" + R.drawable.myImage01
and then use the provided ID to stream the content to the client.
(That is, I assume that this will work.)
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));