diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index 2d769af2580..33ec3a67096 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -8,13 +8,39 @@ import java.io.File class KotlinAndroidGradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "3.3", androidGradlePluginVersion = "2.3.0") -class KotlinAndroid30GradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "4.0-rc-1", androidGradlePluginVersion = "3.0.0-alpha2") class KotlinAndroidWithJackGradleIT : AbstractKotlinAndroidWithJackGradleTests(gradleVersion = "3.3", androidGradlePluginVersion = "2.3.+") +class KotlinAndroid30GradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "4.0-rc-1", androidGradlePluginVersion = "3.0.0-alpha2") { + + @Test + fun testApplyWithFeaturePlugin() { + val project = Project("AndroidProject", gradleVersion) + + project.setupWorkingDir() + File(project.projectDir, "Lib/build.gradle").modify { text -> + // Change the applied plugin to com.android.feature + text.replace("com.android.library", "com.android.feature").apply { assert(!equals(text)) } + } + + // Check that Kotlin tasks were created for both lib and feature variants: + val kotlinTaskNames = + listOf("Debug", "Release").flatMap { buildType -> + listOf("Flavor1", "Flavor2").flatMap { flavor -> + listOf("", "Feature").map { isFeature -> ":Lib:compile$flavor$buildType${isFeature}Kotlin" } + } + } + + project.build(":Lib:assemble") { + assertSuccessful() + assertContains(*kotlinTaskNames.toTypedArray()) + } + } +} + const val ANDROID_HOME_PATH = "../../../dependencies/androidSDK" abstract class AbstractKotlinAndroidGradleTests( - private val gradleVersion: String, + protected val gradleVersion: String, private val androidGradlePluginVersion: String ) : BaseGradleIT() { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt index b92913a1aea..77b6201f17d 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt @@ -6,7 +6,7 @@ import java.io.File class Kapt3Android30IT : Kapt3AndroidIT() { override val androidGradlePluginVersion: String - get() = "3.0.0-alpha1" + get() = "3.0.0-alpha3" } open class Kapt3AndroidIT : Kapt3BaseIT() { @@ -106,4 +106,17 @@ open class Kapt3AndroidIT : Kapt3BaseIT() { assertFileExists("build/generated/source/kapt/release/io/realm/DefaultRealmModuleMediator.java") } } + + @Test + open fun testDatabinding() { + val project = Project("android-databinding", GRADLE_VERSION, directoryPrefix = "kapt2") + val options = androidBuildOptions() + + project.build("compileReleaseSources", options = options) { + assertSuccessful() + assertKaptSuccessful() + assertFileExists("app/build/generated/source/kapt/release/com/example/databinding/BR.java") + assertFileExists("app/build/generated/source/kapt/release/com/example/databinding/databinding/ActivityTestBinding.java") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/build.gradle new file mode 100644 index 00000000000..38b16facd3c --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 24 + buildToolsVersion "25.0.2" + defaultConfig { + applicationId "com.example.databinding" + minSdkVersion 21 + targetSdkVersion 24 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + dataBinding { + enabled = true + } +} + +repositories { + maven { url 'https://maven.google.com' } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + kapt "com.android.databinding:compiler:$android_tools_version" + compile 'com.android.support.constraint:constraint-layout:1.0.2' + testCompile 'junit:junit:4.12' +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/AndroidManifest.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..ec0a4f4c02c --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/EnumAdapter.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/EnumAdapter.kt new file mode 100644 index 00000000000..be774cdd369 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/EnumAdapter.kt @@ -0,0 +1,99 @@ +package com.example.databinding + +import android.content.Context +import android.content.res.Resources +import android.databinding.* +import android.databinding.adapters.AdapterViewBindingAdapter +import android.support.annotation.IntegerRes +import android.util.Log +import android.view.* +import android.widget.* + + +interface Displayable { + fun displayString(res: Resources): String +} + + +@InverseBindingMethods( + InverseBindingMethod(type = Spinner::class, attribute = "selectionEnum", method = "getSelectedItem", event = "app:selectionAttrChanged") +) +open class EnumAdapter(val context: Context, + enumClass: Class, + @IntegerRes var resource: Int = android.R.layout.simple_spinner_item, + @IntegerRes var dropDownResource: Int = android.R.layout.simple_spinner_dropdown_item, + val isOptional: Boolean = false) : + BaseAdapter() where DispEnum : Displayable, DispEnum : Enum +{ + val inflater: LayoutInflater = LayoutInflater.from(context) + val konstants: Array = enumClass.enumConstants + + override fun getItem(position: Int): DispEnum? { + if (isOptional) { + return if (position == 0) null else konstants[position - 1] + } + return konstants[position] + } + + override fun getItemId(position: Int): Long = position + 0L + + override fun getCount(): Int = konstants.size + if (isOptional) 1 else 0 + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + return createViewFromResource(position, convertView, parent, resource) + } + + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { + return createViewFromResource(position, convertView, parent, dropDownResource) + } + + private fun createViewFromResource(position: Int, convertView: View?, parent: ViewGroup, resource: Int): View { + val view = convertView ?: inflater.inflate(resource, parent, false) + val textView: TextView + try { + textView = view as TextView + } catch (e: ClassCastException) { + Log.e("EnumAdapter", "You must supply a resource ID for a TextView") + return view + } + + val enum = getItem(position) + textView.text = enum?.displayString(context.resources) ?: "-----" + return view + } + + companion object { + @JvmStatic fun optionalPosition(e: Enum<*>?): Int { + e?.let { return it.ordinal + 1} + return 0 + } + } +} + +@BindingAdapter("app:selectionEnum", "app:selectionChanged", "app:selectionAttrChanged", requireAll = false) +fun bindSpinnerEnum(spinner: Spinner, newValue: Enum<*>?, + itemSelectedListener: AdapterViewBindingAdapter.OnItemSelected?, + changeListener: InverseBindingListener?) { + val spinnerAdapter = spinner.adapter + if (spinnerAdapter !is EnumAdapter<*>) { + throw UnsupportedOperationException("app:selectionEnum attribute on Spinner requires EnumAdapter") + } + if (changeListener == null && itemSelectedListener == null) + spinner.onItemSelectedListener = null + else + spinner.onItemSelectedListener = AdapterViewBindingAdapter.OnItemSelectedComponentListener(itemSelectedListener, nothingingSelectedListener, changeListener) + + val isOptional = spinnerAdapter.isOptional + if (!isOptional && newValue == null) { + throw IllegalStateException("Can't set a null value for app:selectionEnum, adapter.isOptional is false") + } + if (spinner.selectedItem != newValue) { + val sel = if (isOptional) EnumAdapter.optionalPosition(newValue) else newValue!!.ordinal + spinner.setSelection(sel) + } +} + +val nothingingSelectedListener = object : AdapterViewBindingAdapter.OnNothingSelected { + override fun onNothingSelected(parent: AdapterView<*>?) { + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/MainActivity.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/MainActivity.kt new file mode 100644 index 00000000000..97752b34139 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/MainActivity.kt @@ -0,0 +1,38 @@ +package com.example.databinding + +import android.app.Activity +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.view.MotionEvent +import android.widget.Toast +import com.example.databinding.databinding.ActivityTestBinding + +class MainActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val binding: ActivityTestBinding = DataBindingUtil.setContentView(this, R.layout.activity_test) + val uprof = UserProfile() + binding.userProfile = uprof + binding.context = this + binding.genderPicker.adapter = EnumAdapter(this, Gender::class.java) + binding.genderPicker.setOnTouchListener { v, event -> + if (event.actionMasked == MotionEvent.ACTION_DOWN) + spinnerClicked = true + false + } + } + + var spinnerClicked = false + fun spinnerClicked() { + spinnerClicked = true + } + fun selectionChanged() { + if (spinnerClicked) + Toast.makeText(this, "sdds", Toast.LENGTH_LONG).show() + spinnerClicked = false + } + + fun clickHandler(uprof: UserProfile): Boolean = true + + fun longClickHandler(uprof: UserProfile): Boolean = true +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/UserProfile.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/UserProfile.kt new file mode 100644 index 00000000000..f229d4269f7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/java/com/example/databinding/UserProfile.kt @@ -0,0 +1,13 @@ +package com.example.databinding + +import android.content.res.Resources +import android.databinding.BaseObservable + +class UserProfile : BaseObservable() { + open var gender: Gender = Gender.Female +} + +enum class Gender(val display: String): Displayable { + Male("male"), Female("female"); + override fun displayString(res: Resources): String = display +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/layout/activity_test.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/layout/activity_test.xml new file mode 100644 index 00000000000..9557021ba4d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/values/strings.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/values/strings.xml new file mode 100644 index 00000000000..500e320cbba --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ActivityRideUpTest + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/values/styles.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/values/styles.xml new file mode 100644 index 00000000000..32d75edf43f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/app/src/main/res/values/styles.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/build.gradle new file mode 100644 index 00000000000..748483695ef --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/build.gradle @@ -0,0 +1,24 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + mavenLocal() + maven { url 'https://maven.google.com' } + } + dependencies { + classpath "com.android.tools.build:gradle:$android_tools_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + mavenLocal() + maven { url 'https://maven.google.com' } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/settings.gradle new file mode 100644 index 00000000000..e7b4def49cb --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-databinding/settings.gradle @@ -0,0 +1 @@ +include ':app'