How to open private files saved to the internal storage using Intent.ACTION_VIEW?
You can't share/send a file in internal storage, as referenced by a URI, via an Intent to another app. An app cannot read another app's private data (unless it's through a Content Provider). You pass the URI of the file in the intent (not the actual file itself) and the app that receives the intent needs to be able to read from that URI.
The simplest solution is to copy the file to external storage first and share it from there. If you don't want to do that, create a Content Provider to expose your file. An example can be found here: Create and Share a File from Internal Storage
EDIT: To use a content provider:
First create your content provider class as below. The important override here is 'openFile'. When your content provider is called with a file URI, this method will run and return a ParcelFileDescriptor for it. The other methods need to be present as well since they are abstract in ContentProvider.
public class MyProvider extends ContentProvider {
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File privateFile = new File(getContext().getFilesDir(), uri.getPath());
return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
return 0;
}
@Override
public String getType(Uri arg0) {
return null;
}
@Override
public Uri insert(Uri arg0, ContentValues arg1) {
return null;
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4) {
return null;
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
return 0;
}
}
Define your provider in the Manifest within the application tag, with exported=true to allow other apps to use it:
<provider android:name=".MyProvider" android:authorities="your.package.name" android:exported="true" />
In the openFile() method you have in your Activity, set up a URI as below. This URI points to the content provider in your package along with the filename:
Uri uri = Uri.parse("content://your.package.name/" + filePath);
Finally, set this uri in the intent:
intent.setDataAndType(uri, type);
Remember to insert your own package name where I have used 'your.package.name' above.
Open a pdf stored in internal storage through an Android Intent
Resolved by following the following method.
https://medium.com/@ali.muzaffar/what-is-android-os-fileuriexposedexception-and-what-you-can-do-about-it-70b9eb17c6d0
Open Image with intent from internal storage
Try with this :
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.parse("file://" + file.getAbsolutePath());
intent.setDataAndType(uri,"image/*");
startActivity(intent);
Thanks.
Opening file from SD card via Intent.ACTION_VIEW
I finally found a solution for this. java.lang.SecurityException: Permission Denial
will be thrown when you open a external file using DocumentFile.fromSingleUri(context, uri)
. This static method is only useful when you pick a file inside onActivityResult()
method with action Intent.ACTION_OPEN_DOCUMENT
or Intent.ACTION_CREATE_DOCUMENT
. When your app is destroyed, the permission to access the file is gone. You should not use DocumentFile.fromSingleUri(context, uri)
while working with files that require long time permission. Hence, we need DocumentFile.fromTreeUri(context, uri)
instead.
To do that so, you must access the root of SD card's ID (e.g. 6331-6132
) first. For example:
String path = "6331-6132:Video/Iykwim.mp4";
String sdcardId = path.substring(0, path.indexOf(':') + 1); // => returns '6331-6132:'
Uri uri = Uri.parse("content://com.android.externalstorage.documents/tree/" + Uri.encode(sdcardId));
DocumentFile root = DocumentFile.fromTreeUri(context, uri);
// Now, we already have the root of SD card.
// Next, we will get into => Video => Iykwim.mp4
DocumentFile file = root.findFile("Video").findFile("Iykwim.mp4");
Notice that you cannot access the file directly like this Uri
:
String path = "6331-6132:Video/Iykwim.mp4";
Uri uri = Uri.parse("content://com.android.externalstorage.documents/tree/" + Uri.encode(path));
DocumentFile file = DocumentFile.fromTreeUri(context, uri);
Or like this:
String folder = "6331-6132:Video";
Uri uri = Uri.parse("content://com.android.externalstorage.documents/tree/" + Uri.encode(folder));
DocumentFile directoryVideo = DocumentFile.fromTreeUri(context, uri);
DocumentFile file = directoryVideo.findFile("Iykwim.mp4");
Finally, you can open the file using Intent.ACTION_VIEW
:
Intent intent = new Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(documentFile.getUri());
context.startActivity(intent);
The worst scenario is when you call findFile()
from a folder with so many files inside. It will take long time and may lead to crash your app. Ensure that you always call this method from different thread.
Android is getting worst day by day. They have made a Storage Access Framework (SAF) that makes you difficult to manage files on SD card. Using java.io.File
is almost deprecated since Android Kitkat. You should use DocumentFile
instead.
How to open specific folder in the storage using intent in android
This code may help you:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
startActivityForResult(intent, YOUR_RESULT_CODE);
If you want to open a specific folder:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setDataAndType(Uri.parse(Environment.getExternalStorageDirectory().getPath()
+ File.separator + "myFolder" + File.separator), "file/*");
startActivityForResult(intent, YOUR_RESULT_CODE);
Open file in cache directory with ACTION_VIEW
I found out that I had to do things differently.
Instead of creating my own ContentProvider, the v4 support library offers a FileProvider class that can be used.
In AndroidManifest.xml
add
<application ...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="be.myapplication"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
The FILE_PROVIDER_PATHS is an xml file that describes which files can be read by other applications.
So I added a file_paths.xml file to the res/xml folder.
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="my_cache" path="." />
</paths>
And the only thing you have to do then is create and start the intent to show the file.
File file = new File(getCacheDir(), "test.pdf");
Uri uri = FileProvider.getUriForFile(context, "be.myapplication", file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
And actually that's it.
IMPORTANT: Please do not forget setting
FLAG_GRANT_READ_URI_PERMISSION
flags for the intent. Otherwise it will not work.
Related Topics
How to Change the Android Startactivity() Transition Animation
How to Dynamically Query the Room Database at Runtime
Calling Android Dialog Without It Fading the Background
Adding Watermark Bitmap Over Video in Android: 4.3's Mediamuxer or Ffmpeg
Create/Copy File in Android Q Using Mediastore
Use Roboto Font in App with Minimum API Level 14
Mylib.So Has Text Relocations. This Is Wasting Memory and Is a Security Risk. Please Fix
How to Open Private Files Saved to the Internal Storage Using Intent.Action_View
How to Create a Multilingual Android Application
How to Click or Tap on a Textview Text on Different Words
Sending Mail in Android Without Intents Using Smtp
Android Ndk C++ Jni (No Implementation Found for Native...)
How to Disable Future Dates in Android Date Picker
Android: Picasso Load Image Failed . How to Show Error Message
How to Draw a Circle with Animation in Android with Circle Size Based on a Value
Calculate the Size of a List View or How to Tell It to Fully Expand