Skip to content

Commit f9cb002

Browse files
StaehliJMGaetan89
andauthored
Run Bitmap decoding not on main thread (#601)
Co-authored-by: Gaëtan Muller <[email protected]>
1 parent 778e487 commit f9cb002

File tree

2 files changed

+17
-38
lines changed

2 files changed

+17
-38
lines changed

pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/notification/PillarboxMediaDescriptionAdapter.kt

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,23 @@ import androidx.media3.common.Player
1414
import androidx.media3.ui.PlayerNotificationManager
1515
import androidx.media3.ui.PlayerNotificationManager.MediaDescriptionAdapter
1616
import androidx.media3.ui.R
17+
import kotlinx.coroutines.CoroutineScope
1718
import kotlinx.coroutines.Dispatchers
18-
import kotlinx.coroutines.runBlocking
19+
import kotlinx.coroutines.MainScope
20+
import kotlinx.coroutines.launch
1921
import java.net.URL
2022

2123
/**
2224
* Pillarbox media description adapter
2325
*
2426
* @param pendingIntent [PendingIntent] to use when a user click the notification.
2527
* @param context Context of the application.
26-
*
27-
* @constructor
28+
* @param coroutineScope The [CoroutineScope] used to download image.
2829
*/
2930
class PillarboxMediaDescriptionAdapter(
3031
private val pendingIntent: PendingIntent?,
31-
context: Context
32+
context: Context,
33+
private val coroutineScope: CoroutineScope = MainScope()
3234
) : MediaDescriptionAdapter {
3335
private val imageMaxWidth: Int = context.resources.getDimensionPixelSize(R.dimen.compat_notification_large_icon_max_width)
3436
private val imageMaxHeight: Int = context.resources.getDimensionPixelSize(R.dimen.compat_notification_large_icon_max_height)
@@ -67,11 +69,11 @@ class PillarboxMediaDescriptionAdapter(
6769
val imageUri = player.mediaMetadata.artworkUri!!
6870
val artworkBitmap = bitmapCache.get(imageUri)
6971
if (artworkBitmap == null) {
70-
loadBitmapFromUri(imageUri, callback)
71-
bitmapCache.get(imageUri) // FIXME could return placeholder.
72-
} else {
73-
artworkBitmap
72+
coroutineScope.launch(Dispatchers.IO) {
73+
loadBitmapFromUri(imageUri, callback)
74+
}
7475
}
76+
artworkBitmap // FIXME could return placeholder.
7577
}
7678

7779
else -> {
@@ -86,16 +88,14 @@ class PillarboxMediaDescriptionAdapter(
8688
outWidth = imageMaxWidth
8789
outHeight = imageMaxHeight
8890
}
89-
runBlocking(Dispatchers.IO) {
90-
val result = runCatching {
91-
imageUrl.openStream().use {
92-
BitmapFactory.decodeStream(it, null, opts)
93-
}
94-
}
95-
result.getOrNull()?.let {
96-
bitmapCache.put(imageUri, it)
97-
callback.onBitmap(it)
91+
val result = runCatching {
92+
imageUrl.openStream().use {
93+
BitmapFactory.decodeStream(it, null, opts)
9894
}
9995
}
96+
result.getOrNull()?.let {
97+
bitmapCache.put(imageUri, it)
98+
callback.onBitmap(it)
99+
}
100100
}
101101
}

pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/notification/PillarboxMediaDescriptionAdapterTest.kt

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ import android.content.Context
99
import android.net.Uri
1010
import androidx.media3.common.MediaMetadata
1111
import androidx.media3.common.Player
12-
import androidx.media3.ui.PlayerNotificationManager.BitmapCallback
1312
import androidx.media3.ui.PlayerNotificationManager.MediaDescriptionAdapter
1413
import androidx.test.core.app.ApplicationProvider
1514
import androidx.test.ext.junit.runners.AndroidJUnit4
1615
import io.mockk.every
17-
import io.mockk.justRun
1816
import io.mockk.mockk
1917
import org.junit.runner.RunWith
2018
import org.robolectric.Shadows.shadowOf
@@ -33,7 +31,6 @@ class PillarboxMediaDescriptionAdapterTest {
3331
@BeforeTest
3432
fun setup() {
3533
val context = ApplicationProvider.getApplicationContext<Context>()
36-
3734
pendingIntent = mockk()
3835
mediaDescriptionAdapter = PillarboxMediaDescriptionAdapter(pendingIntent, context)
3936
}
@@ -168,24 +165,6 @@ class PillarboxMediaDescriptionAdapterTest {
168165
assertContentEquals(artworkData, shadowBitmap.createdFromBytes)
169166
}
170167

171-
@Test
172-
fun `get current large icon, with artworkUri only`() {
173-
val artworkUri = "https://source.android.com/static/docs/setup/images/Android_symbol_green_RGB.png"
174-
val player = mockk<Player> {
175-
every { mediaMetadata } returns MediaMetadata.Builder()
176-
.setArtworkUri(Uri.parse(artworkUri))
177-
.build()
178-
}
179-
val bitmapCallback = mockk<BitmapCallback> {
180-
justRun { onBitmap(any()) }
181-
}
182-
val bitmap = mediaDescriptionAdapter.getCurrentLargeIcon(player, bitmapCallback)
183-
184-
assertNotNull(bitmap)
185-
assertEquals(1947, bitmap.width)
186-
assertEquals(1043, bitmap.height)
187-
}
188-
189168
@Test
190169
fun `get current large icon, with bad artworkUri only`() {
191170
val artworkUri = "https://www.example.com/my/image.png"

0 commit comments

Comments
 (0)