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.
This commit is contained in:
t895 2023-11-14 10:57:00 -05:00
parent 247d66a680
commit 4d0b7f8496
2 changed files with 35 additions and 24 deletions

View file

@ -22,12 +22,16 @@ import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView 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.HomeNavigationDirections
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
@ -92,6 +96,8 @@ class GameAdapter(private val activity: AppCompatActivity) :
data = Uri.parse(holder.game.path) data = Uri.parse(holder.game.path)
} }
activity.lifecycleScope.launch {
withContext(Dispatchers.IO) {
val layerDrawable = ResourcesCompat.getDrawable( val layerDrawable = ResourcesCompat.getDrawable(
YuzuApplication.appContext.resources, YuzuApplication.appContext.resources,
R.drawable.shortcut, R.drawable.shortcut,
@ -99,12 +105,14 @@ class GameAdapter(private val activity: AppCompatActivity) :
) as LayerDrawable ) as LayerDrawable
layerDrawable.setDrawableByLayerId( layerDrawable.setDrawableByLayerId(
R.id.shortcut_foreground, R.id.shortcut_foreground,
GameIconUtils.getGameIcon(holder.game).toDrawable(YuzuApplication.appContext.resources) GameIconUtils.getGameIcon(activity, holder.game)
.toDrawable(YuzuApplication.appContext.resources)
) )
val inset = YuzuApplication.appContext.resources val inset = YuzuApplication.appContext.resources
.getDimensionPixelSize(R.dimen.icon_inset) .getDimensionPixelSize(R.dimen.icon_inset)
layerDrawable.setLayerInset(1, inset, inset, inset, inset) layerDrawable.setLayerInset(1, inset, inset, inset, inset)
val shortcut = ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path) val shortcut =
ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
.setShortLabel(holder.game.title) .setShortLabel(holder.game.title)
.setIcon( .setIcon(
IconCompat.createWithAdaptiveBitmap( IconCompat.createWithAdaptiveBitmap(
@ -114,6 +122,8 @@ class GameAdapter(private val activity: AppCompatActivity) :
.setIntent(openIntent) .setIntent(openIntent)
.build() .build()
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
}
}
val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game) val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game)
view.findNavController().navigate(action) view.findNavController().navigate(action)

View file

@ -8,9 +8,9 @@ import android.graphics.BitmapFactory
import android.widget.ImageView import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader import coil.ImageLoader
import coil.decode.DataSource import coil.decode.DataSource
import coil.executeBlocking
import coil.fetch.DrawableResult import coil.fetch.DrawableResult
import coil.fetch.FetchResult import coil.fetch.FetchResult
import coil.fetch.Fetcher import coil.fetch.Fetcher
@ -76,12 +76,13 @@ object GameIconUtils {
imageLoader.enqueue(request) imageLoader.enqueue(request)
} }
fun getGameIcon(game: Game): Bitmap { suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
val request = ImageRequest.Builder(YuzuApplication.appContext) val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game) .data(game)
.lifecycle(lifecycleOwner)
.error(R.drawable.default_icon) .error(R.drawable.default_icon)
.build() .build()
return imageLoader.executeBlocking(request) return imageLoader.execute(request)
.drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888) .drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
} }
} }