Add support for dynamic clock icons in icon packs
This commit is contained in:
parent
2f610f1884
commit
2806032b48
@ -10,10 +10,12 @@ import de.mm20.launcher2.crashreporter.CrashReporter
|
|||||||
import de.mm20.launcher2.database.AppDatabase
|
import de.mm20.launcher2.database.AppDatabase
|
||||||
import de.mm20.launcher2.icons.AppIcon
|
import de.mm20.launcher2.icons.AppIcon
|
||||||
import de.mm20.launcher2.icons.CalendarIcon
|
import de.mm20.launcher2.icons.CalendarIcon
|
||||||
|
import de.mm20.launcher2.icons.ClockIcon
|
||||||
import de.mm20.launcher2.icons.IconBack
|
import de.mm20.launcher2.icons.IconBack
|
||||||
import de.mm20.launcher2.icons.IconMask
|
import de.mm20.launcher2.icons.IconMask
|
||||||
import de.mm20.launcher2.icons.IconPack
|
import de.mm20.launcher2.icons.IconPack
|
||||||
import de.mm20.launcher2.icons.IconUpon
|
import de.mm20.launcher2.icons.IconUpon
|
||||||
|
import de.mm20.launcher2.icons.compat.ClockIconConfig
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
@ -31,40 +33,8 @@ class AppFilterIconPackInstaller(
|
|||||||
val pkgName = iconPack.packageName
|
val pkgName = iconPack.packageName
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val res = context.packageManager.getResourcesForApplication(pkgName)
|
val dynamicClocks = getDynamicClockIcons(pkgName)
|
||||||
val parser: XmlPullParser
|
val parser = getAppfilterParser(pkgName) ?: return@withContext
|
||||||
var inStream: Reader? = null
|
|
||||||
val xmlId = res.getIdentifier("appfilter", "xml", pkgName)
|
|
||||||
val rawId = res.getIdentifier("appfilter", "raw", pkgName)
|
|
||||||
parser = when {
|
|
||||||
xmlId != 0 -> res.getXml(xmlId)
|
|
||||||
rawId != 0 -> {
|
|
||||||
inStream = res.openRawResource(rawId).reader()
|
|
||||||
XmlPullParserFactory.newInstance().newPullParser().apply {
|
|
||||||
setInput(inStream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
val iconPackContext = context.createPackageContext(
|
|
||||||
pkgName,
|
|
||||||
Context.CONTEXT_IGNORE_SECURITY
|
|
||||||
)
|
|
||||||
inStream = try {
|
|
||||||
iconPackContext.assets.open("appfilter.xml").reader()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
CrashReporter.logException(e)
|
|
||||||
Log.e(
|
|
||||||
"MM20",
|
|
||||||
"appfilter.xml not found in $pkgName. Searched locations: res/xml/appfilter.xml, res/raw/appfilter.xml, assets/appfilter.xml"
|
|
||||||
)
|
|
||||||
return@withContext
|
|
||||||
}
|
|
||||||
XmlPullParserFactory.newInstance().newPullParser().apply {
|
|
||||||
setInput(inStream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loop@ while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
loop@ while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
if (parser.eventType != XmlPullParser.START_TAG) continue
|
if (parser.eventType != XmlPullParser.START_TAG) continue
|
||||||
@ -85,7 +55,19 @@ class AppFilterIconPackInstaller(
|
|||||||
|
|
||||||
val name = parser.getAttributeValue(null, "name")
|
val name = parser.getAttributeValue(null, "name")
|
||||||
|
|
||||||
val icon = AppIcon(
|
|
||||||
|
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,
|
packageName = componentName.packageName,
|
||||||
activityName = componentName.shortClassName,
|
activityName = componentName.shortClassName,
|
||||||
drawable = drawable,
|
drawable = drawable,
|
||||||
@ -93,6 +75,7 @@ class AppFilterIconPackInstaller(
|
|||||||
name = name,
|
name = name,
|
||||||
themed = iconPack.themed,
|
themed = iconPack.themed,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
addIcon(icon)
|
addIcon(icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,8 +151,7 @@ class AppFilterIconPackInstaller(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(parser as? XmlResourceParser)?.close()
|
parser.close()
|
||||||
inStream?.close()
|
|
||||||
|
|
||||||
Log.d("MM20", "Icon pack $pkgName has been installed successfully")
|
Log.d("MM20", "Icon pack $pkgName has been installed successfully")
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
@ -180,6 +162,74 @@ class AppFilterIconPackInstaller(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getDynamicClockIcons(packageName: String): Map<String, ClockIconConfig> {
|
||||||
|
val parser = getAppfilterParser(packageName) ?: return emptyMap()
|
||||||
|
val map = mutableMapOf<String, ClockIconConfig>()
|
||||||
|
loop@ while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (parser.eventType != XmlPullParser.START_TAG) continue
|
||||||
|
if (parser.name == "dynamic-clock") {
|
||||||
|
val drawable = parser.getAttributeValue(null, "drawable") ?: continue@loop
|
||||||
|
val defaultHour = parser.getAttributeValue(null, "defaultHour")?.toIntOrNull() ?: 0
|
||||||
|
val defaultMinute =
|
||||||
|
parser.getAttributeValue(null, "defaultMinute")?.toIntOrNull() ?: 0
|
||||||
|
val defaultSecond =
|
||||||
|
parser.getAttributeValue(null, "defaultSecond")?.toIntOrNull() ?: 0
|
||||||
|
val hourLayerIndex =
|
||||||
|
parser.getAttributeValue(null, "hourLayerIndex")?.toIntOrNull() ?: -1
|
||||||
|
val minuteLayerIndex =
|
||||||
|
parser.getAttributeValue(null, "minuteLayerIndex")?.toIntOrNull() ?: -1
|
||||||
|
val secondLayerIndex =
|
||||||
|
parser.getAttributeValue(null, "secondLayerIndex")?.toIntOrNull() ?: -1
|
||||||
|
map[drawable] = ClockIconConfig(
|
||||||
|
defaultHour = defaultHour,
|
||||||
|
defaultMinute = defaultMinute,
|
||||||
|
defaultSecond = defaultSecond,
|
||||||
|
hourLayer = hourLayerIndex,
|
||||||
|
minuteLayer = minuteLayerIndex,
|
||||||
|
secondLayer = secondLayerIndex,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAppfilterParser(packageName: String): ClosableXmlParser? {
|
||||||
|
val res = context.packageManager.getResourcesForApplication(packageName)
|
||||||
|
val xmlId = res.getIdentifier("appfilter", "xml", packageName)
|
||||||
|
val rawId = res.getIdentifier("appfilter", "raw", packageName)
|
||||||
|
return when {
|
||||||
|
xmlId != 0 -> ClosableXmlResourceParser(res.getXml(xmlId))
|
||||||
|
rawId != 0 -> {
|
||||||
|
val inStream = res.openRawResource(rawId).reader()
|
||||||
|
val parser = XmlPullParserFactory.newInstance().newPullParser().apply {
|
||||||
|
setInput(inStream)
|
||||||
|
}
|
||||||
|
ClosableXmlPullParser(parser, inStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val iconPackContext = context.createPackageContext(
|
||||||
|
packageName,
|
||||||
|
Context.CONTEXT_IGNORE_SECURITY
|
||||||
|
)
|
||||||
|
val inStream = try {
|
||||||
|
iconPackContext.assets.open("appfilter.xml").reader()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
CrashReporter.logException(e)
|
||||||
|
Log.e(
|
||||||
|
"MM20",
|
||||||
|
"appfilter.xml not found in $packageName. Searched locations: res/xml/appfilter.xml, res/raw/appfilter.xml, assets/appfilter.xml"
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val parser = XmlPullParserFactory.newInstance().newPullParser().apply {
|
||||||
|
setInput(inStream)
|
||||||
|
}
|
||||||
|
ClosableXmlPullParser(parser, inStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getInstalledIconPacks(): List<IconPack> {
|
override fun getInstalledIconPacks(): List<IconPack> {
|
||||||
val packs = mutableListOf<IconPack>()
|
val packs = mutableListOf<IconPack>()
|
||||||
val pm = context.packageManager
|
val pm = context.packageManager
|
||||||
@ -195,3 +245,24 @@ class AppFilterIconPackInstaller(
|
|||||||
return packs.distinctBy { it.packageName }
|
return packs.distinctBy { it.packageName }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal interface ClosableXmlParser : XmlPullParser {
|
||||||
|
fun close()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ClosableXmlResourceParser(private val parser: XmlResourceParser) : ClosableXmlParser,
|
||||||
|
XmlPullParser by parser {
|
||||||
|
override fun close() {
|
||||||
|
parser.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ClosableXmlPullParser(
|
||||||
|
private val parser: XmlPullParser,
|
||||||
|
private val reader: Reader
|
||||||
|
) : ClosableXmlParser,
|
||||||
|
XmlPullParser by parser {
|
||||||
|
override fun close() {
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user