From 4d0b7f84960172c6dfd4c2ea7503f4d442495698 Mon Sep 17 00:00:00 2001 From: t895 Date: Tue, 14 Nov 2023 10:57:00 -0500 Subject: [PATCH] android: Use suspend function for creating dynamic shortcuts If the coil loader ever got stuck when creating a dynamic shortcut icon, the app would freeze. This would happen most notably when booting nca format games. This pushes that process to a separate coroutine that can be cancelled by the main activity's lifecycle. --- .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 52 +++++++++++-------- .../org/yuzu/yuzu_emu/utils/GameIconUtils.kt | 7 +-- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 0c82cdba88..2ef6385597 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -22,12 +22,16 @@ import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toDrawable import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.preference.PreferenceManager import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication @@ -92,28 +96,34 @@ class GameAdapter(private val activity: AppCompatActivity) : data = Uri.parse(holder.game.path) } - val layerDrawable = ResourcesCompat.getDrawable( - YuzuApplication.appContext.resources, - R.drawable.shortcut, - null - ) as LayerDrawable - layerDrawable.setDrawableByLayerId( - R.id.shortcut_foreground, - GameIconUtils.getGameIcon(holder.game).toDrawable(YuzuApplication.appContext.resources) - ) - val inset = YuzuApplication.appContext.resources - .getDimensionPixelSize(R.dimen.icon_inset) - layerDrawable.setLayerInset(1, inset, inset, inset, inset) - val shortcut = ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path) - .setShortLabel(holder.game.title) - .setIcon( - IconCompat.createWithAdaptiveBitmap( - layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) + activity.lifecycleScope.launch { + withContext(Dispatchers.IO) { + val layerDrawable = ResourcesCompat.getDrawable( + YuzuApplication.appContext.resources, + R.drawable.shortcut, + null + ) as LayerDrawable + layerDrawable.setDrawableByLayerId( + R.id.shortcut_foreground, + GameIconUtils.getGameIcon(activity, holder.game) + .toDrawable(YuzuApplication.appContext.resources) ) - ) - .setIntent(openIntent) - .build() - ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + val inset = YuzuApplication.appContext.resources + .getDimensionPixelSize(R.dimen.icon_inset) + layerDrawable.setLayerInset(1, inset, inset, inset, inset) + val shortcut = + ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path) + .setShortLabel(holder.game.title) + .setIcon( + IconCompat.createWithAdaptiveBitmap( + layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) + ) + ) + .setIntent(openIntent) + .build() + ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + } + } val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game) view.findNavController().navigate(action) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt index 654d62f52f..2e9b0beb8c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt @@ -8,9 +8,9 @@ import android.graphics.BitmapFactory import android.widget.ImageView import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toDrawable +import androidx.lifecycle.LifecycleOwner import coil.ImageLoader import coil.decode.DataSource -import coil.executeBlocking import coil.fetch.DrawableResult import coil.fetch.FetchResult import coil.fetch.Fetcher @@ -76,12 +76,13 @@ object GameIconUtils { imageLoader.enqueue(request) } - fun getGameIcon(game: Game): Bitmap { + suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap { val request = ImageRequest.Builder(YuzuApplication.appContext) .data(game) + .lifecycle(lifecycleOwner) .error(R.drawable.default_icon) .build() - return imageLoader.executeBlocking(request) + return imageLoader.execute(request) .drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888) } }