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