Как использовать URI контента для ACTION_VIEW в Nougat?
У меня есть приложение, которое генерирует видеофайлы, которые могут быть помещены во внутреннее хранилище или на SD-карту и должны быть открыты предпочтительным приложением проигрывателя видео через Intent.ACTION_VIEW. Приложение работает по назначению при таргетинге на API 22, но у меня возникают проблемы при попытке обновить его до 27.
Приложение генерирует различные типы URI в зависимости от места хранения. Для внутреннего хранения используется файловый URI, например:
file:///storage/emulated/0/VideoRecorder/2018_06_22_12_25_50.mp4
А для видео, размещенных на SD-карте, используется URI контента:
content://com.android.externalstorage.documents/tree/72D1-C625%3Avideostest%2Ftest2/document/72D1-C625%3Avideostest%2Ftest2%2F2018_06_22_12_41_27.mp4
Nougat не любит file:// URI, поэтому я использовал FileProvider (код ниже), чтобы исправить это, преобразовав URI файла в URI контента, который другие приложения могут открывать с помощью ACTION_VIEW. Я думал, что URI SD-карты не потребует каких-либо изменений, потому что это уже URI контента, но кажется, что только приложение Photos по умолчанию может открыть этот URI с намерением ACTION_VIEW, в то время как установленные пользователем приложения, такие как VLC Player, не могут, сбой со следующим исключением:
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()
Изучив URI, который генерирует FileProvider, я думаю, что понимаю проблему. Он генерирует URI контента в совершенно ином формате, чем URI контента, который у меня есть для видео с SD-карты:
content://io.github.androidtests.videorecorder.videosfileprovider/external_files/VideoRecorder/2018_06_22_12_25_50.mp4
Мой вопрос: нужно ли обмениваться видео с SD-карты через FileProvider? Как мне это сделать, если у меня есть только URI контента, а не файл, а FileProvider, кажется, специально разработан для преобразования файлов в URI?
РЕДАКТИРОВАТЬ: После тестирования еще нескольких приложений видеоплеера, некоторые из них, похоже, могут использовать URI контента, точно так же, как приложение Photos. Это просто случай, когда некоторые приложения еще не поддерживают URI контента?
Код:
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
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>
Пути провайдера:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>