diff --git a/CHANGELOG.md b/CHANGELOG.md index 6be5a8796..5c975bf5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Fixed +- opening media shared by other apps as file media content ## [v1.3.6] - 2021-03-18 ### Added diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt index cea3fe155..70e7a46f5 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt @@ -112,9 +112,7 @@ class DebugHandler(private val context: Context) : MethodCallHandler { isVideo(mimeType) -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id) else -> uri } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - contentUri = MediaStore.setRequireOriginal(contentUri) - } + contentUri = StorageUtils.getOriginalUri(contentUri) } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt index 5b8c69cd7..ccde43d8a 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt @@ -8,7 +8,6 @@ import android.media.MediaExtractor import android.media.MediaFormat import android.media.MediaMetadataRetriever import android.net.Uri -import android.os.Build import android.provider.MediaStore import android.util.Log import androidx.exifinterface.media.ExifInterface @@ -684,9 +683,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler { isVideo(mimeType) -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id) else -> uri } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - contentUri = MediaStore.setRequireOriginal(contentUri) - } + contentUri = StorageUtils.getOriginalUri(contentUri) } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt index 43638d0d5..6651f784f 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt @@ -293,9 +293,13 @@ object StorageUtils { // need a document URI (not a media content URI) to open a `DocumentFile` output stream if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isMediaStoreContentUri(mediaUri)) { // cleanest API to get it - val docUri = MediaStore.getDocumentUri(context, mediaUri) - if (docUri != null) { - return DocumentFileCompat.fromSingleUri(context, docUri) + try { + val docUri = MediaStore.getDocumentUri(context, mediaUri) + if (docUri != null) { + return DocumentFileCompat.fromSingleUri(context, docUri) + } + } catch (e: Exception) { + Log.w(LOG_TAG, "failed to get document URI for mediaUri=$mediaUri", e) } } // fallback for older APIs @@ -401,13 +405,21 @@ object StorageUtils { return ContentResolver.SCHEME_CONTENT.equals(uri.scheme, ignoreCase = true) && MediaStore.AUTHORITY.equals(uri.host, ignoreCase = true) } - fun openInputStream(context: Context, uri: Uri): InputStream? { - var effectiveUri = uri + fun getOriginalUri(uri: Uri): Uri { // we get a permission denial if we require original from a provider other than the media store if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && isMediaStoreContentUri(uri)) { - effectiveUri = MediaStore.setRequireOriginal(uri) + val path = uri.path + path ?: return uri + // from Android R, accessing the original URI for a file media content yields a `SecurityException` + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || path.startsWith("/external/images/") || path.startsWith("/external/video/")) { + return MediaStore.setRequireOriginal(uri) + } } + return uri + } + fun openInputStream(context: Context, uri: Uri): InputStream? { + val effectiveUri = getOriginalUri(uri) return try { context.contentResolver.openInputStream(effectiveUri) } catch (e: FileNotFoundException) { @@ -420,12 +432,7 @@ object StorageUtils { } fun openMetadataRetriever(context: Context, uri: Uri): MediaMetadataRetriever? { - var effectiveUri = uri - // we get a permission denial if we require original from a provider other than the media store - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && isMediaStoreContentUri(uri)) { - effectiveUri = MediaStore.setRequireOriginal(uri) - } - + val effectiveUri = getOriginalUri(uri) return try { MediaMetadataRetriever().apply { setDataSource(context, effectiveUri)