How to Open Private Files Saved to the Internal Storage Using Intent.Action_View

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



Leave a reply



Submit