diff --git a/app/src/main/java/me/zhanghai/android/files/coil/PathAttributesFetcher.kt b/app/src/main/java/me/zhanghai/android/files/coil/PathAttributesFetcher.kt index 65f9c6a13..b32fd18bd 100644 --- a/app/src/main/java/me/zhanghai/android/files/coil/PathAttributesFetcher.kt +++ b/app/src/main/java/me/zhanghai/android/files/coil/PathAttributesFetcher.kt @@ -44,6 +44,7 @@ import me.zhanghai.android.files.settings.Settings import me.zhanghai.android.files.util.getDimensionPixelSize import me.zhanghai.android.files.util.getPackageArchiveInfoCompat import me.zhanghai.android.files.util.isGetPackageArchiveInfoCompatible +import me.zhanghai.android.files.util.isMediaMetadataRetrieverCompatible import me.zhanghai.android.files.util.runWithCancellationSignal import me.zhanghai.android.files.util.setDataSource import me.zhanghai.android.files.util.valueCompat @@ -119,7 +120,7 @@ class PathAttributesFetcher( if (mimeType != MimeType.GENERIC) mimeType.value else null, path.dataSource ) } - mimeType.isMedia && (path.isLinuxPath || path.isDocumentPath) -> { + mimeType.isMedia && path.isMediaMetadataRetrieverCompatible -> { val embeddedPicture = try { MediaMetadataRetriever().use { retriever -> retriever.setDataSource(path) diff --git a/app/src/main/java/me/zhanghai/android/files/util/MediaMetadataRetrieverPathExtensions.kt b/app/src/main/java/me/zhanghai/android/files/util/MediaMetadataRetrieverPathExtensions.kt index 23abe8132..ce0bb6273 100644 --- a/app/src/main/java/me/zhanghai/android/files/util/MediaMetadataRetrieverPathExtensions.kt +++ b/app/src/main/java/me/zhanghai/android/files/util/MediaMetadataRetrieverPathExtensions.kt @@ -5,14 +5,26 @@ package me.zhanghai.android.files.util +import android.media.MediaDataSource import android.media.MediaMetadataRetriever +import android.os.Build +import androidx.annotation.RequiresApi +import java8.nio.channels.SeekableByteChannel import java8.nio.file.Path +import me.zhanghai.android.files.provider.common.newByteChannel import me.zhanghai.android.files.provider.document.isDocumentPath import me.zhanghai.android.files.provider.document.resolver.DocumentResolver +import me.zhanghai.android.files.provider.ftp.isFtpPath import me.zhanghai.android.files.provider.linux.isLinuxPath +import java.io.IOException +import java.nio.ByteBuffer val Path.isMediaMetadataRetrieverCompatible: Boolean - get() = isLinuxPath || isDocumentPath + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + !isFtpPath + } else { + isLinuxPath || isDocumentPath + } fun MediaMetadataRetriever.setDataSource(path: Path) { when { @@ -20,6 +32,33 @@ fun MediaMetadataRetriever.setDataSource(path: Path) { path.isDocumentPath -> DocumentResolver.openParcelFileDescriptor(path as DocumentResolver.Path, "r") .use { pfd -> setDataSource(pfd.fileDescriptor) } + Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { + val channel = try { + path.newByteChannel() + } catch (e: IOException) { + throw IllegalArgumentException(e) + } + setDataSource(PathMediaDataSource(channel)) + } else -> throw IllegalArgumentException(path.toString()) } } + +@RequiresApi(Build.VERSION_CODES.M) +private class PathMediaDataSource(private val channel: SeekableByteChannel) : MediaDataSource() { + @Throws(IOException::class) + override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int { + channel.position(position) + return channel.read(ByteBuffer.wrap(buffer, offset, size)) + } + + @Throws(IOException::class) + override fun getSize(): Long { + return channel.size() + } + + @Throws(IOException::class) + override fun close() { + channel.close() + } +}