fix(mobile): load original setting on android (#22277)

* fix load original setting with videos

* check in decodeImage too
This commit is contained in:
Mert 2025-09-21 19:53:51 -04:00 committed by GitHub
parent 0be71c82b3
commit b33e8abcdd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -17,6 +17,7 @@ import java.util.concurrent.Executors
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.Priority import com.bumptech.glide.Priority
import com.bumptech.glide.load.DecodeFormat import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.target.Target.SIZE_ORIGINAL
import java.util.Base64 import java.util.Base64
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -120,15 +121,14 @@ class ThumbnailsImpl(context: Context) : ThumbnailApi {
signal: CancellationSignal signal: CancellationSignal
) { ) {
signal.throwIfCanceled() signal.throwIfCanceled()
val targetWidth = width.toInt() val size = Size(width.toInt(), height.toInt())
val targetHeight = height.toInt()
val id = assetId.toLong() val id = assetId.toLong()
signal.throwIfCanceled() signal.throwIfCanceled()
val bitmap = if (isVideo) { val bitmap = if (isVideo) {
decodeVideoThumbnail(id, targetWidth, targetHeight, signal) decodeVideoThumbnail(id, size, signal)
} else { } else {
decodeImage(id, targetWidth, targetHeight, signal) decodeImage(id, size, signal)
} }
processBitmap(bitmap, callback, signal) processBitmap(bitmap, callback, signal)
@ -151,9 +151,7 @@ class ThumbnailsImpl(context: Context) : ThumbnailApi {
bitmap.recycle() bitmap.recycle()
signal.throwIfCanceled() signal.throwIfCanceled()
val res = mapOf( val res = mapOf(
"pointer" to pointer, "pointer" to pointer, "width" to actualWidth.toLong(), "height" to actualHeight.toLong()
"width" to actualWidth.toLong(),
"height" to actualHeight.toLong()
) )
callback(Result.success(res)) callback(Result.success(res))
} catch (e: Exception) { } catch (e: Exception) {
@ -162,55 +160,54 @@ class ThumbnailsImpl(context: Context) : ThumbnailApi {
} }
} }
private fun decodeImage( private fun decodeImage(id: Long, size: Size, signal: CancellationSignal): Bitmap {
id: Long, targetWidth: Int, targetHeight: Int, signal: CancellationSignal
): Bitmap {
signal.throwIfCanceled() signal.throwIfCanceled()
val uri = ContentUris.withAppendedId(Images.Media.EXTERNAL_CONTENT_URI, id) val uri = ContentUris.withAppendedId(Images.Media.EXTERNAL_CONTENT_URI, id)
if (targetHeight > 768 || targetWidth > 768) { if (size.width <= 0 || size.height <= 0 || size.width > 768 || size.height > 768) {
return decodeSource(uri, targetWidth, targetHeight, signal) return decodeSource(uri, size, signal)
} }
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
resolver.loadThumbnail(uri, Size(targetWidth, targetHeight), signal) resolver.loadThumbnail(uri, size, signal)
} else { } else {
signal.setOnCancelListener { Images.Thumbnails.cancelThumbnailRequest(resolver, id) } signal.setOnCancelListener { Images.Thumbnails.cancelThumbnailRequest(resolver, id) }
Images.Thumbnails.getThumbnail(resolver, id, Images.Thumbnails.MINI_KIND, OPTIONS) Images.Thumbnails.getThumbnail(resolver, id, Images.Thumbnails.MINI_KIND, OPTIONS)
} }
} }
private fun decodeVideoThumbnail( private fun decodeVideoThumbnail(id: Long, target: Size, signal: CancellationSignal): Bitmap {
id: Long, targetWidth: Int, targetHeight: Int, signal: CancellationSignal
): Bitmap {
signal.throwIfCanceled() signal.throwIfCanceled()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val uri = ContentUris.withAppendedId(Video.Media.EXTERNAL_CONTENT_URI, id) val uri = ContentUris.withAppendedId(Video.Media.EXTERNAL_CONTENT_URI, id)
resolver.loadThumbnail(uri, Size(targetWidth, targetHeight), signal) // ensure a valid resolution as the thumbnail is used for videos even when no scaling is needed
val size = if (target.width > 0 && target.height > 0) target else Size(768, 768)
resolver.loadThumbnail(uri, size, signal)
} else { } else {
signal.setOnCancelListener { Video.Thumbnails.cancelThumbnailRequest(resolver, id) } signal.setOnCancelListener { Video.Thumbnails.cancelThumbnailRequest(resolver, id) }
Video.Thumbnails.getThumbnail(resolver, id, Video.Thumbnails.MINI_KIND, OPTIONS) Video.Thumbnails.getThumbnail(resolver, id, Video.Thumbnails.MINI_KIND, OPTIONS)
} }
} }
private fun decodeSource( private fun decodeSource(uri: Uri, target: Size, signal: CancellationSignal): Bitmap {
uri: Uri, targetWidth: Int, targetHeight: Int, signal: CancellationSignal
): Bitmap {
signal.throwIfCanceled() signal.throwIfCanceled()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val source = ImageDecoder.createSource(resolver, uri) val source = ImageDecoder.createSource(resolver, uri)
signal.throwIfCanceled() signal.throwIfCanceled()
ImageDecoder.decodeBitmap(source) { decoder, info, _ -> ImageDecoder.decodeBitmap(source) { decoder, info, _ ->
if (targetWidth > 0 && targetHeight > 0) { if (target.width > 0 && target.height > 0) {
val sample = max(1, min(info.size.width / targetWidth, info.size.height / targetHeight)) val sample = max(1, min(info.size.width / target.width, info.size.height / target.height))
decoder.setTargetSampleSize(sample) decoder.setTargetSampleSize(sample)
} }
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.SRGB)) decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
} }
} else { } else {
val ref = Glide.with(ctx).asBitmap().priority(Priority.IMMEDIATE).load(uri) val ref =
.disallowHardwareConfig().format(DecodeFormat.PREFER_ARGB_8888) Glide.with(ctx).asBitmap().priority(Priority.IMMEDIATE).load(uri).disallowHardwareConfig()
.submit(targetWidth, targetHeight) .format(DecodeFormat.PREFER_ARGB_8888).submit(
if (target.width > 0) target.width else SIZE_ORIGINAL,
if (target.height > 0) target.height else SIZE_ORIGINAL,
)
signal.setOnCancelListener { Glide.with(ctx).clear(ref) } signal.setOnCancelListener { Glide.with(ctx).clear(ref) }
ref.get() ref.get()
} }