Abstract custom icon pack logic from icon pack class
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
package app.lawnchair.icons
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Xml
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import org.xmlpull.v1.XmlPullParserException
|
||||
import org.xmlpull.v1.XmlPullParserFactory
|
||||
import java.io.IOException
|
||||
|
||||
class CustomIconPack(context: Context, packPackageName: String) :
|
||||
IconPack(context, packPackageName) {
|
||||
|
||||
private val packResources = context.packageManager.getResourcesForApplication(packPackageName)
|
||||
private val componentMap = mutableMapOf<ComponentName, IconEntry>()
|
||||
private val calendarMap = mutableMapOf<ComponentName, CalendarIconEntry>()
|
||||
private val clockMap = mutableMapOf<ComponentName, IconEntry>()
|
||||
private val clockMetas = mutableMapOf<IconEntry, ClockMetadata>()
|
||||
|
||||
private val idCache = mutableMapOf<String, Int>()
|
||||
|
||||
private var _label: String = ""
|
||||
override val label get() = _label
|
||||
|
||||
override fun getIcon(componentName: ComponentName) = componentMap[componentName]
|
||||
override fun getCalendar(componentName: ComponentName) = calendarMap[componentName]
|
||||
override fun getClock(entry: IconEntry) = clockMetas[entry]
|
||||
|
||||
override fun getCalendars(): MutableSet<ComponentName> = calendarMap.keys
|
||||
override fun getClocks(): MutableSet<ComponentName> = clockMap.keys
|
||||
|
||||
override fun getIcon(iconEntry: IconEntry, iconDpi: Int): Drawable? {
|
||||
val id = getDrawableId(iconEntry.name)
|
||||
if (id == 0) return null
|
||||
return try {
|
||||
ExtendedBitmapDrawable.wrap(
|
||||
packResources,
|
||||
packResources.getDrawableForDensity(id, iconDpi, null),
|
||||
true
|
||||
)
|
||||
} catch (e: Resources.NotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadInternal() {
|
||||
val pm = context.packageManager
|
||||
_label = pm.getApplicationInfo(packPackageName, 0).loadLabel(pm).toString()
|
||||
val parseXml = getXml("appfilter") ?: return
|
||||
val compStart = "ComponentInfo{"
|
||||
val compStartLength = compStart.length
|
||||
val compEnd = "}"
|
||||
val compEndLength = compEnd.length
|
||||
try {
|
||||
while (parseXml.next() != XmlPullParser.END_DOCUMENT) {
|
||||
if (parseXml.eventType != XmlPullParser.START_TAG) continue
|
||||
val name = parseXml.name
|
||||
val isCalendar = name == "calendar"
|
||||
when (name) {
|
||||
"item", "calendar" -> {
|
||||
var componentName: String? = parseXml["component"]
|
||||
val drawableName = parseXml[if (isCalendar) "prefix" else "drawable"]
|
||||
if (componentName != null && drawableName != null) {
|
||||
if (componentName.startsWith(compStart) && componentName.endsWith(compEnd)) {
|
||||
componentName = componentName.substring(compStartLength, componentName.length - compEndLength)
|
||||
}
|
||||
val parsed = ComponentName.unflattenFromString(componentName)
|
||||
if (parsed != null) {
|
||||
if (isCalendar) {
|
||||
calendarMap[parsed] = CalendarIconEntry(this, drawableName)
|
||||
} else {
|
||||
componentMap[parsed] = IconEntry(this, drawableName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"dynamic-clock" -> {
|
||||
val drawableName = parseXml["drawable"]
|
||||
if (drawableName != null) {
|
||||
if (parseXml is XmlResourceParser) {
|
||||
clockMetas[IconEntry(this, drawableName)] = ClockMetadata(
|
||||
parseXml.getAttributeIntValue(null, "hourLayerIndex", -1),
|
||||
parseXml.getAttributeIntValue(null, "minuteLayerIndex", -1),
|
||||
parseXml.getAttributeIntValue(null, "secondLayerIndex", -1),
|
||||
parseXml.getAttributeIntValue(null, "defaultHour", 0),
|
||||
parseXml.getAttributeIntValue(null, "defaultMinute", 0),
|
||||
parseXml.getAttributeIntValue(null, "defaultSecond", 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
componentMap.forEach { (componentName, iconEntry) ->
|
||||
if (clockMetas.containsKey(iconEntry)) {
|
||||
clockMap[componentName] = iconEntry
|
||||
}
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: XmlPullParserException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDrawableId(name: String) = idCache.getOrPut(name) {
|
||||
packResources.getIdentifier(name, "drawable", packPackageName)
|
||||
}
|
||||
|
||||
private fun getXml(name: String): XmlPullParser? {
|
||||
val res: Resources
|
||||
try {
|
||||
res = context.packageManager.getResourcesForApplication(packPackageName)
|
||||
val resourceId = res.getIdentifier(name, "xml", packPackageName)
|
||||
return if (0 != resourceId) {
|
||||
context.packageManager.getXml(packPackageName, resourceId, null)
|
||||
} else {
|
||||
val factory = XmlPullParserFactory.newInstance()
|
||||
val parser = factory.newPullParser()
|
||||
parser.setInput(res.assets.open("$name.xml"), Xml.Encoding.UTF_8.toString())
|
||||
parser
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
} catch (e: IOException) {
|
||||
} catch (e: XmlPullParserException) {
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private operator fun XmlPullParser.get(key: String): String? = this.getAttributeValue(null, key)
|
||||
@@ -14,23 +14,14 @@ import org.xmlpull.v1.XmlPullParserFactory
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.Semaphore
|
||||
|
||||
class IconPack(
|
||||
private val context: Context,
|
||||
abstract class IconPack(
|
||||
protected val context: Context,
|
||||
val packPackageName: String,
|
||||
private val packResources: Resources
|
||||
) {
|
||||
private var waiter: Semaphore? = Semaphore(0)
|
||||
private val deferredLoad: Deferred<Unit>
|
||||
|
||||
private var _label: String = ""
|
||||
val label get() = _label
|
||||
|
||||
private val componentMap = mutableMapOf<ComponentName, IconEntry>()
|
||||
private val calendarMap = mutableMapOf<ComponentName, CalendarIconEntry>()
|
||||
private val clockMap = mutableMapOf<ComponentName, IconEntry>()
|
||||
private val clockMetas = mutableMapOf<IconEntry, ClockMetadata>()
|
||||
|
||||
private val idCache = mutableMapOf<String, Int>()
|
||||
abstract val label: String
|
||||
|
||||
init {
|
||||
deferredLoad = scope.async(Dispatchers.IO) {
|
||||
@@ -51,118 +42,19 @@ class IconPack(
|
||||
}
|
||||
}
|
||||
|
||||
fun getIcon(componentName: ComponentName) = componentMap[componentName]
|
||||
fun getCalendar(componentName: ComponentName) = calendarMap[componentName]
|
||||
fun getClock(entry: IconEntry) = clockMetas[entry]
|
||||
abstract fun getIcon(componentName: ComponentName): IconEntry?
|
||||
abstract fun getCalendar(componentName: ComponentName): CalendarIconEntry?
|
||||
abstract fun getClock(entry: IconEntry): ClockMetadata?
|
||||
|
||||
fun getCalendars(): MutableSet<ComponentName> = calendarMap.keys
|
||||
fun getClocks(): MutableSet<ComponentName> = clockMap.keys
|
||||
abstract fun getCalendars(): MutableSet<ComponentName>
|
||||
abstract fun getClocks(): MutableSet<ComponentName>
|
||||
|
||||
fun getIcon(iconEntry: IconEntry, iconDpi: Int): Drawable? {
|
||||
val id = getDrawableId(iconEntry.name)
|
||||
if (id == 0) return null
|
||||
return try {
|
||||
ExtendedBitmapDrawable.wrap(
|
||||
packResources,
|
||||
packResources.getDrawableForDensity(id, iconDpi, null),
|
||||
true
|
||||
)
|
||||
} catch (e: Resources.NotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDrawableId(name: String) = idCache.getOrPut(name) {
|
||||
packResources.getIdentifier(name, "drawable", packPackageName)
|
||||
}
|
||||
abstract fun getIcon(iconEntry: IconEntry, iconDpi: Int): Drawable?
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
private fun loadInternal() {
|
||||
val pm = context.packageManager
|
||||
_label = pm.getApplicationInfo(packPackageName, 0).loadLabel(pm).toString()
|
||||
val parseXml = getXml("appfilter") ?: return
|
||||
val compStart = "ComponentInfo{"
|
||||
val compStartLength = compStart.length
|
||||
val compEnd = "}"
|
||||
val compEndLength = compEnd.length
|
||||
try {
|
||||
while (parseXml.next() != XmlPullParser.END_DOCUMENT) {
|
||||
if (parseXml.eventType != XmlPullParser.START_TAG) continue
|
||||
val name = parseXml.name
|
||||
val isCalendar = name == "calendar"
|
||||
when (name) {
|
||||
"item", "calendar" -> {
|
||||
var componentName: String? = parseXml["component"]
|
||||
val drawableName = parseXml[if (isCalendar) "prefix" else "drawable"]
|
||||
if (componentName != null && drawableName != null) {
|
||||
if (componentName.startsWith(compStart) && componentName.endsWith(compEnd)) {
|
||||
componentName = componentName.substring(compStartLength, componentName.length - compEndLength)
|
||||
}
|
||||
val parsed = ComponentName.unflattenFromString(componentName)
|
||||
if (parsed != null) {
|
||||
if (isCalendar) {
|
||||
calendarMap[parsed] = CalendarIconEntry(this, drawableName)
|
||||
} else {
|
||||
componentMap[parsed] = IconEntry(this, drawableName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"dynamic-clock" -> {
|
||||
val drawableName = parseXml["drawable"]
|
||||
if (drawableName != null) {
|
||||
if (parseXml is XmlResourceParser) {
|
||||
clockMetas[IconEntry(this, drawableName)] = ClockMetadata(
|
||||
parseXml.getAttributeIntValue(null, "hourLayerIndex", -1),
|
||||
parseXml.getAttributeIntValue(null, "minuteLayerIndex", -1),
|
||||
parseXml.getAttributeIntValue(null, "secondLayerIndex", -1),
|
||||
parseXml.getAttributeIntValue(null, "defaultHour", 0),
|
||||
parseXml.getAttributeIntValue(null, "defaultMinute", 0),
|
||||
parseXml.getAttributeIntValue(null, "defaultSecond", 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
componentMap.forEach { (componentName, iconEntry) ->
|
||||
if (clockMetas.containsKey(iconEntry)) {
|
||||
clockMap[componentName] = iconEntry
|
||||
}
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: XmlPullParserException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getXml(name: String): XmlPullParser? {
|
||||
val res: Resources
|
||||
try {
|
||||
res = context.packageManager.getResourcesForApplication(packPackageName)
|
||||
val resourceId = res.getIdentifier(name, "xml", packPackageName)
|
||||
return if (0 != resourceId) {
|
||||
context.packageManager.getXml(packPackageName, resourceId, null)
|
||||
} else {
|
||||
val factory = XmlPullParserFactory.newInstance()
|
||||
val parser = factory.newPullParser()
|
||||
parser.setInput(res.assets.open("$name.xml"), Xml.Encoding.UTF_8.toString())
|
||||
parser
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
} catch (e: IOException) {
|
||||
} catch (e: XmlPullParserException) {
|
||||
}
|
||||
return null
|
||||
}
|
||||
protected abstract fun loadInternal()
|
||||
|
||||
companion object {
|
||||
private val scope = CoroutineScope(Dispatchers.IO) + CoroutineName("IconPack")
|
||||
}
|
||||
}
|
||||
|
||||
private operator fun XmlPullParser.get(key: String): String? = this.getAttributeValue(null, key)
|
||||
|
||||
@@ -15,7 +15,7 @@ class IconPackProvider(private val context: Context) {
|
||||
return iconPacks.getOrPut(packageName) {
|
||||
try {
|
||||
val packResources = context.packageManager.getResourcesForApplication(packageName)
|
||||
IconPack(context, packageName, packResources)
|
||||
CustomIconPack(context, packageName)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user