app.cash.paparazzi.gradle.instrumentation.ResourcesCompatVisitorFactory.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of paparazzi-gradle-plugin Show documentation
Show all versions of paparazzi-gradle-plugin Show documentation
A Gradle plugin to set up the Paparazzi test library
The newest version!
package app.cash.paparazzi.gradle.instrumentation
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
internal abstract class ResourcesCompatVisitorFactory : AsmClassVisitorFactory {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor
): ClassVisitor {
return ResourcesCompatTransform(nextClassVisitor)
}
override fun isInstrumentable(classData: ClassData): Boolean =
classData.className == RESOURCES_COMPAT_CLASS_NAME
/**
* [ClassVisitor] that fixes a hardcoded path in ResourcesCompat.loadFont.
* In this method, there is a check that font files have a path that starts with res/.
* This is not the case in Studio. This replaces the check with one that verifies that the path contains res/.
*
* Inspired by ASM fix:
* https://cs.android.com/android-studio/platform/tools/adt/idea/+/mirror-goog-studio-main:rendering/src/com/android/tools/rendering/classloading/ResourcesCompatTransform.kt;drc=5bb41b6d5e519c891a4cd6149234138faa28e1af
*/
internal class ResourcesCompatTransform(delegate: ClassVisitor) : ClassVisitor(Opcodes.ASM9, delegate) {
override fun visitMethod(
access: Int,
name: String,
descriptor: String,
signature: String?,
exceptions: Array?
): MethodVisitor {
val methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
if (name == LOAD_FONT_METHOD_NAME && descriptor == LOAD_FONT_METHOD_DESCRIPTOR) {
return LoadFontVisitor(api, methodVisitor)
}
return methodVisitor
}
private class LoadFontVisitor(api: Int, delegate: MethodVisitor) : MethodVisitor(api, delegate) {
override fun visitMethodInsn(
opcode: Int,
owner: String,
name: String,
descriptor: String,
isInterface: Boolean
) {
if ("startsWith" == name) {
super.visitMethodInsn(opcode, owner, "contains", "(Ljava/lang/CharSequence;)Z", isInterface)
} else {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
}
}
}
}
internal companion object {
const val RESOURCES_COMPAT_CLASS_NAME = "androidx.core.content.res.ResourcesCompat"
const val LOAD_FONT_METHOD_NAME = "loadFont"
const val LOAD_FONT_METHOD_DESCRIPTOR =
"(Landroid/content/Context;Landroid/content/res/Resources;Landroid/util/TypedValue;IILandroidx/core/content/res/ResourcesCompat\$FontCallback;Landroid/os/Handler;ZZ)Landroid/graphics/Typeface;"
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy