Android Extensions: Support Dialog classes (KT-16957)

This commit is contained in:
Yan Zhulanow
2017-03-21 18:46:38 +03:00
parent f1e303e18d
commit cba523958e
23 changed files with 101 additions and 11 deletions
@@ -45,6 +45,7 @@ object AndroidConst {
val ACTIVITY_FQNAME = "android.app.Activity"
val FRAGMENT_FQNAME = "android.app.Fragment"
val DIALOG_FQNAME = "android.app.Dialog"
val SUPPORT_V4_PACKAGE = "android.support.v4"
val SUPPORT_FRAGMENT_FQNAME = "$SUPPORT_V4_PACKAGE.app.Fragment"
val SUPPORT_FRAGMENT_ACTIVITY_FQNAME = "$SUPPORT_V4_PACKAGE.app.FragmentActivity"
@@ -48,6 +48,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
enum class AndroidClassType(className: String, val supportsCache: Boolean = false, val fragment: Boolean = false) {
ACTIVITY(AndroidConst.ACTIVITY_FQNAME, supportsCache = true),
FRAGMENT(AndroidConst.FRAGMENT_FQNAME, supportsCache = true, fragment = true),
DIALOG(AndroidConst.DIALOG_FQNAME, supportsCache = false),
SUPPORT_FRAGMENT_ACTIVITY(AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME, supportsCache = true),
SUPPORT_FRAGMENT(AndroidConst.SUPPORT_FRAGMENT_FQNAME, supportsCache = true, fragment = true),
VIEW(AndroidConst.VIEW_FQNAME),
@@ -60,6 +61,7 @@ enum class AndroidClassType(className: String, val supportsCache: Boolean = fals
fun getClassTypeInternal(name: String): AndroidClassType? = when (name) {
AndroidConst.ACTIVITY_FQNAME -> AndroidClassType.ACTIVITY
AndroidConst.FRAGMENT_FQNAME -> AndroidClassType.FRAGMENT
AndroidConst.DIALOG_FQNAME -> AndroidClassType.DIALOG
AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY
AndroidConst.SUPPORT_FRAGMENT_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT
AndroidConst.VIEW_FQNAME -> AndroidClassType.VIEW
@@ -194,7 +196,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
}
else {
when (androidClassType) {
AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW -> {
AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW, AndroidClassType.DIALOG -> {
receiver.put(Type.getType("L${androidClassType.internalClassName};"), v)
getResourceId(v)
v.invokevirtual(androidClassType.internalClassName, "findViewById", "(I)Landroid/view/View;", false)
@@ -370,7 +372,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
// Resolve View via findViewById if not in cache
iv.load(0, classType)
when (androidClassType) {
AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW -> {
AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW, AndroidClassType.DIALOG -> {
loadId()
iv.invokevirtual(className, "findViewById", "(I)Landroid/view/View;", false)
}
@@ -63,7 +63,7 @@ class AndroidSyntheticPackageFragmentDescriptor(
val resolvedWidget = resource.resolve(module)
if (resolvedWidget != null) {
for (receiver in widgetReceivers) {
properties += genPropertyForWidget(packageFragmentDescriptor, receiver, resolvedWidget, context)
properties += genPropertyForWidget(packageFragmentDescriptor, receiver.type, resolvedWidget, context)
}
}
}
@@ -41,6 +41,7 @@ class LazySyntheticElementResolveContext(private val module: ModuleDescriptor, s
val viewDescriptor = find(AndroidConst.VIEW_FQNAME) ?: return SyntheticElementResolveContext.ERROR_CONTEXT
val activityDescriptor = find(AndroidConst.ACTIVITY_FQNAME) ?: return SyntheticElementResolveContext.ERROR_CONTEXT
val fragmentDescriptor = find(AndroidConst.FRAGMENT_FQNAME)
val dialogDescriptor = find(AndroidConst.DIALOG_FQNAME) ?: return SyntheticElementResolveContext.ERROR_CONTEXT
val supportActivityDescriptor = find(AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME)
val supportFragmentDescriptor = find(AndroidConst.SUPPORT_FRAGMENT_FQNAME)
@@ -48,6 +49,7 @@ class LazySyntheticElementResolveContext(private val module: ModuleDescriptor, s
viewDescriptor.defaultType,
activityDescriptor.defaultType,
fragmentDescriptor?.defaultType,
dialogDescriptor.defaultType,
supportActivityDescriptor?.defaultType,
supportFragmentDescriptor?.defaultType)
}
@@ -57,18 +59,20 @@ internal class SyntheticElementResolveContext(
val viewType: SimpleType,
val activityType: SimpleType,
val fragmentType: SimpleType?,
val dialogType: SimpleType,
val supportActivityType: SimpleType?,
val supportFragmentType: SimpleType?) {
companion object {
private fun errorType() = ErrorUtils.createErrorType("")
val ERROR_CONTEXT = SyntheticElementResolveContext(errorType(), errorType(), null, null, null)
val ERROR_CONTEXT = SyntheticElementResolveContext(errorType(), errorType(), null, errorType(), null, null)
}
private val widgetReceivers by lazy {
val receivers = ArrayList<KotlinType>(3)
receivers += activityType
fragmentType?.let { receivers += it }
supportFragmentType?.let { receivers += it }
val receivers = ArrayList<WidgetReceiver>(4)
receivers += WidgetReceiver(activityType, mayHaveCache = true)
receivers += WidgetReceiver(dialogType, mayHaveCache = false)
fragmentType?.let { receivers += WidgetReceiver(it, mayHaveCache = true) }
supportFragmentType?.let { receivers += WidgetReceiver(it, mayHaveCache = true) }
receivers
}
@@ -88,8 +92,11 @@ internal class SyntheticElementResolveContext(
}
}
fun getWidgetReceivers(forView: Boolean): List<KotlinType> {
if (forView) return listOf(viewType)
fun getWidgetReceivers(forView: Boolean): List<WidgetReceiver> {
if (forView) return listOf(WidgetReceiver(viewType, mayHaveCache = false))
return widgetReceivers
}
}
class WidgetReceiver(val type: SimpleType, val mayHaveCache: Boolean)
@@ -79,7 +79,7 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
// Package with clearFindViewByIdCache()
AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s ->
val packageDescriptor = PredefinedPackageFragmentDescriptor(s, module, storageManager, packagesToLookupInCompletion) { descriptor ->
lazyContext().getWidgetReceivers(false).map { genClearCacheFunction(descriptor, it) }
lazyContext().getWidgetReceivers(false).filter { it.mayHaveCache }.map { genClearCacheFunction(descriptor, it.type) }
}
packagesToLookupInCompletion += packageDescriptor
allPackageDescriptors += packageDescriptor
@@ -0,0 +1,7 @@
package android.app
import android.view.View
open class Dialog {
open fun findViewById(id: Int): View? = null
}
@@ -0,0 +1,13 @@
package test
import android.app.Dialog
import kotlinx.android.synthetic.main.layout.*
fun test(dialog: Dialog) {
dialog.login
}
// 1 GETSTATIC test/R\$id\.login
// 1 INVOKEVIRTUAL android/app/Dialog\.findViewById
// 1 CHECKCAST android/widget/Button
// 0 _\$_findCachedViewById
@@ -0,0 +1,17 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemDetailActivity"
tools:ignore="MergeRootFrame" >
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sign in" />
</FrameLayout>
@@ -16,12 +16,16 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.get
public val android.app.Activity.item_detail_container: android.widget.FrameLayout!
public val android.app.Dialog.item_detail_container: android.widget.FrameLayout!
public val android.app.Fragment.item_detail_container: android.widget.FrameLayout!
public val android.app.Activity.login: android.widget.Button!
public val android.app.Dialog.login: android.widget.Button!
public val android.app.Fragment.login: android.widget.Button!
public val android.app.Activity.password: android.widget.EditText!
public val android.app.Dialog.password: android.widget.EditText!
public val android.app.Fragment.password: android.widget.EditText!
public val android.app.Activity.textView1: android.widget.TextView!
public val android.app.Dialog.textView1: android.widget.TextView!
public val android.app.Fragment.textView1: android.widget.TextView!
@@ -16,6 +16,7 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.MyKeyboardView: android.inputmethodservice.KeyboardView!
public val android.app.Dialog.MyKeyboardView: android.inputmethodservice.KeyboardView!
public val android.app.Fragment.MyKeyboardView: android.inputmethodservice.KeyboardView!
@@ -16,6 +16,7 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.MyKeyboardView: android.inputmethodservice.KeyboardView!
public val android.app.Dialog.MyKeyboardView: android.inputmethodservice.KeyboardView!
public val android.app.Fragment.MyKeyboardView: android.inputmethodservice.KeyboardView!
@@ -16,6 +16,7 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.button: android.view.View!
public val android.app.Dialog.button: android.view.View!
public val android.app.Fragment.button: android.view.View!
@@ -16,12 +16,16 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.item_detail_container: android.widget.FrameLayout!
public val android.app.Dialog.item_detail_container: android.widget.FrameLayout!
public val android.app.Fragment.item_detail_container: android.widget.FrameLayout!
public val android.app.Activity.login: android.widget.Button!
public val android.app.Dialog.login: android.widget.Button!
public val android.app.Fragment.login: android.widget.Button!
public val android.app.Activity.password: android.widget.EditText!
public val android.app.Dialog.password: android.widget.EditText!
public val android.app.Fragment.password: android.widget.EditText!
public val android.app.Activity.textView1: android.widget.TextView!
public val android.app.Dialog.textView1: android.widget.TextView!
public val android.app.Fragment.textView1: android.widget.TextView!
@@ -36,12 +40,16 @@ kotlinx.android.synthetic.main.test.view
kotlinx.android.synthetic.main.test1
public val android.app.Activity.frameLayout: android.widget.FrameLayout!
public val android.app.Dialog.frameLayout: android.widget.FrameLayout!
public val android.app.Fragment.frameLayout: android.widget.FrameLayout!
public val android.app.Activity.loginButton: android.widget.Button!
public val android.app.Dialog.loginButton: android.widget.Button!
public val android.app.Fragment.loginButton: android.widget.Button!
public val android.app.Activity.passwordCaption: android.widget.EditText!
public val android.app.Dialog.passwordCaption: android.widget.EditText!
public val android.app.Fragment.passwordCaption: android.widget.EditText!
public val android.app.Activity.passwordField: android.widget.TextView!
public val android.app.Dialog.passwordField: android.widget.TextView!
public val android.app.Fragment.passwordField: android.widget.TextView!
@@ -16,8 +16,10 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.textView1: android.view.View!
public val android.app.Dialog.textView1: android.view.View!
public val android.app.Fragment.textView1: android.view.View!
public val android.app.Activity.textView2: android.widget.TextView!
public val android.app.Dialog.textView2: android.widget.TextView!
public val android.app.Fragment.textView2: android.widget.TextView!
@@ -16,10 +16,13 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.button: android.view.View!
public val android.app.Dialog.button: android.view.View!
public val android.app.Fragment.button: android.view.View!
public val android.app.Activity.button2: android.widget.Button!
public val android.app.Dialog.button2: android.widget.Button!
public val android.app.Fragment.button2: android.widget.Button!
public val android.app.Activity.button3: android.widget.Button!
public val android.app.Dialog.button3: android.widget.Button!
public val android.app.Fragment.button3: android.widget.Button!
@@ -16,12 +16,16 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.item_detail_container: android.widget.FrameLayout!
public val android.app.Dialog.item_detail_container: android.widget.FrameLayout!
public val android.app.Fragment.item_detail_container: android.widget.FrameLayout!
public val android.app.Activity.login: android.widget.Button!
public val android.app.Dialog.login: android.widget.Button!
public val android.app.Fragment.login: android.widget.Button!
public val android.app.Activity.password: android.widget.EditText!
public val android.app.Dialog.password: android.widget.EditText!
public val android.app.Fragment.password: android.widget.EditText!
public val android.app.Activity.textView1: android.widget.TextView!
public val android.app.Dialog.textView1: android.widget.TextView!
public val android.app.Fragment.textView1: android.widget.TextView!
@@ -18,10 +18,13 @@ kotlinx.android.synthetic.main.test
public val android.app.Activity.fragmentTag: android.app.Fragment!
public val android.app.Fragment.fragmentTag: android.app.Fragment!
public val android.app.Activity.`fun`: android.widget.TextView!
public val android.app.Dialog.`fun`: android.widget.TextView!
public val android.app.Fragment.`fun`: android.widget.TextView!
public val android.app.Activity.includeTag: android.view.View!
public val android.app.Dialog.includeTag: android.view.View!
public val android.app.Fragment.includeTag: android.view.View!
public val android.app.Activity.set: android.widget.Button!
public val android.app.Dialog.set: android.widget.Button!
public val android.app.Fragment.set: android.widget.Button!
@@ -16,12 +16,16 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.item_detail_container: android.widget.FrameLayout!
public val android.app.Dialog.item_detail_container: android.widget.FrameLayout!
public val android.app.Fragment.item_detail_container: android.widget.FrameLayout!
public val android.app.Activity.login: android.widget.Button!
public val android.app.Dialog.login: android.widget.Button!
public val android.app.Fragment.login: android.widget.Button!
public val android.app.Activity.password: android.widget.EditText!
public val android.app.Dialog.password: android.widget.EditText!
public val android.app.Fragment.password: android.widget.EditText!
public val android.app.Activity.textView1: android.widget.TextView!
public val android.app.Dialog.textView1: android.widget.TextView!
public val android.app.Fragment.textView1: android.widget.TextView!
@@ -18,10 +18,13 @@ kotlinx.android.synthetic.main.test
public val android.app.Activity.fragmentTag: android.app.Fragment!
public val android.app.Fragment.fragmentTag: android.app.Fragment!
public val android.app.Activity.`fun`: android.widget.TextView!
public val android.app.Dialog.`fun`: android.widget.TextView!
public val android.app.Fragment.`fun`: android.widget.TextView!
public val android.app.Activity.includeTag: android.view.View!
public val android.app.Dialog.includeTag: android.view.View!
public val android.app.Fragment.includeTag: android.view.View!
public val android.app.Activity.set: android.widget.Button!
public val android.app.Dialog.set: android.widget.Button!
public val android.app.Fragment.set: android.widget.Button!
@@ -16,6 +16,7 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.MyView: android.view.View!
public val android.app.Dialog.MyView: android.view.View!
public val android.app.Fragment.MyView: android.view.View!
@@ -16,6 +16,7 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.MyKeyboardView: android.view.View!
public val android.app.Dialog.MyKeyboardView: android.view.View!
public val android.app.Fragment.MyKeyboardView: android.view.View!
@@ -16,6 +16,7 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test
public val android.app.Activity.stub: android.view.ViewStub!
public val android.app.Dialog.stub: android.view.ViewStub!
public val android.app.Fragment.stub: android.view.ViewStub!
@@ -60,6 +60,12 @@ public class AndroidBytecodeShapeTestGenerated extends AbstractAndroidBytecodeSh
doTest(fileName);
}
@TestMetadata("dialog")
public void testDialog() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/dialog/");
doTest(fileName);
}
@TestMetadata("extensionFunctions")
public void testExtensionFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/extensionFunctions/");