fixed opening files shared via content URI with incorrect MIME type
This commit is contained in:
parent
d68ff5861a
commit
51bfb3cd04
3 changed files with 53 additions and 13 deletions
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue