Merge "Convert supportlib over to addInt from addColor"
diff --git a/buildSrc/src/main/groovy/android/support/SupportKotlinLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportKotlinLibraryPlugin.groovy
deleted file mode 100644
index 78b4777..0000000
--- a/buildSrc/src/main/groovy/android/support/SupportKotlinLibraryPlugin.groovy
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support
-
-import com.google.common.collect.ImmutableMap
-import org.gradle.api.JavaVersion
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-
-/**
- * Support kotlin library specific plugin that sets common configurations needed for
- * support library modules.
- */
-class SupportKotlinLibraryPlugin implements Plugin<Project> {
- @Override
- public void apply(Project project) {
- SupportLibraryExtension supportLibraryExtension =
- project.extensions.create("supportLibrary", SupportLibraryExtension, project);
- MavenUploadHelperKt.apply(project, supportLibraryExtension);
-
- project.apply(ImmutableMap.of("plugin", "kotlin"));
- project.apply(ImmutableMap.of("plugin", "kotlin-kapt"));
-
- project.compileJava {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
- }
- }
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
new file mode 100644
index 0000000..d18d533
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support
+
+import org.gradle.api.JavaVersion
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.plugins.JavaPluginConvention
+
+class SupportKotlinLibraryPlugin : Plugin<Project> {
+ override fun apply(project: Project) {
+ val supportLibraryExtension = project.extensions.create("supportLibrary",
+ SupportLibraryExtension::class.java, project)
+ apply(project, supportLibraryExtension)
+ project.apply(mapOf("plugin" to "kotlin"))
+ project.apply(mapOf("plugin" to "kotlin-kapt"))
+
+ val convention = project.convention.getPlugin(JavaPluginConvention::class.java)
+ convention.sourceCompatibility = JavaVersion.VERSION_1_8
+ convention.targetCompatibility = JavaVersion.VERSION_1_8
+ }
+}
\ No newline at end of file
diff --git a/car/res/values-night/colors.xml b/car/res/values-night/colors.xml
index 12eb594..7e29a5b 100644
--- a/car/res/values-night/colors.xml
+++ b/car/res/values-night/colors.xml
@@ -15,10 +15,17 @@
~ limitations under the License.
-->
<resources>
+ <color name="car_headline1">@color/car_headline1_light</color>
+ <color name="car_headline2">@color/car_headline2_light</color>
+ <color name="car_headline3">@color/car_headline3_light</color>
+ <color name="car_headline4">@color/car_headline4_light</color>
<color name="car_title">@color/car_title_light</color>
<color name="car_title2">@color/car_title2_light</color>
<color name="car_body1">@color/car_body1_light</color>
<color name="car_body2">@color/car_body2_light</color>
+ <color name="car_body3">@color/car_body3_light</color>
+ <color name="car_body4">@color/car_body4_light</color>
+ <color name="car_action1">@color/car_action1_light</color>
<color name="car_tint">@color/car_tint_light</color>
<color name="car_tint_inverse">@color/car_tint_dark</color>
diff --git a/car/res/values/colors.xml b/car/res/values/colors.xml
index 99804e3..8f82c01 100644
--- a/car/res/values/colors.xml
+++ b/car/res/values/colors.xml
@@ -99,8 +99,8 @@
<color name="car_body4_dark">@android:color/black</color>
<color name="car_body4">@color/car_body4_dark</color>
- <color name="car_action1_light">@color/car_grey_900</color>
- <color name="car_action1_dark">@color/car_grey_50</color>
+ <color name="car_action1_light">@color/car_grey_50</color>
+ <color name="car_action1_dark">@color/car_grey_900</color>
<color name="car_action1">@color/car_action1_dark</color>
<!-- The tinting colors to create a light- and dark-colored icon respectively. -->
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
index 5f61e21..521c271 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
@@ -30,7 +30,10 @@
import javax.lang.model.element.VariableElement
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
+import javax.lang.model.type.WildcardType
import javax.lang.model.util.SimpleAnnotationValueVisitor6
+import javax.lang.model.util.SimpleTypeVisitor7
+import javax.lang.model.util.Types
import kotlin.reflect.KClass
fun Element.hasAnyOf(vararg modifiers: Modifier): Boolean {
@@ -161,3 +164,50 @@
fun AnnotationValue.getAsStringList(): List<String> {
return ANNOTATION_VALUE_STRING_ARR_VISITOR.visit(this)
}
+
+// a variant of Types.isAssignable that ignores variance.
+fun Types.isAssignableWithoutVariance(from: TypeMirror, to: TypeMirror): Boolean {
+ val assignable = isAssignable(from, to)
+ if (assignable) {
+ return true
+ }
+ if (from.kind != TypeKind.DECLARED || to.kind != TypeKind.DECLARED) {
+ return false
+ }
+ val declaredFrom = MoreTypes.asDeclared(from)
+ val declaredTo = MoreTypes.asDeclared(to)
+ val fromTypeArgs = declaredFrom.typeArguments
+ val toTypeArgs = declaredTo.typeArguments
+ // no type arguments, we don't need extra checks
+ if (fromTypeArgs.isEmpty() || fromTypeArgs.size != toTypeArgs.size) {
+ return false
+ }
+ // check erasure version first, if it does not match, no reason to proceed
+ if (!isAssignable(erasure(from), erasure(to))) {
+ return false
+ }
+ // convert from args to their upper bounds if it exists
+ val fromExtendsBounds = fromTypeArgs.map {
+ it.extendsBound()
+ }
+ // if there are no upper bound conversions, return.
+ if (fromExtendsBounds.all { it == null }) {
+ return false
+ }
+ // try to move the types of the from to their upper bounds. It does not matter for the "to"
+ // because Types.isAssignable handles it as it is valid java
+ return (0 until fromTypeArgs.size).all { index ->
+ isAssignableWithoutVariance(
+ from = fromExtendsBounds[index] ?: fromTypeArgs[index],
+ to = toTypeArgs[index])
+ }
+}
+
+// converts ? in Set< ? extends Foo> to Foo
+private fun TypeMirror.extendsBound(): TypeMirror? {
+ return this.accept(object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
+ override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
+ return type.extendsBound
+ }
+ }, null)
+}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
index cb63b6d..f3b505d 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
@@ -26,6 +26,7 @@
import android.arch.persistence.room.ext.getAsStringList
import android.arch.persistence.room.ext.hasAnnotation
import android.arch.persistence.room.ext.hasAnyOf
+import android.arch.persistence.room.ext.isAssignableWithoutVariance
import android.arch.persistence.room.ext.isCollection
import android.arch.persistence.room.ext.toClassType
import android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD
@@ -216,7 +217,8 @@
} else if (!field.nameWithVariations.contains(paramName)) {
false
} else {
- typeUtils.isAssignable(paramType, field.type)
+ // see: b/69164099
+ typeUtils.isAssignableWithoutVariance(paramType, field.type)
}
}
@@ -555,7 +557,8 @@
val matching = candidates
.filter {
- types.isAssignable(getType(it), field.element.asType())
+ // b/69164099
+ types.isAssignableWithoutVariance(getType(it), field.element.asType())
&& (field.nameWithVariations.contains(it.simpleName.toString())
|| nameVariations.contains(it.simpleName.toString()))
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
index dcd5ee6..d64300c 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
@@ -362,8 +362,14 @@
|| MoreTypes.isTypeOf(java.util.Set::class.java, typeMirror))) {
val declared = MoreTypes.asDeclared(typeMirror)
val binder = findStatementValueBinder(declared.typeArguments.first(),
- null) ?: return null
- return CollectionQueryParameterAdapter(binder)
+ null)
+ if (binder != null) {
+ return CollectionQueryParameterAdapter(binder)
+ } else {
+ // maybe user wants to convert this collection themselves. look for a match
+ val collectionBinder = findStatementValueBinder(typeMirror, null) ?: return null
+ return BasicQueryParameterAdapter(collectionBinder)
+ }
} else if (typeMirror is ArrayType && typeMirror.componentType.kind != TypeKind.BYTE) {
val component = typeMirror.componentType
val binder = findStatementValueBinder(component, null) ?: return null
@@ -439,8 +445,10 @@
private fun getAllTypeConverters(input: TypeMirror, excludes: List<TypeMirror>):
List<TypeConverter> {
val types = context.processingEnv.typeUtils
+ // for input, check assignability because it defines whether we can use the method or not.
+ // for excludes, use exact match
return typeConverters.filter { converter ->
- types.isSameType(input, converter.from) &&
+ types.isAssignable(input, converter.from) &&
!excludes.any { types.isSameType(it, converter.to) }
}
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt
index d9b4997..ae635b2 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt
@@ -39,6 +39,7 @@
import com.squareup.javapoet.FieldSpec
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterSpec
+import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
import org.junit.Test
@@ -83,6 +84,26 @@
}
}
""")
+ val CUSTOM_TYPE_SET = ParameterizedTypeName.get(
+ ClassName.get(Set::class.java), CUSTOM_TYPE)
+ val CUSTOM_TYPE_SET_CONVERTER = ClassName.get("foo.bar", "MySetConverter")
+ val CUSTOM_TYPE_SET_CONVERTER_JFO = JavaFileObjects.forSourceLines(
+ CUSTOM_TYPE_SET_CONVERTER.toString(),
+ """
+ package ${CUSTOM_TYPE_SET_CONVERTER.packageName()};
+ import java.util.HashSet;
+ import java.util.Set;
+ public class ${CUSTOM_TYPE_SET_CONVERTER.simpleName()} {
+ @${TypeConverter::class.java.canonicalName}
+ public static $CUSTOM_TYPE_SET toCustom(int value) {
+ return null;
+ }
+ @${TypeConverter::class.java.canonicalName}
+ public static int fromCustom($CUSTOM_TYPE_SET input) {
+ return 0;
+ }
+ }
+ """)
}
@Test
@@ -94,6 +115,36 @@
}
@Test
+ fun collection_forEntity() {
+ val entity = createEntity(
+ hasCustomField = true,
+ useCollection = true)
+ val database = createDatabase(
+ hasConverters = true,
+ hasDao = true,
+ useCollection = true)
+ val dao = createDao(
+ hasQueryWithCustomParam = false,
+ useCollection = true)
+ run(entity.toJFO(), dao.toJFO(), database.toJFO()).compilesWithoutError()
+ }
+
+ @Test
+ fun collection_forDao() {
+ val entity = createEntity(
+ hasCustomField = true,
+ useCollection = true)
+ val database = createDatabase(
+ hasConverters = true,
+ hasDao = true,
+ useCollection = true)
+ val dao = createDao(
+ hasQueryWithCustomParam = true,
+ useCollection = true)
+ run(entity.toJFO(), dao.toJFO(), database.toJFO()).compilesWithoutError()
+ }
+
+ @Test
fun useFromDatabase_forQueryParameter() {
val entity = createEntity()
val database = createDatabase(hasConverters = true, hasDao = true)
@@ -170,21 +221,29 @@
fun run(vararg jfos: JavaFileObject): CompileTester {
return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
- .that(jfos.toList() + CUSTOM_TYPE_JFO + CUSTOM_TYPE_CONVERTER_JFO)
+ .that(jfos.toList() + CUSTOM_TYPE_JFO + CUSTOM_TYPE_CONVERTER_JFO
+ + CUSTOM_TYPE_SET_CONVERTER_JFO)
.processedWith(RoomProcessor())
}
- private fun createEntity(hasCustomField: Boolean = false,
- hasConverters: Boolean = false,
- hasConverterOnField: Boolean = false): TypeSpec {
+ private fun createEntity(
+ hasCustomField: Boolean = false,
+ hasConverters: Boolean = false,
+ hasConverterOnField: Boolean = false,
+ useCollection: Boolean = false): TypeSpec {
if (hasConverterOnField && hasConverters) {
throw IllegalArgumentException("cannot have both converters")
}
+ val type = if (useCollection) {
+ CUSTOM_TYPE_SET
+ } else {
+ CUSTOM_TYPE
+ }
return TypeSpec.classBuilder(ENTITY).apply {
addAnnotation(Entity::class.java)
addModifiers(Modifier.PUBLIC)
if (hasCustomField) {
- addField(FieldSpec.builder(CUSTOM_TYPE, "myCustomField", Modifier.PUBLIC).apply {
+ addField(FieldSpec.builder(type, "myCustomField", Modifier.PUBLIC).apply {
if (hasConverterOnField) {
addAnnotation(createConvertersAnnotation())
}
@@ -199,13 +258,15 @@
}.build()
}
- private fun createDatabase(hasConverters: Boolean = false,
- hasDao: Boolean = false): TypeSpec {
+ private fun createDatabase(
+ hasConverters: Boolean = false,
+ hasDao: Boolean = false,
+ useCollection: Boolean = false): TypeSpec {
return TypeSpec.classBuilder(DB).apply {
addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
superclass(RoomTypeNames.ROOM_DB)
if (hasConverters) {
- addAnnotation(createConvertersAnnotation())
+ addAnnotation(createConvertersAnnotation(useCollection = useCollection))
}
addField(FieldSpec.builder(TypeName.INT, "id", Modifier.PUBLIC).apply {
addAnnotation(PrimaryKey::class.java)
@@ -225,11 +286,13 @@
}.build()
}
- private fun createDao(hasConverters: Boolean = false,
- hasQueryReturningEntity: Boolean = false,
- hasQueryWithCustomParam: Boolean = false,
- hasMethodConverters: Boolean = false,
- hasParameterConverters: Boolean = false): TypeSpec {
+ private fun createDao(
+ hasConverters: Boolean = false,
+ hasQueryReturningEntity: Boolean = false,
+ hasQueryWithCustomParam: Boolean = false,
+ hasMethodConverters: Boolean = false,
+ hasParameterConverters: Boolean = false,
+ useCollection: Boolean = false): TypeSpec {
val annotationCount = listOf(hasMethodConverters, hasConverters, hasParameterConverters)
.map { if (it) 1 else 0 }.sum()
if (annotationCount > 1) {
@@ -242,7 +305,7 @@
addAnnotation(Dao::class.java)
addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
if (hasConverters) {
- addAnnotation(createConvertersAnnotation())
+ addAnnotation(createConvertersAnnotation(useCollection = useCollection))
}
if (hasQueryReturningEntity) {
addMethod(MethodSpec.methodBuilder("loadAll").apply {
@@ -253,18 +316,23 @@
returns(ENTITY)
}.build())
}
+ val customType = if (useCollection) {
+ CUSTOM_TYPE_SET
+ } else {
+ CUSTOM_TYPE
+ }
if (hasQueryWithCustomParam) {
addMethod(MethodSpec.methodBuilder("queryWithCustom").apply {
addAnnotation(AnnotationSpec.builder(Query::class.java).apply {
addMember("value", S, "SELECT COUNT(*) FROM ${ENTITY.simpleName()} where" +
- " id IN(:customs)")
+ " id = :custom")
}.build())
if (hasMethodConverters) {
- addAnnotation(createConvertersAnnotation())
+ addAnnotation(createConvertersAnnotation(useCollection = useCollection))
}
- addParameter(ParameterSpec.builder(CUSTOM_TYPE, "customs").apply {
+ addParameter(ParameterSpec.builder(customType, "custom").apply {
if (hasParameterConverters) {
- addAnnotation(createConvertersAnnotation())
+ addAnnotation(createConvertersAnnotation(useCollection = useCollection))
}
}.build())
addModifiers(Modifier.ABSTRACT)
@@ -274,8 +342,13 @@
}.build()
}
- private fun createConvertersAnnotation(): AnnotationSpec {
+ private fun createConvertersAnnotation(useCollection: Boolean = false): AnnotationSpec {
+ val converter = if (useCollection) {
+ CUSTOM_TYPE_SET_CONVERTER
+ } else {
+ CUSTOM_TYPE_CONVERTER
+ }
return AnnotationSpec.builder(TypeConverters::class.java)
- .addMember("value", "$T.class", CUSTOM_TYPE_CONVERTER).build()
+ .addMember("value", "$T.class", converter).build()
}
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAssignmentTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAssignmentTest.kt
new file mode 100644
index 0000000..03d4031
--- /dev/null
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAssignmentTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.solver
+
+import android.arch.persistence.room.ext.getAllFieldsIncludingPrivateSupers
+import android.arch.persistence.room.ext.isAssignableWithoutVariance
+import android.arch.persistence.room.testing.TestInvocation
+import com.google.testing.compile.JavaFileObjects
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Test
+import simpleRun
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.element.TypeElement
+import javax.lang.model.element.VariableElement
+
+class TypeAssignmentTest {
+ companion object {
+ private val TEST_OBJECT = JavaFileObjects.forSourceString("foo.bar.MyObject",
+ """
+ package foo.bar;
+ import java.util.Set;
+ import java.util.HashSet;
+ import java.util.Map;
+ class MyObject {
+ String mString;
+ Integer mInteger;
+ Set<MyObject> mSet;
+ Set<? extends MyObject> mVarianceSet;
+ HashSet<MyObject> mHashSet;
+ Map<String, ?> mUnboundedMap;
+ Map<String, String> mStringMap;
+ }
+ """.trimIndent())
+ }
+
+ @Test
+ fun basic() {
+ runTest {
+ val testObject = typeElement("foo.bar.MyObject")
+ val string = testObject.getField(processingEnv, "mString")
+ val integer = testObject.getField(processingEnv, "mInteger")
+ assertThat(typeUtils.isAssignableWithoutVariance(string.asType(),
+ integer.asType()),
+ `is`(false))
+ }
+ }
+
+ @Test
+ fun generics() {
+ runTest {
+ val testObject = typeElement("foo.bar.MyObject")
+ val set = testObject.getField(processingEnv, "mSet").asType()
+ val hashSet = testObject.getField(processingEnv, "mHashSet").asType()
+ assertThat(typeUtils.isAssignableWithoutVariance(
+ from = set,
+ to = hashSet
+ ), `is`(false))
+ assertThat(typeUtils.isAssignableWithoutVariance(
+ from = hashSet,
+ to = set
+ ), `is`(true))
+ }
+ }
+
+ @Test
+ fun variance() {
+ /**
+ * Set<User> userSet = null;
+ * Set<? extends User> userSet2 = null;
+ * userSet = userSet2; // NOT OK for java but kotlin data classes hit this so we want
+ * // to accept it
+ */
+ runTest {
+ val testObject = typeElement("foo.bar.MyObject")
+ val set = testObject.getField(processingEnv, "mSet").asType()
+ val varianceSet = testObject.getField(processingEnv, "mVarianceSet").asType()
+ assertThat(typeUtils.isAssignableWithoutVariance(
+ from = set,
+ to = varianceSet
+ ), `is`(true))
+ assertThat(typeUtils.isAssignableWithoutVariance(
+ from = varianceSet,
+ to = set
+ ), `is`(true))
+ }
+ }
+
+ @Test
+ fun unboundedVariance() {
+ runTest {
+ val testObject = typeElement("foo.bar.MyObject")
+ val unbounded = testObject.getField(processingEnv, "mUnboundedMap").asType()
+ val objectMap = testObject.getField(processingEnv, "mStringMap").asType()
+ assertThat(typeUtils.isAssignableWithoutVariance(
+ from = unbounded,
+ to = objectMap
+ ), `is`(false))
+ assertThat(typeUtils.isAssignableWithoutVariance(
+ from = objectMap,
+ to = unbounded
+ ), `is`(true))
+ }
+ }
+
+ private fun TypeElement.getField(
+ env: ProcessingEnvironment,
+ name: String): VariableElement {
+ return getAllFieldsIncludingPrivateSupers(env).first {
+ it.simpleName.toString() == name
+ }
+ }
+
+ private fun runTest(handler: TestInvocation.() -> Unit) {
+ simpleRun(TEST_OBJECT) {
+ it.apply { handler() }
+ }.compilesWithoutError()
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt
index 86b6e01..e03f1db 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt
@@ -29,4 +29,6 @@
fun typeElement(qName: String): TypeElement {
return processingEnv.elementUtils.getTypeElement(qName)
}
+
+ val typeUtils by lazy { processingEnv.typeUtils }
}
diff --git a/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json b/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
index e6bb21c..04e7cad 100644
--- a/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
+++ b/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 1,
- "identityHash": "933c7e2810b0f89ab84faa68bbea5852",
+ "identityHash": "c7e8b9f03366a1b0a03ab28b7c9c5ad7",
"entities": [
{
"tableName": "Book",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bookId` TEXT NOT NULL, `title` TEXT NOT NULL, `bookPublisherId` TEXT NOT NULL, PRIMARY KEY(`bookId`), FOREIGN KEY(`bookPublisherId`) REFERENCES `Publisher`(`publisherId`) ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bookId` TEXT NOT NULL, `title` TEXT NOT NULL, `bookPublisherId` TEXT NOT NULL, `languages` INTEGER NOT NULL, PRIMARY KEY(`bookId`), FOREIGN KEY(`bookPublisherId`) REFERENCES `Publisher`(`publisherId`) ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)",
"fields": [
{
"fieldPath": "bookId",
@@ -25,6 +25,12 @@
"columnName": "bookPublisherId",
"affinity": "TEXT",
"notNull": true
+ },
+ {
+ "fieldPath": "languages",
+ "columnName": "languages",
+ "affinity": "INTEGER",
+ "notNull": true
}
],
"primaryKey": {
@@ -191,7 +197,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
- "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"933c7e2810b0f89ab84faa68bbea5852\")"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"c7e8b9f03366a1b0a03ab28b7c9c5ad7\")"
]
}
}
\ No newline at end of file
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
index 20e9d18..39e8cae 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
@@ -20,10 +20,12 @@
import android.arch.persistence.room.Dao
import android.arch.persistence.room.Insert
import android.arch.persistence.room.Query
+import android.arch.persistence.room.TypeConverters
import android.arch.persistence.room.integration.kotlintestapp.vo.Author
import android.arch.persistence.room.integration.kotlintestapp.vo.Book
import android.arch.persistence.room.integration.kotlintestapp.vo.BookAuthor
import android.arch.persistence.room.integration.kotlintestapp.vo.BookWithPublisher
+import android.arch.persistence.room.integration.kotlintestapp.vo.Lang
import android.arch.persistence.room.integration.kotlintestapp.vo.Publisher
import android.arch.persistence.room.integration.kotlintestapp.vo.PublisherWithBooks
import io.reactivex.Flowable
@@ -91,4 +93,8 @@
@Query("UPDATE book SET title = :title WHERE bookId = :bookId")
fun updateBookTitle(bookId: String, title: String?)
+
+ @Query("SELECT * FROM book WHERE languages & :langs != 0 ORDER BY bookId ASC")
+ @TypeConverters(Lang::class)
+ fun findByLanguages(langs: Set<Lang>): List<Book>
}
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt
index acc2c7d..93be6e9 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt
@@ -19,6 +19,7 @@
import android.arch.persistence.room.integration.kotlintestapp.vo.Author
import android.arch.persistence.room.integration.kotlintestapp.vo.Book
import android.arch.persistence.room.integration.kotlintestapp.vo.BookWithPublisher
+import android.arch.persistence.room.integration.kotlintestapp.vo.Lang
import android.arch.persistence.room.integration.kotlintestapp.vo.Publisher
import android.database.sqlite.SQLiteConstraintException
import android.support.test.filters.SmallTest
@@ -119,4 +120,25 @@
TestUtil.BOOK_2.bookId))
assertThat(books, `is`(listOf(TestUtil.BOOK_2, TestUtil.BOOK_1)))
}
+
+ @Test
+ fun findBooksByLanguage() {
+ booksDao.addPublishers(TestUtil.PUBLISHER)
+ val book1 = TestUtil.BOOK_1.copy(languages = setOf(Lang.TR))
+ val book2 = TestUtil.BOOK_2.copy(languages = setOf(Lang.ES, Lang.TR))
+ val book3 = TestUtil.BOOK_3.copy(languages = setOf(Lang.EN))
+ booksDao.addBooks(book1, book2, book3)
+
+ assertThat(booksDao.findByLanguages(setOf(Lang.EN, Lang.TR)),
+ `is`(listOf(book1, book2, book3)))
+
+ assertThat(booksDao.findByLanguages(setOf(Lang.TR)),
+ `is`(listOf(book1, book2)))
+
+ assertThat(booksDao.findByLanguages(setOf(Lang.ES)),
+ `is`(listOf(book2)))
+
+ assertThat(booksDao.findByLanguages(setOf(Lang.EN)),
+ `is`(listOf(book3)))
+ }
}
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestUtil.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestUtil.kt
index c4d406c..57546d0 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestUtil.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestUtil.kt
@@ -19,6 +19,7 @@
import android.arch.persistence.room.integration.kotlintestapp.vo.Author
import android.arch.persistence.room.integration.kotlintestapp.vo.Book
import android.arch.persistence.room.integration.kotlintestapp.vo.BookAuthor
+import android.arch.persistence.room.integration.kotlintestapp.vo.Lang
import android.arch.persistence.room.integration.kotlintestapp.vo.Publisher
class TestUtil {
@@ -31,8 +32,12 @@
val AUTHOR_1 = Author("a1", "author 1")
val AUTHOR_2 = Author("a2", "author 2")
- val BOOK_1 = Book("b1", "book title 1", "ph1")
- val BOOK_2 = Book("b2", "book title 2", "ph1")
+ val BOOK_1 = Book("b1", "book title 1", "ph1",
+ setOf(Lang.EN))
+ val BOOK_2 = Book("b2", "book title 2", "ph1",
+ setOf(Lang.TR))
+ val BOOK_3 = Book("b3", "book title 2", "ph1",
+ setOf(Lang.ES))
val BOOK_AUTHOR_1_1 = BookAuthor(BOOK_1.bookId, AUTHOR_1.authorId)
val BOOK_AUTHOR_1_2 = BookAuthor(BOOK_1.bookId, AUTHOR_2.authorId)
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Book.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Book.kt
index 794e60b..fe4a600 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Book.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Book.kt
@@ -19,10 +19,16 @@
import android.arch.persistence.room.Entity
import android.arch.persistence.room.ForeignKey
import android.arch.persistence.room.PrimaryKey
+import android.arch.persistence.room.TypeConverters
@Entity(foreignKeys = arrayOf(
ForeignKey(entity = Publisher::class,
parentColumns = arrayOf("publisherId"),
childColumns = arrayOf("bookPublisherId"),
deferred = true)))
-data class Book(@PrimaryKey val bookId: String, val title: String, val bookPublisherId: String)
+data class Book(
+ @PrimaryKey val bookId: String,
+ val title: String,
+ val bookPublisherId: String,
+ @field:TypeConverters(Lang::class)
+ val languages: Set<Lang>)
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Lang.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Lang.kt
new file mode 100644
index 0000000..1d5fb5c
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Lang.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.kotlintestapp.vo
+
+import android.arch.persistence.room.TypeConverter
+
+/**
+ * An enum class which gets saved as a bit set in the database.
+ */
+enum class Lang {
+ TR,
+ EN,
+ ES;
+
+ companion object {
+ @JvmStatic
+ @TypeConverter
+ fun toInt(langs: Set<Lang>): Int {
+ return langs.fold(0) { left, lang ->
+ left.or(1 shl lang.ordinal)
+ }
+ }
+
+ @JvmStatic
+ @TypeConverter
+ fun toSet(value: Int): Set<Lang> {
+ return Lang.values().filter {
+ (1 shl it.ordinal).and(value) != 0
+ }.toSet()
+ }
+ }
+}
\ No newline at end of file
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java
index 2fad7b1..610afb2 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java
@@ -32,6 +32,7 @@
import android.arch.persistence.room.integration.testapp.dao.UserPetDao;
import android.arch.persistence.room.integration.testapp.dao.WithClauseDao;
import android.arch.persistence.room.integration.testapp.vo.BlobEntity;
+import android.arch.persistence.room.integration.testapp.vo.Day;
import android.arch.persistence.room.integration.testapp.vo.FunnyNamedEntity;
import android.arch.persistence.room.integration.testapp.vo.Pet;
import android.arch.persistence.room.integration.testapp.vo.PetCouple;
@@ -41,6 +42,8 @@
import android.arch.persistence.room.integration.testapp.vo.User;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
@Database(entities = {User.class, Pet.class, School.class, PetCouple.class, Toy.class,
BlobEntity.class, Product.class, FunnyNamedEntity.class},
@@ -74,5 +77,25 @@
return date.getTime();
}
}
+
+ @TypeConverter
+ public Set<Day> decomposeDays(int flags) {
+ Set<Day> result = new HashSet<>();
+ for (Day day : Day.values()) {
+ if ((flags & (1 << day.ordinal())) != 0) {
+ result.add(day);
+ }
+ }
+ return result;
+ }
+
+ @TypeConverter
+ public int composeDays(Set<Day> days) {
+ int result = 0;
+ for (Day day : days) {
+ result |= 1 << day.ordinal();
+ }
+ return result;
+ }
}
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java
index f601a86..1a2a468 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java
@@ -29,6 +29,7 @@
import android.arch.persistence.room.Update;
import android.arch.persistence.room.integration.testapp.TestDatabase;
import android.arch.persistence.room.integration.testapp.vo.AvgWeightByAge;
+import android.arch.persistence.room.integration.testapp.vo.Day;
import android.arch.persistence.room.integration.testapp.vo.NameAndLastName;
import android.arch.persistence.room.integration.testapp.vo.User;
import android.database.Cursor;
@@ -37,6 +38,7 @@
import java.util.Date;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Callable;
import io.reactivex.Flowable;
@@ -204,6 +206,9 @@
@Query("UPDATE User set mWeight = :weight WHERE mId IN (:ids) AND mAge == :age")
public abstract int updateByAgeAndIds(float weight, int age, List<Integer> ids);
+ @Query("SELECT * FROM user WHERE (mWorkDays & :days) != 0")
+ public abstract List<User> findUsersByWorkDays(Set<Day> days);
+
// QueryLoader
@Query("SELECT COUNT(*) from user")
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java
index c5015f2..4be2d85 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java
@@ -35,6 +35,7 @@
import android.arch.persistence.room.integration.testapp.dao.UserDao;
import android.arch.persistence.room.integration.testapp.dao.UserPetDao;
import android.arch.persistence.room.integration.testapp.vo.BlobEntity;
+import android.arch.persistence.room.integration.testapp.vo.Day;
import android.arch.persistence.room.integration.testapp.vo.NameAndLastName;
import android.arch.persistence.room.integration.testapp.vo.Pet;
import android.arch.persistence.room.integration.testapp.vo.Product;
@@ -58,7 +59,9 @@
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
@SmallTest
@@ -534,4 +537,35 @@
assertThat(result.getName(), is(user.getName()));
assertThat(result.getLastName(), is(user.getLastName()));
}
+
+ @Test
+ public void enumSet_simpleLoad() {
+ User a = TestUtil.createUser(3);
+ Set<Day> expected = toSet(Day.MONDAY, Day.TUESDAY);
+ a.setWorkDays(expected);
+ mUserDao.insert(a);
+ User loaded = mUserDao.load(3);
+ assertThat(loaded.getWorkDays(), is(expected));
+ }
+
+ @Test
+ public void enumSet_query() {
+ User user1 = TestUtil.createUser(3);
+ user1.setWorkDays(toSet(Day.MONDAY, Day.FRIDAY));
+ User user2 = TestUtil.createUser(5);
+ user2.setWorkDays(toSet(Day.MONDAY, Day.THURSDAY));
+ mUserDao.insert(user1);
+ mUserDao.insert(user2);
+ List<User> empty = mUserDao.findUsersByWorkDays(toSet(Day.WEDNESDAY));
+ assertThat(empty.size(), is(0));
+ List<User> friday = mUserDao.findUsersByWorkDays(toSet(Day.FRIDAY));
+ assertThat(friday, is(Arrays.asList(user1)));
+ List<User> monday = mUserDao.findUsersByWorkDays(toSet(Day.MONDAY));
+ assertThat(monday, is(Arrays.asList(user1, user2)));
+
+ }
+
+ private Set<Day> toSet(Day... days) {
+ return new HashSet<>(Arrays.asList(days));
+ }
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/Day.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/Day.java
new file mode 100644
index 0000000..e02b91c
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/Day.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.testapp.vo;
+
+public enum Day {
+ MONDAY,
+ TUESDAY,
+ WEDNESDAY,
+ THURSDAY,
+ FRIDAY,
+ SATURDAY,
+ SUNDAY
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/User.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/User.java
index a5b8839..a615819 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/User.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/User.java
@@ -23,6 +23,8 @@
import android.arch.persistence.room.integration.testapp.TestDatabase;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
@Entity
@TypeConverters({TestDatabase.Converters.class})
@@ -46,6 +48,9 @@
@ColumnInfo(name = "custommm", collate = ColumnInfo.NOCASE)
private String mCustomField;
+ // bit flags
+ private Set<Day> mWorkDays = new HashSet<>();
+
public int getId() {
return mId;
}
@@ -110,6 +115,15 @@
mCustomField = customField;
}
+ public Set<Day> getWorkDays() {
+ return mWorkDays;
+ }
+
+ public void setWorkDays(
+ Set<Day> workDays) {
+ mWorkDays = workDays;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -128,8 +142,11 @@
if (mBirthday != null ? !mBirthday.equals(user.mBirthday) : user.mBirthday != null) {
return false;
}
- return mCustomField != null ? mCustomField.equals(user.mCustomField)
- : user.mCustomField == null;
+ if (mCustomField != null ? !mCustomField.equals(user.mCustomField)
+ : user.mCustomField != null) {
+ return false;
+ }
+ return mWorkDays != null ? mWorkDays.equals(user.mWorkDays) : user.mWorkDays == null;
}
@Override
@@ -142,6 +159,7 @@
result = 31 * result + (mWeight != +0.0f ? Float.floatToIntBits(mWeight) : 0);
result = 31 * result + (mBirthday != null ? mBirthday.hashCode() : 0);
result = 31 * result + (mCustomField != null ? mCustomField.hashCode() : 0);
+ result = 31 * result + (mWorkDays != null ? mWorkDays.hashCode() : 0);
return result;
}
@@ -155,7 +173,8 @@
+ ", mAdmin=" + mAdmin
+ ", mWeight=" + mWeight
+ ", mBirthday=" + mBirthday
- + ", mCustom=" + mCustomField
+ + ", mCustomField='" + mCustomField + '\''
+ + ", mWorkDays=" + mWorkDays
+ '}';
}
}
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 2816600..ae7407b 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -34,5 +34,5 @@
mavenGroup = LibraryGroups.SLICES
inceptionYear = "2017"
description = "A set of builders to create templates using SliceProvider APIs"
- minSdkVersion = 19
+ minSdkVersion = 24
}
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
index e2015bb..9cb7ba2 100644
--- a/slices/core/build.gradle
+++ b/slices/core/build.gradle
@@ -45,5 +45,5 @@
mavenGroup = LibraryGroups.SLICES
inceptionYear = "2017"
description = "The slices core library provides utilities for the slices view and provider libraries"
- minSdkVersion = 19
+ minSdkVersion = 24
}
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 35d5e93..9c863c9 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -36,5 +36,5 @@
mavenGroup = LibraryGroups.SLICES
inceptionYear = "2017"
description = "A library that handles rendering of slice content into supported templates"
- minSdkVersion = 19
+ minSdkVersion = 24
}
diff --git a/webkit-codegen/src/test/resources/README.txt b/webkit-codegen/src/test/resources/README.txt
new file mode 100644
index 0000000..99a9f15
--- /dev/null
+++ b/webkit-codegen/src/test/resources/README.txt
@@ -0,0 +1,15 @@
+The webkit-codegen module represents a code generation tool, so the tests in
+this module ensures the code generated by the tool is correct. We do this by
+using two types of test-resource files: input and output files. The input files
+live under codegen/ while the output files live under codegen-expected/.
+Each test consists of parsing the input file, then passing that file to the tool
+to perform some code transformation/generation, and finally validating the
+output against one or several output file.
+The input and output files are named in such a way that they correspond to how
+the tool names its generated files, e.g. running boundary interface generation
+for Foo.java will generate a file named FooBoundaryInterface.java.
+
+The folder deps/android/webkit/ contains classes that should be seen as
+android.webkit classes. These classes are special because they need special
+treatment by the code generation tool (since the support library will never
+reference those classes directly, but instead create its own versions of them).
diff --git a/webkit-codegen/src/test/resources/codegen-expected/SingleClassAndMethodBoundaryInterface.java b/webkit-codegen/src/test/resources/codegen-expected/SingleClassAndMethodBoundaryInterface.java
new file mode 100644
index 0000000..ed67bbf
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen-expected/SingleClassAndMethodBoundaryInterface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.chromium.support_lib_boundary;
+
+public interface SingleClassAndMethodBoundaryInterface {
+ void method(boolean param);
+}
\ No newline at end of file
diff --git a/webkit-codegen/src/test/resources/codegen-expected/WebKitMethodParametertypeBoundaryInterface.java b/webkit-codegen/src/test/resources/codegen-expected/WebKitMethodParametertypeBoundaryInterface.java
new file mode 100644
index 0000000..8c1fea6
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen-expected/WebKitMethodParametertypeBoundaryInterface.java
@@ -0,0 +1,11 @@
+package org.chromium.support_lib_boundary;
+
+import java.lang.reflect.InvocationHandler;
+
+public interface WebKitMethodParametertypeBoundaryInterface {
+ void method(InvocationHandler webViewClient);
+
+ void methodX(InvocationHandler response);
+
+ void urlCall(String url);
+}
\ No newline at end of file
diff --git a/webkit-codegen/src/test/resources/codegen-expected/WebkitReturntypeClassBoundaryInterface.java b/webkit-codegen/src/test/resources/codegen-expected/WebkitReturntypeClassBoundaryInterface.java
new file mode 100644
index 0000000..498ea1e
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen-expected/WebkitReturntypeClassBoundaryInterface.java
@@ -0,0 +1,9 @@
+package org.chromium.support_lib_boundary;
+
+import java.lang.reflect.InvocationHandler;
+
+public interface WebkitReturntypeClassBoundaryInterface {
+ InvocationHandler method();
+
+ InvocationHandler method2();
+}
\ No newline at end of file
diff --git a/webkit-codegen/src/test/resources/codegen/SingleClassAndMethod.java b/webkit-codegen/src/test/resources/codegen/SingleClassAndMethod.java
new file mode 100644
index 0000000..3100ca8
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen/SingleClassAndMethod.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.webkit;
+
+public class SingleClassAndMethod {
+
+ public void method(boolean param) {
+ File x = new File("");
+ }
+}
diff --git a/webkit-codegen/src/test/resources/codegen/WebKitMethodParametertype.java b/webkit-codegen/src/test/resources/codegen/WebKitMethodParametertype.java
new file mode 100644
index 0000000..6730939
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen/WebKitMethodParametertype.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+public abstract class WebKitMethodParametertype {
+ public void method(WebViewClient webViewClient);
+ public void methodX(SafeBrowsingResponse response) {
+ return null;
+ }
+ public void urlCall(String url) {
+ return null;
+ }
+}
diff --git a/webkit-codegen/src/test/resources/codegen/WebkitReturntypeClass.java b/webkit-codegen/src/test/resources/codegen/WebkitReturntypeClass.java
new file mode 100644
index 0000000..aed7c36
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen/WebkitReturntypeClass.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+public class WebkitReturntypeClass {
+ public WebViewClient method() {
+ return null;
+ }
+ public SafeBrowsingResponse method2() {
+ return null;
+ }
+}
diff --git a/webkit-codegen/src/test/resources/codegen/deps/android/webkit/SafeBrowsingResponse.java b/webkit-codegen/src/test/resources/codegen/deps/android/webkit/SafeBrowsingResponse.java
new file mode 100644
index 0000000..960b56b
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen/deps/android/webkit/SafeBrowsingResponse.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+public class SafeBrowsingResponse {
+}
diff --git a/webkit-codegen/src/test/resources/codegen/deps/android/webkit/WebViewClient.java b/webkit-codegen/src/test/resources/codegen/deps/android/webkit/WebViewClient.java
new file mode 100644
index 0000000..f5d220c
--- /dev/null
+++ b/webkit-codegen/src/test/resources/codegen/deps/android/webkit/WebViewClient.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.webkit;
+
+public class WebViewClient {
+}