fixed opening files shared via content URI with incorrect MIME type

This commit is contained in:
Thibault Deckers 2021-05-03 11:36:33 +09:00
parent d68ff5861a
commit 51bfb3cd04
3 changed files with 53 additions and 13 deletions

View file

@ -29,7 +29,7 @@ class ImageFileHandler(private val activity: Activity) : MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"getEntry" -> GlobalScope.launch(Dispatchers.IO) { safesus(call, result, ::getEntry) }
"getEntry" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getEntry) }
"getThumbnail" -> GlobalScope.launch(Dispatchers.IO) { safesus(call, result, ::getThumbnail) }
"getRegion" -> GlobalScope.launch(Dispatchers.IO) { safesus(call, result, ::getRegion) }
"rename" -> GlobalScope.launch(Dispatchers.IO) { safesus(call, result, ::rename) }
@ -40,7 +40,7 @@ class ImageFileHandler(private val activity: Activity) : MethodCallHandler {
}
}
private suspend fun getEntry(call: MethodCall, result: MethodChannel.Result) {
private fun getEntry(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType") // MIME type is optional
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (uri == null) {

View file

@ -127,16 +127,7 @@ object Metadata {
Log.d(LOG_TAG, "use a preview for uri=$uri mimeType=$mimeType size=$sizeBytes")
var previewFile = previewFiles[uri]
if (previewFile == null) {
previewFile = File.createTempFile("aves", null, context.cacheDir).apply {
deleteOnExit()
outputStream().use { output ->
StorageUtils.openInputStream(context, uri)?.use { input ->
val b = ByteArray(previewSize)
input.read(b, 0, previewSize)
output.write(b)
}
}
}
previewFile = createPreviewFile(context, uri)
previewFiles[uri] = previewFile
}
Uri.fromFile(previewFile)
@ -147,6 +138,19 @@ object Metadata {
}
}
fun createPreviewFile(context: Context, uri: Uri): File {
return File.createTempFile("aves", null, context.cacheDir).apply {
deleteOnExit()
outputStream().use { output ->
StorageUtils.openInputStream(context, uri)?.use { input ->
val b = ByteArray(previewSize)
input.read(b, 0, previewSize)
output.write(b)
}
}
}
}
fun openSafeInputStream(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): InputStream? {
val safeUri = getSafeUri(context, uri, mimeType, sizeBytes)
return StorageUtils.openInputStream(context, safeUri)

View file

@ -4,10 +4,44 @@ import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Log
import com.drew.imaging.ImageMetadataReader
import com.drew.metadata.file.FileTypeDirectory
import deckers.thibault.aves.metadata.Metadata
import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeString
import deckers.thibault.aves.model.SourceEntry
import deckers.thibault.aves.utils.LogUtils
import deckers.thibault.aves.utils.MimeTypes
import deckers.thibault.aves.utils.StorageUtils
internal class ContentImageProvider : ImageProvider() {
override fun fetchSingle(context: Context, uri: Uri, mimeType: String?, callback: ImageOpCallback) {
override fun fetchSingle(context: Context, uri: Uri, sourceMimeType: String?, callback: ImageOpCallback) {
// source MIME type may be incorrect, so we get a second opinion if possible
var extractorMimeType: String? = null
try {
val safeUri = Uri.fromFile(Metadata.createPreviewFile(context, uri))
StorageUtils.openInputStream(context, safeUri)?.use { input ->
val metadata = ImageMetadataReader.readMetadata(input)
for (dir in metadata.getDirectoriesOfType(FileTypeDirectory::class.java)) {
// `metadata-extractor` is the most reliable, except for `tiff` (false positives, false negatives)
// cf https://github.com/drewnoakes/metadata-extractor/issues/296
dir.getSafeString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE) {
if (it != MimeTypes.TIFF) {
extractorMimeType = it
if (extractorMimeType != sourceMimeType) {
Log.d(LOG_TAG, "source MIME type is $sourceMimeType but extracted MIME type is $extractorMimeType for uri=$uri")
}
}
}
}
}
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get MIME type by metadata-extractor for uri=$uri", e)
} catch (e: NoClassDefFoundError) {
Log.w(LOG_TAG, "failed to get MIME type by metadata-extractor for uri=$uri", e)
}
val mimeType = extractorMimeType ?: sourceMimeType
if (mimeType == null) {
callback.onFailure(Exception("MIME type is null for uri=$uri"))
return
@ -39,6 +73,8 @@ internal class ContentImageProvider : ImageProvider() {
}
companion object {
private val LOG_TAG = LogUtils.createTag<ContentImageProvider>()
@Suppress("DEPRECATION")
const val PATH = MediaStore.MediaColumns.DATA