Improve icon search
This commit is contained in:
parent
bb8a0d4c0d
commit
9c5f1e971f
@ -79,14 +79,14 @@ sealed class CustomIcon : CustomAttribute {
|
|||||||
"custom_icon_pack_icon" -> {
|
"custom_icon_pack_icon" -> {
|
||||||
val legacyComponentName = payload.optString("icon").let { ComponentName.unflattenFromString(it) }
|
val legacyComponentName = payload.optString("icon").let { ComponentName.unflattenFromString(it) }
|
||||||
if (legacyComponentName != null) {
|
if (legacyComponentName != null) {
|
||||||
CustomIconPackIcon(
|
LegacyCustomIconPackIcon(
|
||||||
iconPackageName = legacyComponentName.packageName,
|
iconPackageName = legacyComponentName.packageName,
|
||||||
iconActivityName = legacyComponentName.className,
|
iconActivityName = legacyComponentName.className,
|
||||||
iconPackPackage = payload.getString("icon_pack"),
|
iconPackPackage = payload.getString("icon_pack"),
|
||||||
allowThemed = payload.optBoolean("allow_themed", true),
|
allowThemed = payload.optBoolean("allow_themed", true),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
CustomIconPackIcon(
|
LegacyCustomIconPackIcon(
|
||||||
iconPackageName = payload.optString("package").takeIf { it.isNotEmpty() } ?: return null,
|
iconPackageName = payload.optString("package").takeIf { it.isNotEmpty() } ?: return null,
|
||||||
iconActivityName = payload.optString("activity").takeIf { it.isNotEmpty() },
|
iconActivityName = payload.optString("activity").takeIf { it.isNotEmpty() },
|
||||||
iconPackPackage = payload.getString("icon_pack"),
|
iconPackPackage = payload.getString("icon_pack"),
|
||||||
@ -94,6 +94,15 @@ sealed class CustomIcon : CustomAttribute {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"custom_icon_pack_icon2" -> {
|
||||||
|
CustomIconPackIcon(
|
||||||
|
iconPackPackage = payload.getString("icon_pack"),
|
||||||
|
type = payload.getString("type"),
|
||||||
|
drawable = payload.optString("drawable"),
|
||||||
|
extras = payload.optString("extras").takeIf { it.isNotEmpty() },
|
||||||
|
allowThemed = payload.optBoolean("allow_themed", true),
|
||||||
|
)
|
||||||
|
}
|
||||||
"custom_themed_icon" -> {
|
"custom_themed_icon" -> {
|
||||||
CustomThemedIcon(
|
CustomThemedIcon(
|
||||||
iconPackageName = payload.getString("icon"),
|
iconPackageName = payload.getString("icon"),
|
||||||
@ -116,7 +125,8 @@ sealed class CustomIcon : CustomAttribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CustomIconPackIcon(
|
@Deprecated("Use CustomIconPackIcon instead")
|
||||||
|
data class LegacyCustomIconPackIcon(
|
||||||
val iconPackPackage: String,
|
val iconPackPackage: String,
|
||||||
val iconPackageName: String,
|
val iconPackageName: String,
|
||||||
val iconActivityName: String?,
|
val iconActivityName: String?,
|
||||||
@ -133,6 +143,28 @@ data class CustomIconPackIcon(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [type], [drawable], and [extras] correspond to the fields in [IconEntity]
|
||||||
|
*/
|
||||||
|
data class CustomIconPackIcon(
|
||||||
|
val iconPackPackage: String,
|
||||||
|
val type: String,
|
||||||
|
val drawable: String?,
|
||||||
|
val extras: String?,
|
||||||
|
val allowThemed: Boolean,
|
||||||
|
): CustomIcon() {
|
||||||
|
override fun toDatabaseValue(): String {
|
||||||
|
return jsonObjectOf(
|
||||||
|
"type" to "custom_icon_pack_icon2",
|
||||||
|
"icon_pack" to iconPackPackage,
|
||||||
|
"type" to type,
|
||||||
|
"drawable" to drawable,
|
||||||
|
"extras" to extras,
|
||||||
|
"allow_themed" to allowThemed,
|
||||||
|
).toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class AdaptifiedLegacyIcon(
|
data class AdaptifiedLegacyIcon(
|
||||||
val fgScale: Float,
|
val fgScale: Float,
|
||||||
/**
|
/**
|
||||||
@ -173,7 +205,7 @@ data class CustomThemedIcon(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ForceThemedIcon : CustomIcon() {
|
data object ForceThemedIcon : CustomIcon() {
|
||||||
override fun toDatabaseValue(): String {
|
override fun toDatabaseValue(): String {
|
||||||
return jsonObjectOf(
|
return jsonObjectOf(
|
||||||
"type" to "force_themed_icon"
|
"type" to "force_themed_icon"
|
||||||
@ -184,19 +216,18 @@ object ForceThemedIcon : CustomIcon() {
|
|||||||
/**
|
/**
|
||||||
* Use default icon, ignore any icon pack, themed icon or force adaptive settings.
|
* Use default icon, ignore any icon pack, themed icon or force adaptive settings.
|
||||||
*/
|
*/
|
||||||
object UnmodifiedSystemDefaultIcon: CustomIcon() {
|
data object UnmodifiedSystemDefaultIcon: CustomIcon() {
|
||||||
override fun toDatabaseValue(): String {
|
override fun toDatabaseValue(): String {
|
||||||
return jsonObjectOf(
|
return jsonObjectOf(
|
||||||
"type" to "default_icon"
|
"type" to "default_icon"
|
||||||
).toString()
|
).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the default placeholder icon
|
* Use the default placeholder icon
|
||||||
*/
|
*/
|
||||||
object DefaultPlaceholderIcon: CustomIcon() {
|
data object DefaultPlaceholderIcon: CustomIcon() {
|
||||||
override fun toDatabaseValue(): String {
|
override fun toDatabaseValue(): String {
|
||||||
return jsonObjectOf(
|
return jsonObjectOf(
|
||||||
"type" to "default_placeholder_icon"
|
"type" to "default_placeholder_icon"
|
||||||
|
|||||||
@ -13,12 +13,14 @@ interface IconDao {
|
|||||||
@Query("SELECT * FROM Icons WHERE packageName = :packageName AND (activityName = :activityName OR activityName IS NULL) AND iconPack = :iconPack AND type IN ('app', 'calendar', 'clock') ORDER BY type DESC LIMIT 1")
|
@Query("SELECT * FROM Icons WHERE packageName = :packageName AND (activityName = :activityName OR activityName IS NULL) AND iconPack = :iconPack AND type IN ('app', 'calendar', 'clock') ORDER BY type DESC LIMIT 1")
|
||||||
suspend fun getIcon(packageName: String, activityName: String?, iconPack: String): IconEntity?
|
suspend fun getIcon(packageName: String, activityName: String?, iconPack: String): IconEntity?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Icons WHERE drawable = :iconName AND iconPack = :iconPack ORDER BY type DESC LIMIT 1")
|
||||||
|
suspend fun getIcon(iconName: String, iconPack: String): IconEntity?
|
||||||
|
|
||||||
@Query("SELECT * FROM Icons WHERE packageName = :packageName AND (activityName = :activityName OR activityName IS NULL) AND type IN ('app', 'calendar', 'clock')")
|
@Query("SELECT * FROM Icons WHERE packageName = :packageName AND (activityName = :activityName OR activityName IS NULL) AND type IN ('app', 'calendar', 'clock')")
|
||||||
suspend fun getIconsFromAllPacks(packageName: String, activityName: String): List<IconEntity>
|
suspend fun getIconsFromAllPacks(packageName: String, activityName: String): List<IconEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM Icons WHERE type IN ('app', 'calendar', 'clock') AND (drawable LIKE :drawableQuery OR packageName LIKE :componentQuery OR activityName LIKE :componentQuery OR name LIKE :nameQuery) AND (:iconPack IS NULL OR iconPack = :iconPack) GROUP BY drawable ORDER BY iconPack, drawable LIMIT :limit")
|
@Query("SELECT * FROM Icons WHERE type IN ('app', 'calendar', 'clock') AND (drawable LIKE :drawableQuery OR name LIKE :nameQuery) AND (:iconPack IS NULL OR iconPack = :iconPack) GROUP BY drawable, iconPack, type ORDER BY type DESC, iconPack, drawable LIMIT :limit")
|
||||||
suspend fun searchIconPackIcons(
|
suspend fun searchIconPackIcons(
|
||||||
componentQuery: String,
|
|
||||||
nameQuery: String,
|
nameQuery: String,
|
||||||
drawableQuery: String,
|
drawableQuery: String,
|
||||||
iconPack: String?,
|
iconPack: String?,
|
||||||
|
|||||||
@ -11,7 +11,7 @@ sealed interface IconPackComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sealed interface IconPackAppIcon: IconPackComponent {
|
sealed interface IconPackAppIcon: IconPackComponent {
|
||||||
val packageName: String
|
val packageName: String?
|
||||||
val activityName: String?
|
val activityName: String?
|
||||||
val name: String?
|
val name: String?
|
||||||
val themed: Boolean
|
val themed: Boolean
|
||||||
@ -59,9 +59,9 @@ data class IconMask(
|
|||||||
data class AppIcon(
|
data class AppIcon(
|
||||||
val drawable: String,
|
val drawable: String,
|
||||||
override val iconPack: String,
|
override val iconPack: String,
|
||||||
override val packageName: String,
|
override val packageName: String? = null,
|
||||||
override val activityName: String?,
|
override val activityName: String? = null,
|
||||||
override val name: String?,
|
override val name: String? = null,
|
||||||
override val themed: Boolean = false,
|
override val themed: Boolean = false,
|
||||||
): IconPackComponent, IconPackAppIcon {
|
): IconPackComponent, IconPackAppIcon {
|
||||||
override fun toDatabaseEntity(): IconEntity {
|
override fun toDatabaseEntity(): IconEntity {
|
||||||
@ -80,7 +80,7 @@ data class AppIcon(
|
|||||||
data class CalendarIcon(
|
data class CalendarIcon(
|
||||||
val drawables: List<String>,
|
val drawables: List<String>,
|
||||||
override val iconPack: String,
|
override val iconPack: String,
|
||||||
override val packageName: String,
|
override val packageName: String?,
|
||||||
override val activityName: String? = null,
|
override val activityName: String? = null,
|
||||||
override val name: String? = null,
|
override val name: String? = null,
|
||||||
override val themed: Boolean = false,
|
override val themed: Boolean = false,
|
||||||
@ -102,7 +102,7 @@ data class CalendarIcon(
|
|||||||
data class ClockIcon(
|
data class ClockIcon(
|
||||||
val drawable: String,
|
val drawable: String,
|
||||||
override val iconPack: String,
|
override val iconPack: String,
|
||||||
override val packageName: String,
|
override val packageName: String? = null,
|
||||||
override val activityName: String? = null,
|
override val activityName: String? = null,
|
||||||
override val name: String? = null,
|
override val name: String? = null,
|
||||||
override val themed: Boolean,
|
override val themed: Boolean,
|
||||||
@ -146,7 +146,7 @@ fun Icon(entity: IconEntity): IconPackComponent? {
|
|||||||
"app" -> AppIcon(
|
"app" -> AppIcon(
|
||||||
drawable = entity.drawable ?: return null,
|
drawable = entity.drawable ?: return null,
|
||||||
iconPack = entity.iconPack,
|
iconPack = entity.iconPack,
|
||||||
packageName = entity.packageName ?: return null,
|
packageName = entity.packageName,
|
||||||
activityName = entity.activityName,
|
activityName = entity.activityName,
|
||||||
themed = entity.themed,
|
themed = entity.themed,
|
||||||
name = entity.name,
|
name = entity.name,
|
||||||
@ -155,7 +155,7 @@ fun Icon(entity: IconEntity): IconPackComponent? {
|
|||||||
drawables = entity.drawable?.split(",") ?: return null,
|
drawables = entity.drawable?.split(",") ?: return null,
|
||||||
iconPack = entity.iconPack,
|
iconPack = entity.iconPack,
|
||||||
themed = entity.themed,
|
themed = entity.themed,
|
||||||
packageName = entity.packageName ?: return null,
|
packageName = entity.packageName,
|
||||||
activityName = entity.activityName,
|
activityName = entity.activityName,
|
||||||
name = entity.name,
|
name = entity.name,
|
||||||
)
|
)
|
||||||
@ -164,7 +164,7 @@ fun Icon(entity: IconEntity): IconPackComponent? {
|
|||||||
ClockIcon(
|
ClockIcon(
|
||||||
drawable = entity.drawable!!,
|
drawable = entity.drawable!!,
|
||||||
iconPack = entity.iconPack,
|
iconPack = entity.iconPack,
|
||||||
packageName = entity.packageName ?: return null,
|
packageName = entity.packageName,
|
||||||
name = entity.name,
|
name = entity.name,
|
||||||
activityName = entity.activityName,
|
activityName = entity.activityName,
|
||||||
themed = entity.themed,
|
themed = entity.themed,
|
||||||
|
|||||||
@ -112,6 +112,27 @@ class IconPackManager(
|
|||||||
return@withContext null
|
return@withContext null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getIcon(
|
||||||
|
iconPack: String,
|
||||||
|
icon: IconPackAppIcon,
|
||||||
|
allowThemed: Boolean,
|
||||||
|
): 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@withContext null
|
||||||
|
}
|
||||||
|
if (icon is CalendarIcon) {
|
||||||
|
return@withContext getIconPackCalendarIcon(icon, res, allowThemed)
|
||||||
|
} else if (icon is AppIcon) {
|
||||||
|
return@withContext getIconPackStaticIcon(icon, res, allowThemed)
|
||||||
|
} else if (icon is ClockIcon) {
|
||||||
|
return@withContext getIconPackClockIcon(icon, res, allowThemed)
|
||||||
|
}
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun generateIcon(
|
suspend fun generateIcon(
|
||||||
context: Context,
|
context: Context,
|
||||||
iconPack: String,
|
iconPack: String,
|
||||||
@ -448,12 +469,11 @@ class IconPackManager(
|
|||||||
val drawableQuery = query.replace(" ", "_").lowercase()
|
val drawableQuery = query.replace(" ", "_").lowercase()
|
||||||
return iconDao.searchIconPackIcons(
|
return iconDao.searchIconPackIcons(
|
||||||
drawableQuery = "%$drawableQuery%",
|
drawableQuery = "%$drawableQuery%",
|
||||||
componentQuery = "%$query%",
|
|
||||||
nameQuery = "%$query%",
|
nameQuery = "%$query%",
|
||||||
iconPack = iconPack?.packageName,
|
iconPack = iconPack?.packageName,
|
||||||
).mapNotNull {
|
).mapNotNull {
|
||||||
IconPackAppIcon(it)
|
IconPackAppIcon(it)
|
||||||
}
|
}.distinct()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import de.mm20.launcher2.data.customattrs.AdaptifiedLegacyIcon
|
|||||||
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
||||||
import de.mm20.launcher2.data.customattrs.CustomIcon
|
import de.mm20.launcher2.data.customattrs.CustomIcon
|
||||||
import de.mm20.launcher2.data.customattrs.CustomIconPackIcon
|
import de.mm20.launcher2.data.customattrs.CustomIconPackIcon
|
||||||
|
import de.mm20.launcher2.data.customattrs.LegacyCustomIconPackIcon
|
||||||
import de.mm20.launcher2.data.customattrs.CustomThemedIcon
|
import de.mm20.launcher2.data.customattrs.CustomThemedIcon
|
||||||
import de.mm20.launcher2.data.customattrs.DefaultPlaceholderIcon
|
import de.mm20.launcher2.data.customattrs.DefaultPlaceholderIcon
|
||||||
import de.mm20.launcher2.data.customattrs.ForceThemedIcon
|
import de.mm20.launcher2.data.customattrs.ForceThemedIcon
|
||||||
@ -18,6 +19,7 @@ import de.mm20.launcher2.data.customattrs.UnmodifiedSystemDefaultIcon
|
|||||||
import de.mm20.launcher2.icons.providers.CalendarIconProvider
|
import de.mm20.launcher2.icons.providers.CalendarIconProvider
|
||||||
import de.mm20.launcher2.icons.providers.CompatIconProvider
|
import de.mm20.launcher2.icons.providers.CompatIconProvider
|
||||||
import de.mm20.launcher2.icons.providers.CustomIconPackIconProvider
|
import de.mm20.launcher2.icons.providers.CustomIconPackIconProvider
|
||||||
|
import de.mm20.launcher2.icons.providers.LegacyCustomIconPackIconProvider
|
||||||
import de.mm20.launcher2.icons.providers.CustomThemedIconProvider
|
import de.mm20.launcher2.icons.providers.CustomThemedIconProvider
|
||||||
import de.mm20.launcher2.icons.providers.DynamicClockIconProvider
|
import de.mm20.launcher2.icons.providers.DynamicClockIconProvider
|
||||||
import de.mm20.launcher2.icons.providers.IconPackIconProvider
|
import de.mm20.launcher2.icons.providers.IconPackIconProvider
|
||||||
@ -44,7 +46,6 @@ import kotlinx.coroutines.flow.collectLatest
|
|||||||
import kotlinx.coroutines.flow.combine
|
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.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class IconService(
|
class IconService(
|
||||||
@ -174,6 +175,14 @@ class IconService(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (customIcon is LegacyCustomIconPackIcon) {
|
||||||
|
return listOf(
|
||||||
|
LegacyCustomIconPackIconProvider(
|
||||||
|
customIcon,
|
||||||
|
iconPackManager
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
if (customIcon is CustomThemedIcon) {
|
if (customIcon is CustomThemedIcon) {
|
||||||
return listOf(
|
return listOf(
|
||||||
CustomThemedIconProvider(
|
CustomThemedIconProvider(
|
||||||
@ -288,11 +297,14 @@ class IconService(
|
|||||||
)
|
)
|
||||||
|
|
||||||
providerOptions.addAll(
|
providerOptions.addAll(
|
||||||
iconPackIcons.mapNotNull {
|
iconPackIcons.map {
|
||||||
|
val ent = it.toDatabaseEntity()
|
||||||
CustomIconPackIcon(
|
CustomIconPackIcon(
|
||||||
iconPackPackage = it.iconPack,
|
iconPackPackage = it.iconPack,
|
||||||
iconActivityName = it.activityName,
|
type = ent.type,
|
||||||
iconPackageName = it.packageName,
|
drawable = ent.drawable,
|
||||||
|
extras = ent.extras,
|
||||||
|
allowThemed = it.themed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -356,20 +368,22 @@ class IconService(
|
|||||||
val transformations = this.transformations.first()
|
val transformations = this.transformations.first()
|
||||||
val iconPackIcons = iconPackManager.searchIconPackIcon(query, iconPack).flatMap {
|
val iconPackIcons = iconPackManager.searchIconPackIcon(query, iconPack).flatMap {
|
||||||
val unthemedIcon = if (it.themed) {
|
val unthemedIcon = if (it.themed) {
|
||||||
iconPackManager.getIcon(it.iconPack, it.packageName, it.activityName, false)
|
iconPackManager.getIcon(it.iconPack, it, false)
|
||||||
?.transform(transformations)
|
?.transform(transformations)
|
||||||
} else null
|
} else null
|
||||||
val icon = iconPackManager.getIcon(it.iconPack, it.packageName, it.activityName, true)
|
val icon = iconPackManager.getIcon(it.iconPack, it, true)
|
||||||
?.transform(transformations)
|
?.transform(transformations)
|
||||||
|
|
||||||
buildList<CustomIconWithPreview> {
|
buildList {
|
||||||
|
val ent = it.toDatabaseEntity()
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
add(CustomIconWithPreview(
|
add(CustomIconWithPreview(
|
||||||
customIcon = CustomIconPackIcon(
|
customIcon = CustomIconPackIcon(
|
||||||
iconPackPackage = it.iconPack,
|
iconPackPackage = it.iconPack,
|
||||||
iconActivityName = it.activityName,
|
type = ent.type,
|
||||||
iconPackageName = it.packageName,
|
drawable = ent.drawable,
|
||||||
allowThemed = true
|
extras = ent.extras,
|
||||||
|
allowThemed = true,
|
||||||
),
|
),
|
||||||
preview = icon
|
preview = icon
|
||||||
))
|
))
|
||||||
@ -378,9 +392,10 @@ class IconService(
|
|||||||
add(CustomIconWithPreview(
|
add(CustomIconWithPreview(
|
||||||
customIcon = CustomIconPackIcon(
|
customIcon = CustomIconPackIcon(
|
||||||
iconPackPackage = it.iconPack,
|
iconPackPackage = it.iconPack,
|
||||||
iconActivityName = it.activityName,
|
type = ent.type,
|
||||||
iconPackageName = it.packageName,
|
drawable = ent.drawable,
|
||||||
allowThemed = false
|
extras = ent.extras,
|
||||||
|
allowThemed = false,
|
||||||
),
|
),
|
||||||
preview = unthemedIcon
|
preview = unthemedIcon
|
||||||
))
|
))
|
||||||
|
|||||||
@ -30,138 +30,181 @@ class AppFilterIconPackInstaller(
|
|||||||
) : IconPackInstaller(database) {
|
) : IconPackInstaller(database) {
|
||||||
override suspend fun IconPackInstallerScope.buildIconPack(iconPack: IconPack) {
|
override suspend fun IconPackInstallerScope.buildIconPack(iconPack: IconPack) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val pkgName = iconPack.packageName
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val dynamicClocks = getDynamicClockIcons(pkgName)
|
val dynamicClocks = getDynamicClockIcons(iconPack.packageName)
|
||||||
val parser = getAppfilterParser(pkgName) ?: return@withContext
|
|
||||||
|
|
||||||
loop@ while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
parseAppfilterXml(iconPack, dynamicClocks)
|
||||||
if (parser.eventType != XmlPullParser.START_TAG) continue
|
parseDrawableXml(iconPack, dynamicClocks)
|
||||||
when (parser.name) {
|
|
||||||
"item" -> {
|
|
||||||
val component = parser.getAttributeValue(null, "component")
|
|
||||||
?: continue@loop
|
|
||||||
val drawable = parser.getAttributeValue(null, "drawable")
|
|
||||||
?: continue@loop
|
|
||||||
if (component.length <= 14) continue@loop
|
|
||||||
val componentName = ComponentName.unflattenFromString(
|
|
||||||
component.substring(
|
|
||||||
14,
|
|
||||||
component.lastIndex
|
|
||||||
)
|
|
||||||
)
|
|
||||||
?: continue@loop
|
|
||||||
|
|
||||||
val name = parser.getAttributeValue(null, "name")
|
Log.d("MM20", "Icon pack ${iconPack.packageName} has been installed successfully")
|
||||||
|
|
||||||
|
|
||||||
val icon = if (dynamicClocks.containsKey(drawable)) {
|
|
||||||
ClockIcon(
|
|
||||||
packageName = componentName.packageName,
|
|
||||||
activityName = componentName.shortClassName,
|
|
||||||
iconPack = pkgName,
|
|
||||||
themed = iconPack.themed,
|
|
||||||
name = name,
|
|
||||||
drawable = drawable,
|
|
||||||
config = dynamicClocks[drawable]!!,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
AppIcon(
|
|
||||||
packageName = componentName.packageName,
|
|
||||||
activityName = componentName.shortClassName,
|
|
||||||
drawable = drawable,
|
|
||||||
iconPack = pkgName,
|
|
||||||
name = name,
|
|
||||||
themed = iconPack.themed,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
addIcon(icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
"calendar" -> {
|
|
||||||
val component = parser.getAttributeValue(null, "component")
|
|
||||||
?: continue@loop
|
|
||||||
val drawable = parser.getAttributeValue(null, "prefix") ?: continue@loop
|
|
||||||
if (component.length < 14) continue@loop
|
|
||||||
val componentName = ComponentName.unflattenFromString(
|
|
||||||
component.substring(
|
|
||||||
14,
|
|
||||||
component.lastIndex
|
|
||||||
)
|
|
||||||
)
|
|
||||||
?: continue@loop
|
|
||||||
|
|
||||||
val name = parser.getAttributeValue(null, "name")
|
|
||||||
|
|
||||||
val icon = CalendarIcon(
|
|
||||||
packageName = componentName.packageName,
|
|
||||||
activityName = componentName.shortClassName,
|
|
||||||
drawables = (1..31).map { "$drawable$it" },
|
|
||||||
iconPack = pkgName,
|
|
||||||
themed = iconPack.themed,
|
|
||||||
name = name,
|
|
||||||
)
|
|
||||||
addIcon(icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
"iconback" -> {
|
|
||||||
for (i in 0 until parser.attributeCount) {
|
|
||||||
if (parser.getAttributeName(i).startsWith("img")) {
|
|
||||||
val drawable = parser.getAttributeValue(i)
|
|
||||||
val icon = IconBack(
|
|
||||||
drawable = drawable,
|
|
||||||
iconPack = pkgName,
|
|
||||||
)
|
|
||||||
addIcon(icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"iconupon" -> {
|
|
||||||
for (i in 0 until parser.attributeCount) {
|
|
||||||
if (parser.getAttributeName(i).startsWith("img")) {
|
|
||||||
val drawable = parser.getAttributeValue(i)
|
|
||||||
val icon = IconUpon(
|
|
||||||
drawable = drawable,
|
|
||||||
iconPack = pkgName,
|
|
||||||
)
|
|
||||||
addIcon(icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"iconmask" -> {
|
|
||||||
for (i in 0 until parser.attributeCount) {
|
|
||||||
if (parser.getAttributeName(i).startsWith("img")) {
|
|
||||||
val drawable = parser.getAttributeValue(i)
|
|
||||||
val icon = IconMask(
|
|
||||||
drawable = drawable,
|
|
||||||
iconPack = pkgName,
|
|
||||||
)
|
|
||||||
addIcon(icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"scale" -> {
|
|
||||||
val scale = parser.getAttributeValue(null, "factor")?.toFloatOrNull()
|
|
||||||
?: continue@loop
|
|
||||||
updatePackInfo { it.copy(scale = scale) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parser.close()
|
|
||||||
|
|
||||||
Log.d("MM20", "Icon pack $pkgName has been installed successfully")
|
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
Log.e("MM20", "Could not install icon pack $pkgName: package not found.")
|
Log.e(
|
||||||
|
"MM20",
|
||||||
|
"Could not install icon pack ${iconPack.packageName}: package not found."
|
||||||
|
)
|
||||||
} catch (e: XmlPullParserException) {
|
} catch (e: XmlPullParserException) {
|
||||||
CrashReporter.logException(e)
|
CrashReporter.logException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun IconPackInstallerScope.parseAppfilterXml(
|
||||||
|
iconPack: IconPack,
|
||||||
|
dynamicClocks: Map<String, ClockIconConfig>
|
||||||
|
) {
|
||||||
|
val pkgName = iconPack.packageName
|
||||||
|
val parser = getAppfilterParser(pkgName) ?: return
|
||||||
|
|
||||||
|
loop@ while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (parser.eventType != XmlPullParser.START_TAG) continue
|
||||||
|
when (parser.name) {
|
||||||
|
"item" -> {
|
||||||
|
val component = parser.getAttributeValue(null, "component")
|
||||||
|
?: continue@loop
|
||||||
|
val drawable = parser.getAttributeValue(null, "drawable")
|
||||||
|
?: continue@loop
|
||||||
|
if (component.length <= 14) continue@loop
|
||||||
|
val componentName = ComponentName.unflattenFromString(
|
||||||
|
component.substring(
|
||||||
|
14,
|
||||||
|
component.lastIndex
|
||||||
|
)
|
||||||
|
)
|
||||||
|
?: continue@loop
|
||||||
|
|
||||||
|
val name = parser.getAttributeValue(null, "name")
|
||||||
|
|
||||||
|
|
||||||
|
val icon = if (dynamicClocks.containsKey(drawable)) {
|
||||||
|
ClockIcon(
|
||||||
|
packageName = componentName.packageName,
|
||||||
|
activityName = componentName.shortClassName,
|
||||||
|
iconPack = pkgName,
|
||||||
|
themed = iconPack.themed,
|
||||||
|
name = name,
|
||||||
|
drawable = drawable,
|
||||||
|
config = dynamicClocks[drawable]!!,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AppIcon(
|
||||||
|
packageName = componentName.packageName,
|
||||||
|
activityName = componentName.shortClassName,
|
||||||
|
drawable = drawable,
|
||||||
|
iconPack = pkgName,
|
||||||
|
name = name,
|
||||||
|
themed = iconPack.themed,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addIcon(icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
"calendar" -> {
|
||||||
|
val component = parser.getAttributeValue(null, "component")
|
||||||
|
?: continue@loop
|
||||||
|
val drawable = parser.getAttributeValue(null, "prefix") ?: continue@loop
|
||||||
|
if (component.length < 14) continue@loop
|
||||||
|
val componentName = ComponentName.unflattenFromString(
|
||||||
|
component.substring(
|
||||||
|
14,
|
||||||
|
component.lastIndex
|
||||||
|
)
|
||||||
|
)
|
||||||
|
?: continue@loop
|
||||||
|
|
||||||
|
val name = parser.getAttributeValue(null, "name")
|
||||||
|
|
||||||
|
val icon = CalendarIcon(
|
||||||
|
packageName = componentName.packageName,
|
||||||
|
activityName = componentName.shortClassName,
|
||||||
|
drawables = (1..31).map { "$drawable$it" },
|
||||||
|
iconPack = pkgName,
|
||||||
|
themed = iconPack.themed,
|
||||||
|
name = name,
|
||||||
|
)
|
||||||
|
addIcon(icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
"iconback" -> {
|
||||||
|
for (i in 0 until parser.attributeCount) {
|
||||||
|
if (parser.getAttributeName(i).startsWith("img")) {
|
||||||
|
val drawable = parser.getAttributeValue(i)
|
||||||
|
val icon = IconBack(
|
||||||
|
drawable = drawable,
|
||||||
|
iconPack = pkgName,
|
||||||
|
)
|
||||||
|
addIcon(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"iconupon" -> {
|
||||||
|
for (i in 0 until parser.attributeCount) {
|
||||||
|
if (parser.getAttributeName(i).startsWith("img")) {
|
||||||
|
val drawable = parser.getAttributeValue(i)
|
||||||
|
val icon = IconUpon(
|
||||||
|
drawable = drawable,
|
||||||
|
iconPack = pkgName,
|
||||||
|
)
|
||||||
|
addIcon(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"iconmask" -> {
|
||||||
|
for (i in 0 until parser.attributeCount) {
|
||||||
|
if (parser.getAttributeName(i).startsWith("img")) {
|
||||||
|
val drawable = parser.getAttributeValue(i)
|
||||||
|
val icon = IconMask(
|
||||||
|
drawable = drawable,
|
||||||
|
iconPack = pkgName,
|
||||||
|
)
|
||||||
|
addIcon(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"scale" -> {
|
||||||
|
val scale = parser.getAttributeValue(null, "factor")?.toFloatOrNull()
|
||||||
|
?: continue@loop
|
||||||
|
updatePackInfo { it.copy(scale = scale) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun IconPackInstallerScope.parseDrawableXml(
|
||||||
|
iconPack: IconPack,
|
||||||
|
dynamicClocks: Map<String, ClockIconConfig>
|
||||||
|
) {
|
||||||
|
val res = context.packageManager.getResourcesForApplication(iconPack.packageName)
|
||||||
|
val xmlId = res.getIdentifier("drawable", "xml", iconPack.packageName)
|
||||||
|
if (xmlId == 0) return
|
||||||
|
val parser = res.getXml(xmlId)
|
||||||
|
loop@ while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (parser.eventType != XmlPullParser.START_TAG) continue
|
||||||
|
if (parser.name == "item") {
|
||||||
|
val drawable = parser.getAttributeValue(null, "drawable") ?: continue@loop
|
||||||
|
val icon = if (dynamicClocks.containsKey(drawable)) {
|
||||||
|
ClockIcon(
|
||||||
|
iconPack = iconPack.packageName,
|
||||||
|
themed = iconPack.themed,
|
||||||
|
drawable = drawable,
|
||||||
|
config = dynamicClocks[drawable]!!,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AppIcon(
|
||||||
|
drawable = drawable,
|
||||||
|
iconPack = iconPack.packageName,
|
||||||
|
themed = iconPack.themed,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addIcon(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser.close()
|
||||||
|
}
|
||||||
|
|
||||||
private fun getDynamicClockIcons(packageName: String): Map<String, ClockIconConfig> {
|
private fun getDynamicClockIcons(packageName: String): Map<String, ClockIconConfig> {
|
||||||
val parser = getAppfilterParser(packageName) ?: return emptyMap()
|
val parser = getAppfilterParser(packageName) ?: return emptyMap()
|
||||||
val map = mutableMapOf<String, ClockIconConfig>()
|
val map = mutableMapOf<String, ClockIconConfig>()
|
||||||
@ -190,6 +233,7 @@ class AppFilterIconPackInstaller(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
parser.close()
|
||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
package de.mm20.launcher2.icons.providers
|
package de.mm20.launcher2.icons.providers
|
||||||
|
|
||||||
import android.content.ComponentName
|
|
||||||
import de.mm20.launcher2.data.customattrs.CustomIconPackIcon
|
import de.mm20.launcher2.data.customattrs.CustomIconPackIcon
|
||||||
|
import de.mm20.launcher2.database.entities.IconEntity
|
||||||
|
import de.mm20.launcher2.icons.IconPackAppIcon
|
||||||
import de.mm20.launcher2.icons.IconPackManager
|
import de.mm20.launcher2.icons.IconPackManager
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
@ -11,10 +12,16 @@ class CustomIconPackIconProvider(
|
|||||||
private val iconPackManager: IconPackManager,
|
private val iconPackManager: IconPackManager,
|
||||||
) : IconProvider {
|
) : IconProvider {
|
||||||
override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? {
|
override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? {
|
||||||
|
val ent = IconEntity(
|
||||||
|
type = customIcon.type,
|
||||||
|
drawable = customIcon.drawable,
|
||||||
|
extras = customIcon.extras,
|
||||||
|
iconPack = customIcon.iconPackPackage,
|
||||||
|
)
|
||||||
|
val icon = IconPackAppIcon(ent) ?: return null
|
||||||
return iconPackManager.getIcon(
|
return iconPackManager.getIcon(
|
||||||
customIcon.iconPackPackage,
|
customIcon.iconPackPackage,
|
||||||
customIcon.iconPackageName,
|
icon,
|
||||||
customIcon.iconActivityName,
|
|
||||||
customIcon.allowThemed,
|
customIcon.allowThemed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
package de.mm20.launcher2.icons.providers
|
||||||
|
|
||||||
|
import de.mm20.launcher2.data.customattrs.LegacyCustomIconPackIcon
|
||||||
|
import de.mm20.launcher2.icons.IconPackManager
|
||||||
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
|
|
||||||
|
@Deprecated("Use CustomIconPackIconProvider instead")
|
||||||
|
class LegacyCustomIconPackIconProvider(
|
||||||
|
private val customIcon: LegacyCustomIconPackIcon,
|
||||||
|
private val iconPackManager: IconPackManager,
|
||||||
|
) : IconProvider {
|
||||||
|
override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? {
|
||||||
|
return iconPackManager.getIcon(
|
||||||
|
customIcon.iconPackPackage,
|
||||||
|
customIcon.iconPackageName,
|
||||||
|
customIcon.iconActivityName,
|
||||||
|
customIcon.allowThemed,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user