Skip to content

Commit

Permalink
[Feature] Support remote media thumbnail on Android 6.0+.
Browse files Browse the repository at this point in the history
  • Loading branch information
zhanghai committed Sep 15, 2023
1 parent edc71c8 commit 08135e3
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,60 @@

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 {
path.isLinuxPath -> setDataSource(path.toFile().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()
}
}

0 comments on commit 08135e3

Please sign in to comment.