I have an app that generates video files, which can be placed in the internal storage or the SD card, and need to be opened by the user's preferred video player app via Intent.ACTION_VIEW. The app works as intended when targeting API 22, but I'm having issues when I attempt to upgrade it to 27.
The app generates different types of URI depending on storage location. For internal storage, it uses a file URI, like so:
file:///storage/emulated/0/VideoRecorder/2018_06_22_12_25_50.mp4
And for videos placed in the SD card, it uses a content URI:
content://com.android.externalstorage.documents/tree/72D1-C625%3Avideostest%2Ftest2/document/72D1-C625%3Avideostest%2Ftest2%2F2018_06_22_12_41_27.mp4
Nougat doesn't like file:// URIs, so I used a FileProvider (code below) to fix that, converting the file URI into a content URI that other apps can open with ACTION_VIEW. I thought the SD card URI wouldn't need any changes, because it's already a content URI, but it seems that only the default Photos app can open that URI with a ACTION_VIEW intent, whereas user-installed apps like VLC Player can't, failing with the following exception:
java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/72D1-C625:videostest/test2/document/72D1-C625:videostest/test2/2018_06_22_12_27_45.mp4 from pid=7809, uid=10022 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
Having examined the URI that the FileProvider generates, I think I understand the problem. It generates a content URI that's in an entirely different format than the content URI I have for the SD card video:
content://io.github.androidtests.videorecorder.videosfileprovider/external_files/VideoRecorder/2018_06_22_12_25_50.mp4
My question is, do the SD card videos need to be shared via FileProvider as well? How do I do that, seeing as I only have a content URI, not a File, and FileProvider seems specifically designed to convert Files into URIs?
EDIT: After testing some more video player apps, some of them seem to be able to use the content URI, just the same as the Photos app. Is this just a case of some apps not supporting content URIs yet?
Code:
Uri uri = adapter.mDataset.get(position).videoUri;
if (uri.toString().contains("file://")) {
try {
ParcelFileDescriptor pFD = ctx.getContentResolver().openFileDescriptor(uri, "r");
String truePath = Utils.getFdPath(pFD);
uri = FileProvider.getUriForFile(ctx, "io.github.androidtests.videorecorder.videosfileprovider", new File(truePath));
} catch (FileNotFoundException e) {
StaticMethodsAndValues.launchFabricException("RecyclerViewFragment caught FileNotFoundException when opening video.", e);
return;
}
}
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setDataAndType(uri, "video/mp4");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
ctx.startActivity(intent);
}
catch (ActivityNotFoundException e) {
Toast.makeText(mContext.get(), mContext.get().getString(R.string.toast_no_video_player_found), Toast.LENGTH_LONG).show();
StaticMethodsAndValues.launchFabricException("Device does not have app to handle intent action.VIEW for video/mp4.", e);
}
Provider manifest definition:
<provider
android:name=".VideosFileProvider"
android:authorities="io.github.androidtests.videorecorder.videosfileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
Provider paths:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>