diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c3f7e575..f8d8b76a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,10 @@ All notable changes to this project will be documented in this file.
- upgraded Flutter to stable v3.29.3
+### Fixed
+
+- region decoding failing to access decoder pool
+
## [v1.12.9] - 2025-04-06
### Added
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt
index f3d761fbb..0762a4df9 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt
@@ -20,6 +20,8 @@ import deckers.thibault.aves.utils.MemoryUtils
import deckers.thibault.aves.utils.MimeTypes
import deckers.thibault.aves.utils.StorageUtils
import io.flutter.plugin.common.MethodChannel
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
import kotlin.math.max
import kotlin.math.roundToInt
@@ -60,7 +62,7 @@ class RegionFetcher internal constructor(
}
try {
- val decoder = getOrCreateDecoder(uri, requestKey)
+ val decoder = getOrCreateDecoder(context, uri, requestKey)
if (decoder == null) {
result.error("fetch-read-null", "failed to open file for mimeType=$mimeType uri=$uri regionRect=$regionRect", null)
return
@@ -143,26 +145,6 @@ class RegionFetcher internal constructor(
}
}
- private fun getOrCreateDecoder(uri: Uri, requestKey: Pair): BitmapRegionDecoder? {
- var decoderRef = decoderPool.firstOrNull { it.requestKey == requestKey }
- if (decoderRef == null) {
- val newDecoder = StorageUtils.openInputStream(context, uri)?.use { input ->
- BitmapRegionDecoderCompat.newInstance(input)
- }
- if (newDecoder == null) {
- return null
- }
- decoderRef = DecoderRef(requestKey, newDecoder)
- } else {
- decoderPool.remove(decoderRef)
- }
- decoderPool.add(0, decoderRef)
- while (decoderPool.size > DECODER_POOL_SIZE) {
- decoderPool.removeAt(decoderPool.size - 1)
- }
- return decoderRef.decoder
- }
-
private fun createTemporaryJpegExport(uri: Uri, mimeType: String, pageId: Int?): Uri {
Log.d(LOG_TAG, "create JPEG export for uri=$uri mimeType=$mimeType pageId=$pageId")
val target = Glide.with(context)
@@ -195,5 +177,29 @@ class RegionFetcher internal constructor(
private const val DECODER_POOL_SIZE = 3
private val decoderPool = ArrayList()
private val exportUris = HashMap, Uri>()
+
+ private val poolLock = ReentrantLock()
+
+ private fun getOrCreateDecoder(context: Context, uri: Uri, requestKey: Pair): BitmapRegionDecoder? {
+ poolLock.withLock {
+ var decoderRef = decoderPool.firstOrNull { it.requestKey == requestKey }
+ if (decoderRef == null) {
+ val newDecoder = StorageUtils.openInputStream(context, uri)?.use { input ->
+ BitmapRegionDecoderCompat.newInstance(input)
+ }
+ if (newDecoder == null) {
+ return null
+ }
+ decoderRef = DecoderRef(requestKey, newDecoder)
+ } else {
+ decoderPool.remove(decoderRef)
+ }
+ decoderPool.add(0, decoderRef)
+ while (decoderPool.size > DECODER_POOL_SIZE) {
+ decoderPool.removeAt(decoderPool.size - 1)
+ }
+ return decoderRef.decoder
+ }
+ }
}
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt
index 7208bc6a3..03b8d4df4 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt
@@ -17,6 +17,8 @@ import deckers.thibault.aves.utils.BitmapUtils
import deckers.thibault.aves.utils.MemoryUtils
import deckers.thibault.aves.utils.StorageUtils
import io.flutter.plugin.common.MethodChannel
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
import kotlin.math.ceil
class SvgRegionFetcher internal constructor(
@@ -38,7 +40,7 @@ class SvgRegionFetcher internal constructor(
}
try {
- val svg = getOrCreateDecoder(uri)
+ val svg = getOrCreateDecoder(context, uri)
if (svg == null) {
result.error("fetch-read-null", "failed to open file for uri=$uri regionRect=$regionRect", null)
return
@@ -95,27 +97,6 @@ class SvgRegionFetcher internal constructor(
}
}
- private fun getOrCreateDecoder(uri: Uri): SVG? {
- var decoderRef = decoderPool.firstOrNull { it.uri == uri }
- if (decoderRef == null) {
- val newDecoder = StorageUtils.openInputStream(context, uri)?.use { input ->
- SVG.getFromInputStream(SVGParserBufferedInputStream(input))
- }
- if (newDecoder == null) {
- return null
- }
- newDecoder.normalizeSize()
- decoderRef = DecoderRef(uri, newDecoder)
- } else {
- decoderPool.remove(decoderRef)
- }
- decoderPool.add(0, decoderRef)
- while (decoderPool.size > DECODER_POOL_SIZE) {
- decoderPool.removeAt(decoderPool.size - 1)
- }
- return decoderRef.decoder
- }
-
private data class DecoderRef(
val uri: Uri,
val decoder: SVG,
@@ -125,5 +106,30 @@ class SvgRegionFetcher internal constructor(
private val PREFERRED_CONFIG = Bitmap.Config.ARGB_8888
private const val DECODER_POOL_SIZE = 3
private val decoderPool = ArrayList()
+
+ private val poolLock = ReentrantLock()
+
+ private fun getOrCreateDecoder(context: Context, uri: Uri): SVG? {
+ poolLock.withLock {
+ var decoderRef = decoderPool.firstOrNull { it.uri == uri }
+ if (decoderRef == null) {
+ val newDecoder = StorageUtils.openInputStream(context, uri)?.use { input ->
+ SVG.getFromInputStream(SVGParserBufferedInputStream(input))
+ }
+ if (newDecoder == null) {
+ return null
+ }
+ newDecoder.normalizeSize()
+ decoderRef = DecoderRef(uri, newDecoder)
+ } else {
+ decoderPool.remove(decoderRef)
+ }
+ decoderPool.add(0, decoderRef)
+ while (decoderPool.size > DECODER_POOL_SIZE) {
+ decoderPool.removeAt(decoderPool.size - 1)
+ }
+ return decoderRef.decoder
+ }
+ }
}
}