Magisk/app/src/main/java/com/topjohnwu/magisk/ui/inflater/LayoutInflaterFactory.kt

87 lines
3.0 KiB
Kotlin
Raw Normal View History

package com.topjohnwu.magisk.ui.inflater
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.InflateException
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.SimpleArrayMap
import java.lang.reflect.Constructor
open class LayoutInflaterFactory(private val delegate: AppCompatDelegate) : LayoutInflater.Factory2 {
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
return onCreateView(null, name, context, attrs)
}
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? {
val view = delegate.createView(parent, name, context, attrs)
?: LayoutInflaterFactoryDefaultImpl.createViewFromTag(context, name, attrs)
onViewCreated(view, parent, name, context, attrs)
return view
}
open fun onViewCreated(view: View?, parent: View?, name: String, context: Context, attrs: AttributeSet) {
if (view == null) return
2021-04-21 18:41:42 +02:00
WindowInsetsHelper.attach(view, attrs)
}
}
private object LayoutInflaterFactoryDefaultImpl {
private val constructorSignature = arrayOf(
Context::class.java, AttributeSet::class.java)
private val classPrefixList = arrayOf(
"android.widget.",
"android.view.",
"android.webkit."
)
private val constructorMap = SimpleArrayMap<String, Constructor<out View?>>()
fun createViewFromTag(context: Context, name: String, attrs: AttributeSet): View? {
var name = name
if (name == "view") {
name = attrs.getAttributeValue(null, "class")
}
return try {
if (-1 == name.indexOf('.')) {
for (prefix in classPrefixList) {
val view: View? = createViewByPrefix(context, name, attrs, prefix)
if (view != null) {
return view
}
}
null
} else {
createViewByPrefix(context, name, attrs, null)
}
} catch (e: Exception) {
null
}
}
@Throws(ClassNotFoundException::class, InflateException::class)
private fun createViewByPrefix(context: Context, name: String, attrs: AttributeSet, prefix: String?): View? {
var constructor = constructorMap[name]
return try {
if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it
val clazz = Class.forName(
if (prefix != null) prefix + name else name,
false,
context.classLoader).asSubclass(View::class.java)
constructor = clazz.getConstructor(*constructorSignature)
constructorMap.put(name, constructor)
}
constructor!!.isAccessible = true
constructor.newInstance(context, attrs)
} catch (e: Exception) {
null
}
}
2021-04-21 18:41:42 +02:00
}