diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt index b60ba164..eb315ae4 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt @@ -90,26 +90,26 @@ class IconPackManager( packageName: String, activityName: String?, allowThemed: Boolean = true - ): LauncherIcon? { + ): LauncherIcon? = withContext(Dispatchers.IO) { val res = try { context.packageManager.getResourcesForApplication(iconPack) } catch (e: PackageManager.NameNotFoundException) { Log.e("MM20", "Icon pack package $iconPack not found!") - return null + return@withContext null } val activity = activityName?.let { ComponentName(packageName, it) }?.shortClassName val iconDao = appDatabase.iconDao() val icon = iconDao.getIcon(packageName, activity, iconPack)?.let { IconPackAppIcon(it) } - ?: return null + ?: return@withContext null if (icon is CalendarIcon) { - return getIconPackCalendarIcon(icon, res, allowThemed) + return@withContext getIconPackCalendarIcon(icon, res, allowThemed) } else if (icon is AppIcon) { - return getIconPackStaticIcon(icon, res, allowThemed) + return@withContext getIconPackStaticIcon(icon, res, allowThemed) } else if (icon is ClockIcon) { - return getIconPackClockIcon(icon, res, allowThemed) + return@withContext getIconPackClockIcon(icon, res, allowThemed) } - return null + return@withContext null } suspend fun generateIcon( @@ -117,14 +117,14 @@ class IconPackManager( iconPack: String, baseIcon: Drawable, size: Int - ): LauncherIcon? { + ): LauncherIcon? = withContext(Dispatchers.IO) { val back = getIconBack(iconPack) val upon = getIconUpon(iconPack) val mask = getIconMask(iconPack) val scale = getPackScale(iconPack) if (back == null && upon == null && mask == null) { - return null + return@withContext null } val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) @@ -155,18 +155,18 @@ class IconPackManager( val res = try { pm.getResourcesForApplication(pack) } catch (e: Resources.NotFoundException) { - return null + return@withContext null } catch (e: PackageManager.NameNotFoundException) { - return null + return@withContext null } if (mask != null) { res.getIdentifier(mask, "drawable", pack).takeIf { it != 0 }?.let { paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) val maskDrawable = try { - ResourcesCompat.getDrawable(res, it, null) ?: return null + ResourcesCompat.getDrawable(res, it, null) ?: return@withContext null } catch (e: Resources.NotFoundException) { - return null + return@withContext null } val maskBmp = maskDrawable.toBitmap(size, size) inBounds = Rect(0, 0, maskBmp.width, maskBmp.height) @@ -178,9 +178,9 @@ class IconPackManager( res.getIdentifier(upon, "drawable", pack).takeIf { it != 0 }?.let { paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OVER) val maskDrawable = try { - ResourcesCompat.getDrawable(res, it, null) ?: return null + ResourcesCompat.getDrawable(res, it, null) ?: return@withContext null } catch (e: Resources.NotFoundException) { - return null + return@withContext null } val maskBmp = maskDrawable.toBitmap(size, size) inBounds = Rect(0, 0, maskBmp.width, maskBmp.height) @@ -192,9 +192,9 @@ class IconPackManager( res.getIdentifier(back, "drawable", pack).takeIf { it != 0 }?.let { paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OVER) val maskDrawable = try { - ResourcesCompat.getDrawable(res, it, null) ?: return null + ResourcesCompat.getDrawable(res, it, null) ?: return@withContext null } catch (e: Resources.NotFoundException) { - return null + return@withContext null } val maskBmp = maskDrawable.toBitmap(size, size) inBounds = Rect(0, 0, maskBmp.width, maskBmp.height) @@ -203,7 +203,7 @@ class IconPackManager( } } - return StaticLauncherIcon( + return@withContext StaticLauncherIcon( foregroundLayer = StaticIconLayer( icon = BitmapDrawable(context.resources, bitmap), scale = 1f, diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/IconService.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/IconService.kt index 619dbf18..5d95b065 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/IconService.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/IconService.kt @@ -42,6 +42,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @@ -138,30 +139,25 @@ class IconService( } - fun getIcon(searchable: SavableSearchable, size: Int): Flow = channelFlow { - iconProviders.collectLatest { providers -> - transformations.collectLatest { transformations -> - customAttributesRepository.getCustomIcon(searchable).collectLatest { customIcon -> - - val provs = getProviders(customIcon) + providers - val transforms = getTransformations(customIcon) ?: transformations - - var icon = cache.get(searchable.key + customIcon.hashCode()) - if (icon != null) { - send(icon) - return@collectLatest - } - - icon = provs.getFirstIcon(searchable, size) - - if (icon != null) { - icon = icon.transform(transforms) - - cache.put(searchable.key + customIcon.hashCode(), icon) - send(icon) - } - } + fun getIcon(searchable: SavableSearchable, size: Int): Flow { + val customIcon = customAttributesRepository.getCustomIcon(searchable) + return combine(iconProviders, transformations, customIcon) { providers, transformations, ci -> + var icon = cache.get(searchable.key + customIcon.hashCode()) + if (icon != null) { + return@combine icon } + + val provs = if (ci != null) getProviders(ci) + providers else providers + val transforms = getTransformations(ci) ?: transformations + + icon = provs.getFirstIcon(searchable, size) + + if (icon != null) { + icon = icon.transform(transforms) + + cache.put(searchable.key + customIcon.hashCode(), icon) + } + return@combine icon } } diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/CalendarIconProvider.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/CalendarIconProvider.kt index f0c90e0a..93d1e623 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/CalendarIconProvider.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/CalendarIconProvider.kt @@ -8,39 +8,41 @@ import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.ktx.obtainTypedArrayOrNull import de.mm20.launcher2.search.SavableSearchable import de.mm20.launcher2.search.data.LauncherApp +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext class CalendarIconProvider(val context: Context, val themed: Boolean): IconProvider { - override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? { - if(searchable !is LauncherApp) return null + override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? = withContext(Dispatchers.IO) { + if(searchable !is LauncherApp) return@withContext null val component = ComponentName(searchable.`package`, searchable.activity) val pm = context.packageManager val ai = try { pm.getActivityInfo(component, PackageManager.GET_META_DATA) } catch (e: PackageManager.NameNotFoundException) { - return null + return@withContext null } var arrayId = ai.metaData?.getInt("com.teslacoilsw.launcher.calendarIconArray") ?: 0 if (arrayId == 0) arrayId = ai.metaData?.getInt("com.google.android.calendar.dynamic_icons") - ?: return null + ?: return@withContext null if (arrayId == 0) arrayId = ai.metaData?.getInt("org.lineageos.etar.dynamic_icons") - ?: return null - if (arrayId == 0) return null + ?: return@withContext null + if (arrayId == 0) return@withContext null val resources = try { pm.getResourcesForActivity(component) } catch (e: PackageManager.NameNotFoundException) { - return null + return@withContext null } - val typedArray = resources.obtainTypedArrayOrNull(arrayId) ?: return null + val typedArray = resources.obtainTypedArrayOrNull(arrayId) ?: return@withContext null if (typedArray.length() != 31) { typedArray.recycle() - return null + return@withContext null } val drawableIds = IntArray(31) for (i in 0 until 31) { drawableIds[i] = typedArray.getResourceId(i, 0) } typedArray.recycle() - return DynamicCalendarIcon( + return@withContext DynamicCalendarIcon( resources = resources, resourceIds = drawableIds, isThemed = themed diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/DynamicClockIconProvider.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/DynamicClockIconProvider.kt index 4f4975d9..172c8bc4 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/DynamicClockIconProvider.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/DynamicClockIconProvider.kt @@ -8,10 +8,12 @@ import de.mm20.launcher2.icons.compat.ClockIconConfig import de.mm20.launcher2.icons.compat.toLauncherIcon import de.mm20.launcher2.search.SavableSearchable import de.mm20.launcher2.search.data.LauncherApp +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext class DynamicClockIconProvider(val context: Context, private val themed: Boolean) : IconProvider { - override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? { - if (searchable !is LauncherApp) return null + override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? = withContext(Dispatchers.IO) { + if (searchable !is LauncherApp) return@withContext null val pm = context.packageManager val appInfo = try { pm.getApplicationInfo( @@ -19,22 +21,22 @@ class DynamicClockIconProvider(val context: Context, private val themed: Boolean PackageManager.GET_META_DATA ) } catch (e: PackageManager.NameNotFoundException) { - return null + return@withContext null } - if (appInfo.metaData == null) return null + if (appInfo.metaData == null) return@withContext null val drawableId = appInfo.metaData.getInt("com.android.launcher3.LEVEL_PER_TICK_ICON_ROUND") - if (drawableId == 0) return null + if (drawableId == 0) return@withContext null val resources = try { pm.getResourcesForApplication(appInfo) } catch (e: PackageManager.NameNotFoundException) { - return null + return@withContext null } - val icon = AdaptiveIconDrawableCompat.from(resources, drawableId) ?: return null + val icon = AdaptiveIconDrawableCompat.from(resources, drawableId) ?: return@withContext null val defaultHour = appInfo.metaData.getInt("com.android.launcher3.DEFAULT_HOUR") @@ -71,7 +73,7 @@ class DynamicClockIconProvider(val context: Context, private val themed: Boolean ) } - return icon.toLauncherIcon( + return@withContext icon.toLauncherIcon( themed = themed, clock = clockConfig ) diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/transformations/LegacyToAdaptiveTransformation.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/transformations/LegacyToAdaptiveTransformation.kt index 60d426be..c8592c3b 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/transformations/LegacyToAdaptiveTransformation.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/transformations/LegacyToAdaptiveTransformation.kt @@ -35,13 +35,13 @@ internal class LegacyToAdaptiveTransformation( if (layer is StaticIconLayer) { val drawable = layer.icon - val bitmap = if (drawable is BitmapDrawable) { - drawable.bitmap - } else { - drawable.toBitmap(48, 48) - } val palette = withContext(Dispatchers.Default) { + val bitmap = if (drawable is BitmapDrawable) { + drawable.bitmap + } else { + drawable.toBitmap(48, 48) + } Palette.from(bitmap).generate() } return palette.getDominantColor(0)