From here I know a way to write a file and be accessible to other app and other intent, but now that the Context.MODE_WORLD_READABLE is deprecated how can I safely accomplish this?
FileOutputStream out = myActivity.openFileOutput(fileTo, Context.MODE_WORLD_READABLE);
Okay more info:
I'm using this:
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "video/*");
And the uri will be the one that I will write to a sdcard location. And the video will come from the application so problem is, if this is now not allowed, how can I write the file and view it.
And the uri will be the one that I will write to a sdcard location.
That is already MODE_WORLD_WRITABLE by default. Also note that the code you have listed (openFileOutput()) does not write to external storage (what you incorrectly call "sdcard"). openFileOutput() is for internal storage.
And the video will come from the application so problem is, if this is now not allowed, how can I write the file and view it.
If you are really writing the file to external storage, just use a Uri pointing to that file.
If you are writing the file to internal storage, create a ContentProvider to serve that file, and use a Uri pointing to that ContentProvider. Here is a sample application with a ContentProvider that extracts a PDF file from assets/ on first run, then serves up that file via openFile() so it can be viewed by a PDF viewer.
Save your video in your internal memory using:
openFileOutput("test.mp4", "MODE_PRIVATE");
Then do this:
String path = context.getFilesDir().getAbsolutePath() + "/test.mp4"; // path to the root of internal memory.
File f = new File(path);
f.setReadable(true, false);
Intent playIntent ....
playIntent.setType("video/*");
playIntent.setData(Uri.fromFile(f));
Good Luck.
It seems to look like the docs are clear about it.
This constant was deprecated in API level 17.
Creating world-readable files is very dangerous, and likely to cause
security holes in applications. It is strongly discouraged; instead,
applications should use more formal mechanism for interactions such as
ContentProvider, BroadcastReceiver, and Service. There are no
guarantees that this access mode will remain on a file, such as when
it goes through a backup and restore. File creation mode: allow all
other applications to have read access to the created file.
Related
I want to show a file browser to the user, let him choose an arbitrary file he wants, and read it using the ZipFile class. The class requires a File object, not an InputStream.
If my research is correct, the in-built file choosers (ACTION_OPEN_DOCUMENT, etc) only provide a stream, not a File, right? Even if I get the file name from the chooser and have acquired READ_EXTERNAL_STORAGE from the user, it seems that in recent Android versions, the API only allows "only media" and reading files of other types seems to fail.
If I have also acquired MANAGE_EXTERNAL_STORAGE, then it works, but that shows a scary warning like following to the user.
Allow this app to access, modify, and delete files on the device or any connected storage devices? This app may access files without asking you.
That seems to be an unnecessarily broad permission when all I want to is a read-only access to File for a file that the user has explicitly chosen in the file browser. There is no other way than acquiring MANAGE_EXTERNAL_STORAGE, is that right? I want to make it sure, because it sounds weird. Even a very restricted environment like a web browser, the browser does not require any special permission or show any warning for reading a file that the user has explicitly selected, and the same was true for UWP app.
If my research is correct, the in-built file choosers (ACTION_OPEN_DOCUMENT, etc) only provide a stream, not a File, right?
Correct. After all, the user can choose something that you cannot access via the filesystem, either due to permissions or due to the fact that it simply isn't on the filesystem (e.g., cloud storage, SMB/CIFS file server).
IOW, what you refer to as "file choosers" are not limited to what you seem to be thinking of as files.
If I have also acquired MANAGE_EXTERNAL_STORAGE, then it works
I do not know what "it" is. You cannot hack into Google Drive to get a File object using MANAGE_EXTERNAL_STORAGE, for example. Nor can you get a File object for a document contained as a BLOB in an encrypted database, etc.
There is no other way than acquiring MANAGE_EXTERNAL_STORAGE, is that right?
You cannot do what you want even with MANAGE_EXTERNAL_STORAGE. A Uri is not a file.
Your options are:
Copy the content identified by the Uri to some file that you control (e.g., in getCacheDir()), so you can use ZipFile.
Relax the ZipFile constraint. For example, perhaps you could use ZipInputStream, or find a third-party ZIP reader that supports InputStream (such as this or this). You can get an InputStream on the content identified by the Uri via openInputStream() on ContentResolver.
Relax the "in-built file choosers" constraint, and implement your own "file chooser" with files that your app can read on the filesystem. That way, you are guaranteed that you can use File, since you used File to get to them in the first place.
I am trying to share images from other applications to my application using implicit intent ACTION_SEND.
While sharing search images from chrome browser, app receives intent with a Content URI like this:
content://com.android.chrome.FileProvider/images/screenshot/1457448067808912906311.jpg
How can I fetch file path from this type of Content URI? All other apps like Facebook, Google+ are doing it.
I am using FileChooser for getting file path of other types of Content URIs (eg. from Gallery).
Tried looking everywhere, without much help.
Can someone suggest how to work with these Content URIs?
If you absolutely need a local copy of the file, you are going to need to open the InputStream copy the contents to a local file that you know the path to and then go from there. Sidenote: Guava's ByteStreams#copy is an easy way to accomplish this.
Of course this file is no longer backed by the original Uri source, so I don't think this is what you want. Instead, you should work with the Uri's intended API. Take a look at the Storage Access Framework
Edit
Here is how you can get an InputStream from your Uri
InputStream inputStream = getContentResolver().openInputStream(uri);
How can I fetch file path from this type of Content URI?
You don't, as there does not have to be a file at all behind the Uri, let alone one that you can access. That Uri might point to:
A local file on external storage
A local file on internal storage for the other app
A local file on removable storage
A local file that is encrypted and needs to be decrypted on the fly
A stream of bytes held in a BLOB column in a database
A piece of content that needs to be downloaded by the other app first
...and so on
All other apps like Facebook, Google+ are doing it
No, they are not. They are using ContentResolver and:
openInputStream() to read in the bytes associated with the content
getType() to get the MIME type associated with the content
query() and the OpenableColumns to get the size and display name associated with the content
I have read so many theories about saving a file to the internal storage and external storage that I don't know exactly any more what to do.
I created a PDF file with droidtext that I want to e-mail as an attachment in the chosen e-mail app.
This is no problem. I succeeded in this, however... I only can do it with the external storage.
So, I create a PDF, put it in the external storage with Environment.getExternalStorageDirectory().getAbsolutePath().
However, if no external storage is available I want to save the PDF on the internal storage.
I did it like this so far:
External (working perfectly):
pdf = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + java.io.File.separator + fileName);
PdfWriter.getInstance(document, new FileOutputStream(pdf));
Internal storage:
pdf = new File(fileName);
PdfWriter.getInstance(document, openFileOutput(fileName, MODE_PRIVATE));
With both having Document document = new Document();.
The Internal memory method delivers no error whatsoever, but I am not sure if the file is saved internally.
Also, I think that because it is saved internally, the mail app will not be able to select it as an attachment.
I can't test this because my emulator has no mail app. Nor can I go through the content on the device. Nor do I own a device that has no external storage...
What is the best way to solve this? Force users to have external storage or are there other ways to solve this?
"What is the best way to solve this? Force users to have external storage or are there other ways to solve this?"...I'm not certain, but I think you have no choice but to force users to have external storage to be able to email an attachment.
You can't use MODE_PRIVATE to save to internal storage or the email app won't be able to access the file. You'll have to use MODE_WORLD_READABLE.
To get the directory of where the file is stored use Context.getFilesDir() (http://developer.android.com/reference/android/content/Context.html#getFilesDir%28%29)
You can also just install an email app on the emulator to test this. Just download an apk and install it via adb.
From here I know a way to write a file and be accessible to other app and other intent, but now that the Context.MODE_WORLD_READABLE is deprecated how can I safely accomplish this?
FileOutputStream out = myActivity.openFileOutput(fileTo, Context.MODE_WORLD_READABLE);
Okay more info:
I'm using this:
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "video/*");
And the uri will be the one that I will write to a sdcard location. And the video will come from the application so problem is, if this is now not allowed, how can I write the file and view it.
And the uri will be the one that I will write to a sdcard location.
That is already MODE_WORLD_WRITABLE by default. Also note that the code you have listed (openFileOutput()) does not write to external storage (what you incorrectly call "sdcard"). openFileOutput() is for internal storage.
And the video will come from the application so problem is, if this is now not allowed, how can I write the file and view it.
If you are really writing the file to external storage, just use a Uri pointing to that file.
If you are writing the file to internal storage, create a ContentProvider to serve that file, and use a Uri pointing to that ContentProvider. Here is a sample application with a ContentProvider that extracts a PDF file from assets/ on first run, then serves up that file via openFile() so it can be viewed by a PDF viewer.
Save your video in your internal memory using:
openFileOutput("test.mp4", "MODE_PRIVATE");
Then do this:
String path = context.getFilesDir().getAbsolutePath() + "/test.mp4"; // path to the root of internal memory.
File f = new File(path);
f.setReadable(true, false);
Intent playIntent ....
playIntent.setType("video/*");
playIntent.setData(Uri.fromFile(f));
Good Luck.
It seems to look like the docs are clear about it.
This constant was deprecated in API level 17.
Creating world-readable files is very dangerous, and likely to cause
security holes in applications. It is strongly discouraged; instead,
applications should use more formal mechanism for interactions such as
ContentProvider, BroadcastReceiver, and Service. There are no
guarantees that this access mode will remain on a file, such as when
it goes through a backup and restore. File creation mode: allow all
other applications to have read access to the created file.
I want to save a file and then fire an intent to an other application to open that file. How do I accomplish this?
If tried : openFileOutput("file.pdf", Context.MODE_WORLD_READABLE) but doesn't seem to work. Should I save the file outside the applications folder? If so how do I pass it the correct permissions?
You can use something like this:
String extPath = Environment.getExternalStorageDirectory().getAbsolutePath();
String pathPrefix = extPath + "/Android/data/" + APP_PACKAGE_ID + "/cache/";
to save the file to sd card, which is accessible by all other applications. the Mode Context.MODE_WORLD_READABLE is sufficient for this. The code is for use with android 2.1 and uses the suggested path for storing app related data on the sd card. Starting with Android 2.2 this directory automatically gets deleted if the app is uninstalled.
Your app needs the right to install to sd card:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Using openFileOutput(...) with world readable rights is a bit useless as this files are stored into a folder only accessible by the application itself.
More information is described in the data storage documentation.
Please note that the external memory may be unavailable if the user has connected the device via USB for file storage access. You should always check for this conditions first via String state = Environment.getExternalStorageState();.