Support android.support.v4.Fragment classes

This commit is contained in:
Yan Zhulanow
2015-04-07 20:41:00 +03:00
parent cc697d2c1a
commit 514bc74e9c
9 changed files with 74 additions and 16 deletions
@@ -38,6 +38,8 @@ public object AndroidConfigurationKeys {
public val ANDROID_RES_PATH: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("android resources search path")
public val ANDROID_MANIFEST: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("android manifest file")
public val SUPPORT_V4: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("'true' if compiled with support-v4 library")
}
public class AndroidCommandLineProcessor : CommandLineProcessor {
@@ -46,16 +48,18 @@ public class AndroidCommandLineProcessor : CommandLineProcessor {
public val RESOURCE_PATH_OPTION: CliOption = CliOption("androidRes", "<path>", "Android resources path")
public val MANIFEST_FILE_OPTION: CliOption = CliOption("androidManifest", "<path>", "Android manifest file")
public val SUPPORT_V4_OPTION: CliOption = CliOption("supportV4", "<path>", "Support android-v4 library", required = false)
}
override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> = listOf(RESOURCE_PATH_OPTION, MANIFEST_FILE_OPTION)
override val pluginOptions: Collection<CliOption> = listOf(RESOURCE_PATH_OPTION, MANIFEST_FILE_OPTION, SUPPORT_V4_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
RESOURCE_PATH_OPTION -> configuration.put(AndroidConfigurationKeys.ANDROID_RES_PATH, value)
MANIFEST_FILE_OPTION -> configuration.put(AndroidConfigurationKeys.ANDROID_MANIFEST, value)
SUPPORT_V4_OPTION -> configuration.put(AndroidConfigurationKeys.SUPPORT_V4, value)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
@@ -73,9 +77,13 @@ public class AndroidComponentRegistrar : ComponentRegistrar {
public override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val androidResPath = configuration.get(AndroidConfigurationKeys.ANDROID_RES_PATH)
val androidManifest = configuration.get(AndroidConfigurationKeys.ANDROID_MANIFEST)
val supportV4 = configuration.get(AndroidConfigurationKeys.SUPPORT_V4) ?: "false"
if (androidResPath != null && androidManifest != null) {
project.registerService(javaClass<AndroidUIXmlProcessor>(), CliAndroidUIXmlProcessor(project, androidManifest, androidResPath))
val xmlProcessor = CliAndroidUIXmlProcessor(project, androidManifest, androidResPath)
if (supportV4 == "true") xmlProcessor.supportV4 = true
project.registerService(javaClass<AndroidUIXmlProcessor>(), xmlProcessor)
project.registerService(javaClass<AndroidResourceManager>(), CliAndroidResourceManager(project, androidManifest, androidResPath))
ExternalDeclarationsProvider.registerExtension(project, CliAndroidDeclarationsProvider(project))
@@ -44,12 +44,16 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
private enum class AndroidClassType(val internalClassName: String, val supportsCache: Boolean = false) {
ACTIVITY : AndroidClassType("android/app/Activity", true)
FRAGMENT : AndroidClassType("android/app/Fragment", true)
VIEW : AndroidClassType("android/view/View")
ACTIVITY : AndroidClassType(AndroidConst.ACTIVITY_FQNAME.innerName, true)
FRAGMENT : AndroidClassType(AndroidConst.FRAGMENT_FQNAME.innerName, true)
SUPPORT_FRAGMENT : AndroidClassType(AndroidConst.SUPPORT_FRAGMENT_FQNAME.innerName, true)
VIEW : AndroidClassType(AndroidConst.VIEW_FQNAME.innerName)
UNKNOWN : AndroidClassType("")
}
private val String.innerName: String
get() = replace('.', '/')
public class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
companion object {
private val PROPERTY_NAME = "_\$_findViewCache"
@@ -145,7 +149,7 @@ public class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
v.getstatic(androidPackage.replace(".", "/") + "/R\$id", descriptor.getName().asString(), "I")
v.invokevirtual(androidClassType.internalClassName, "findViewById", "(I)Landroid/view/View;", false)
}
AndroidClassType.FRAGMENT -> {
AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> {
receiver.put(Type.getType("L${androidClassType.internalClassName};"), v)
v.invokevirtual(androidClassType.internalClassName, "getView", "()Landroid/view/View;", false)
v.getstatic(androidPackage.replace(".", "/") + "/R\$id", descriptor.getName().asString(), "I")
@@ -169,9 +173,10 @@ public class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
private fun getClassType(descriptor: ClassifierDescriptor): AndroidClassType {
fun getClassTypeInternal(name: String): AndroidClassType? = when (name) {
"android.app.Activity" -> AndroidClassType.ACTIVITY
"android.app.Fragment" -> AndroidClassType.FRAGMENT
"android.view.View" -> AndroidClassType.VIEW
AndroidConst.ACTIVITY_FQNAME -> AndroidClassType.ACTIVITY
AndroidConst.FRAGMENT_FQNAME -> AndroidClassType.FRAGMENT
AndroidConst.SUPPORT_FRAGMENT_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT
AndroidConst.VIEW_FQNAME -> AndroidClassType.VIEW
else -> null
}
@@ -291,7 +296,7 @@ public class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
loadId()
iv.invokevirtual(className, "findViewById", "(I)Landroid/view/View;", false)
}
AndroidClassType.FRAGMENT -> {
AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> {
iv.invokevirtual(className, "getView", "()Landroid/view/View;", false)
loadId()
iv.invokevirtual("android/view/View", "findViewById", "(I)Landroid/view/View;", false)
@@ -41,6 +41,12 @@ public object AndroidConst {
val CLEAR_FUNCTION_NAME = "clearFindViewByIdCache"
val VIEW_FQNAME = "android.view.View"
val ACTIVITY_FQNAME = "android.app.Activity"
val FRAGMENT_FQNAME = "android.app.Fragment"
val SUPPORT_V4_PACKAGE = "android.support.v4"
val SUPPORT_FRAGMENT_FQNAME = "$SUPPORT_V4_PACKAGE.app.Fragment"
val IGNORED_XML_WIDGET_TYPES = setOf("requestFocus", "merge", "tag", "check", "fragment")
val ESCAPED_IDENTIFIERS = (JetTokens.KEYWORDS.getTypes() + JetTokens.SOFT_KEYWORDS.getTypes())
@@ -66,6 +66,8 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
protected abstract val cachedSources: CachedValue<List<AndroidSyntheticFile>>
var supportV4 = false
private val cachedJetFiles: CachedValue<List<JetFile>> by Delegates.lazy {
cachedValue {
val psiManager = PsiManager.getInstance(project)
@@ -90,8 +92,9 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
val clearCacheFile = renderSyntheticFile("clearCache") {
writePackage(AndroidConst.SYNTHETIC_PACKAGE)
writeAndroidImports()
writeClearCacheFunction("android.app.Activity")
writeClearCacheFunction("android.app.Fragment")
writeClearCacheFunction(AndroidConst.ACTIVITY_FQNAME)
writeClearCacheFunction(AndroidConst.FRAGMENT_FQNAME)
if (supportV4) writeClearCacheFunction(AndroidConst.SUPPORT_FRAGMENT_FQNAME)
}
listOf(clearCacheFile,
@@ -109,6 +112,7 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
val mainLayoutFile = renderMainLayoutFile(layoutName, resources)
val viewLayoutFile = renderViewLayoutFile(layoutName, resources)
listOf(mainLayoutFile, viewLayoutFile)
}.filterNotNull() + commonFiles
}
@@ -138,7 +142,9 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
for (res in resources) {
properties(res).forEach {
writeSyntheticProperty(it.first, res, it.second)
if (supportV4 || !it.first.startsWith(AndroidConst.SUPPORT_V4_PACKAGE)) {
writeSyntheticProperty(it.first, res, it.second)
}
}
}
}
@@ -31,7 +31,8 @@ public abstract class AndroidResource(val id: String) {
public class AndroidWidget(id: String, override val className: String) : AndroidResource(id) {
override val mainProperties = listOf(
"android.app.Activity" to "findViewById(0)",
"android.app.Fragment" to "getView().findViewById(0)")
"android.app.Fragment" to "getView().findViewById(0)",
"android.support.v4.app.Fragment" to "getView().findViewById(0)")
override val viewProperties = listOf("android.view.View" to "findViewById(0)")