Optimize icon loading

This commit is contained in:
MM20 2023-07-20 19:40:00 +02:00
parent 6ea9751535
commit 1241067357
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
5 changed files with 64 additions and 64 deletions

View File

@ -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,

View File

@ -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<LauncherIcon> = 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<LauncherIcon> {
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
}
}

View File

@ -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

View File

@ -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
)

View File

@ -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)