[go: nahoru, domu]

Merge "Document setTargetRotation for ImageAnalysis" into androidx-master-dev
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
index 918b673..c67da97 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
@@ -364,10 +364,10 @@
         List<Size> sizesNotMatchAspectRatio = new ArrayList<>();
 
         Rational aspectRatio = null;
-        Integer targetAspectRatio = config.getTargetAspectRatio(null);
-        if (targetAspectRatio != null) {
+        if (config.hasTargetAspectRatio()) {
             // Checks the sensor orientation.
             boolean isSensorLandscapeOrientation = isRotationNeeded(Surface.ROTATION_0);
+            @AspectRatio int targetAspectRatio = config.getTargetAspectRatio();
             switch (targetAspectRatio) {
                 case AspectRatio.RATIO_4_3:
                     aspectRatio =
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
index bd07ef3..55d6114 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
@@ -319,17 +319,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -736,7 +728,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
index d40e832..06a4036 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
@@ -95,18 +95,6 @@
     /**
      * Returns the {@link FlashMode}.
      *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
-    public Integer getFlashMode(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_FLASH_MODE, valueIfMissing);
-    }
-
-    /**
-     * Returns the {@link FlashMode}.
-     *
      * @return The stored value, if it exists in this configuration.
      * @throws IllegalArgumentException if the option does not exist in this configuration.
      */
@@ -423,17 +411,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -768,7 +748,7 @@
          *
          * @return A {@link ImageCaptureConfig} populated with the current state.
          * @throws IllegalArgumentException if attempting to set both target aspect ratio and
-         * target resolution.
+         *                                  target resolution.
          */
         @Override
         @NonNull
@@ -909,7 +889,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
index 3951792..68431fa 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
@@ -144,14 +144,12 @@
     Rational getTargetAspectRatioCustom();
 
     /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
+     * Verifies whether the aspect ratio of the target intending to use images from this
+     * configuration is set.
      *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
+     * @return true is the value exists in this configuration, false otherwise.
      */
-    @Nullable
-    Integer getTargetAspectRatio(@Nullable Integer valueIfMissing);
+    boolean hasTargetAspectRatio();
 
     /**
      * Retrieves the aspect ratio of the target intending to use images from this configuration.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
index 6c303fe..a03f6cb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
@@ -258,17 +258,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -637,7 +629,7 @@
          *
          * @return A {@link PreviewConfig} populated with the current state.
          * @throws IllegalArgumentException if attempting to set both target aspect ratio and
-         * target resolution.
+         *                                  target resolution.
          */
         @NonNull
         @Override
@@ -672,7 +664,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
index b4fc308..5b309d3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
@@ -462,17 +462,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -925,7 +917,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
diff --git a/room/common/api/2.3.0-alpha01.txt b/room/common/api/2.3.0-alpha01.txt
index 238967d..4e032bd 100644
--- a/room/common/api/2.3.0-alpha01.txt
+++ b/room/common/api/2.3.0-alpha01.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/current.txt b/room/common/api/current.txt
index 238967d..4e032bd 100644
--- a/room/common/api/current.txt
+++ b/room/common/api/current.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/public_plus_experimental_2.3.0-alpha01.txt b/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
index 238967d..4e032bd 100644
--- a/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
+++ b/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/public_plus_experimental_current.txt b/room/common/api/public_plus_experimental_current.txt
index 238967d..4e032bd 100644
--- a/room/common/api/public_plus_experimental_current.txt
+++ b/room/common/api/public_plus_experimental_current.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/restricted_2.3.0-alpha01.txt b/room/common/api/restricted_2.3.0-alpha01.txt
index ed6c4ee..a2a0510 100644
--- a/room/common/api/restricted_2.3.0-alpha01.txt
+++ b/room/common/api/restricted_2.3.0-alpha01.txt
@@ -176,6 +176,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/restricted_current.txt b/room/common/api/restricted_current.txt
index ed6c4ee..a2a0510 100644
--- a/room/common/api/restricted_current.txt
+++ b/room/common/api/restricted_current.txt
@@ -176,6 +176,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/src/main/java/androidx/room/RoomWarnings.java b/room/common/src/main/java/androidx/room/RoomWarnings.java
index e8ad213..66cc1b8 100644
--- a/room/common/src/main/java/androidx/room/RoomWarnings.java
+++ b/room/common/src/main/java/androidx/room/RoomWarnings.java
@@ -134,6 +134,47 @@
     public static final String RELATION_QUERY_WITHOUT_TRANSACTION =
             "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
 
+    /**
+     * Reported when an `@Entity` field's type do not exactly match the getter type.
+     * For instance, in the following class:
+     * <pre>
+     * {@code @}Entity
+     * class Foo {
+     *     ...
+     *     private Boolean value;
+     *     public boolean getValue() {
+     *         return value == null ? false : value;
+     *     }
+     * }
+     * </pre>
+     *
+     * Trying to insert this entity into database will always set {@code value} column to
+     * {@code false} when {@code Foo.value} is {@code null} since Room will use the {@code getValue}
+     * method to read the value. So even thought the database column is nullable, it will never
+     * be inserted as {@code null} if inserted as a {@code Foo} instance.
+     */
+    public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+
+    /**
+     * Reported when an `@Entity` field's type do not exactly match the setter type.
+     * For instance, in the following class:
+     * <pre>
+     * {@code @}Entity
+     * class Foo {
+     *     ...
+     *     private Boolean value;
+     *     public void setValue(boolean value) {
+     *         this.value = value;
+     *     }
+     * }
+     * </pre>
+     *
+     * If Room reads this entity from the database, it will always set {@code Foo.value} to
+     * {@code false} when the column value is {@code null} since Room will use the {@code setValue}
+     * method to write the value.
+     */
+    public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
+
     /** @deprecated This type should not be instantiated as it contains only static methods. */
     @Deprecated
     @SuppressWarnings("PrivateConstructorForUtilityClass")
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index 235a457..745c40f 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -718,6 +718,23 @@
         context.checker.check(
             success || bindingScope == FieldProcessor.BindingScope.READ_FROM_CURSOR,
             field.element, CANNOT_FIND_GETTER_FOR_FIELD)
+        if (success && !context.processingEnv.typeUtils.isSameType(field.getter.type, field.type)) {
+            // getter's parameter type is not exactly the same as the field type.
+            // put a warning and update the value statement binder.
+            context.logger.w(
+                warning = Warning.MISMATCHED_GETTER_TYPE,
+                element = field.element,
+                msg = ProcessorErrors.mismatchedGetter(
+                    fieldName = field.name,
+                    ownerType = element.asType().typeName(),
+                    getterType = field.getter.type.typeName(),
+                    fieldType = field.typeName
+                ))
+            field.statementBinder = context.typeAdapterStore.findStatementValueBinder(
+                input = field.getter.type,
+                affinity = field.affinity
+            )
+        }
     }
 
     private fun assignSetters(
@@ -769,6 +786,23 @@
         context.checker.check(
             success || bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT,
             field.element, CANNOT_FIND_SETTER_FOR_FIELD)
+        if (success && !context.processingEnv.typeUtils.isSameType(field.setter.type, field.type)) {
+            // setter's parameter type is not exactly the same as the field type.
+            // put a warning and update the value reader adapter.
+            context.logger.w(
+                warning = Warning.MISMATCHED_SETTER_TYPE,
+                element = field.element,
+                msg = ProcessorErrors.mismatchedSetter(
+                    fieldName = field.name,
+                    ownerType = element.asType().typeName(),
+                    setterType = field.setter.type.typeName(),
+                    fieldType = field.typeName
+                ))
+            field.cursorValueReader = context.typeAdapterStore.findCursorValueReader(
+                output = field.setter.type,
+                affinity = field.affinity
+            )
+        }
     }
 
     /**
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index d331aa1..d5b85f4 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -730,4 +730,26 @@
     fun invalidChannelType(typeName: String) = "'$typeName' is not supported as a return type. " +
             "Instead declare return type as ${KotlinTypeNames.FLOW} and use Flow transforming " +
             "functions that converts the Flow into a Channel."
+
+    fun mismatchedGetter(
+        fieldName: String,
+        ownerType: TypeName,
+        getterType: TypeName,
+        fieldType: TypeName
+    ) = """
+            $ownerType's $fieldName field has type $fieldType but its getter returns $getterType.
+            This mismatch might cause unexpected $fieldName values in the database when $ownerType
+            is inserted into database.
+        """.trim()
+
+    fun mismatchedSetter(
+        fieldName: String,
+        ownerType: TypeName,
+        setterType: TypeName,
+        fieldType: TypeName
+    ) = """
+            $ownerType's $fieldName field has type $fieldType but its setter accepts $setterType.
+            This mismatch might cause unexpected $fieldName values when $ownerType is read from the
+            database.
+        """.trim()
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
index 0abd15e9..f959979 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
@@ -36,7 +36,9 @@
     DEFAULT_CONSTRUCTOR("ROOM_DEFAULT_CONSTRUCTOR"),
     MISSING_COPY_ANNOTATIONS("MISSING_COPY_ANNOTATIONS"),
     MISSING_INDEX_ON_JUNCTION("MISSING_INDEX_ON_JUNCTION"),
-    JDK_VERSION_HAS_BUG("JDK_VERSION_HAS_BUG");
+    JDK_VERSION_HAS_BUG("JDK_VERSION_HAS_BUG"),
+    MISMATCHED_GETTER_TYPE("ROOM_MISMATCHED_GETTER_TYPE"),
+    MISMATCHED_SETTER_TYPE("ROOM_MISMATCHED_SETTER_TYPE");
 
     companion object {
         val PUBLIC_KEY_MAP = Warning.values().associateBy { it.publicKey }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
index 448ab8f..4ffb54a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
@@ -189,7 +189,10 @@
                     val constructorFields = node.directFields.filter {
                         it.field.setter.callType == CallType.CONSTRUCTOR
                     }.associateBy { fwi ->
-                        FieldReadWriteWriter(fwi).readIntoTmpVar(cursorVar, scope)
+                        FieldReadWriteWriter(fwi).readIntoTmpVar(
+                            cursorVar,
+                            fwi.field.setter.type.typeName(),
+                            scope)
                     }
                     // read decomposed fields (e.g. embedded)
                     node.subNodes.forEach(::visitNode)
@@ -349,9 +352,12 @@
     /**
      * Reads the value into a temporary local variable.
      */
-    fun readIntoTmpVar(cursorVar: String, scope: CodeGenScope): String {
+    fun readIntoTmpVar(
+        cursorVar: String,
+        typeName: TypeName,
+        scope: CodeGenScope
+    ): String {
         val tmpField = scope.getTmpVar("_tmp${field.name.capitalize()}")
-        val typeName = field.getter.type.typeName()
         scope.builder().apply {
             addStatement("final $T $L", typeName, tmpField)
             if (alwaysExists) {
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
index b9ec119..f9b4038 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
@@ -17,6 +17,7 @@
 package androidx.room.processor
 
 import COMMON
+import androidx.room.ext.typeName
 import androidx.room.parser.SQLTypeAffinity
 import androidx.room.processor.ProcessorErrors.RELATION_IN_ENTITY
 import androidx.room.vo.CallType
@@ -28,6 +29,8 @@
 import androidx.room.vo.Pojo
 import androidx.room.vo.columnNames
 import com.google.testing.compile.JavaFileObjects
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
 import compileLibrarySource
 import org.hamcrest.CoreMatchers.`is`
 import org.hamcrest.CoreMatchers.hasItems
@@ -35,6 +38,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import java.lang.AssertionError
 import javax.lang.model.type.TypeKind.INT
 
 @RunWith(JUnit4::class)
@@ -141,6 +145,46 @@
     }
 
     @Test
+    fun setterWithAssignableType_2() {
+        singleEntity("""
+                @PrimaryKey
+                private Integer id;
+                public Integer getId() {return id;}
+                public void setId(int id) {}
+                """) { entity, invocation ->
+            val idField = entity.fields.first()
+            val cursorValueReader = idField.cursorValueReader
+                ?: throw AssertionError("must have a cursor value reader")
+            assertThat(cursorValueReader.typeMirror().typeName(),
+                `is`(invocation.typeUtils.getPrimitiveType(INT).typeName()))
+        }.compilesWithoutError()
+            .withWarningContaining(
+                ProcessorErrors.mismatchedSetter(
+                    fieldName = "id",
+                    ownerType = ClassName.bestGuess("foo.bar.MyEntity"),
+                    setterType = TypeName.INT,
+                    fieldType = TypeName.INT.box()
+                )
+            )
+    }
+
+    @Test
+    fun getterWithAssignableType_2() {
+        singleEntity("""
+                @PrimaryKey
+                private Integer id;
+                public int getId() {return id == null ? 0 : id;}
+                public void setId(Integer id) {}
+                """) { entity, invocation ->
+            val idField = entity.fields.first()
+            val statementBinder = idField.statementBinder
+                ?: throw AssertionError("must have a statement binder")
+            assertThat(statementBinder.typeMirror().typeName(),
+                `is`(invocation.typeUtils.getPrimitiveType(INT).typeName()))
+        }.compilesWithoutError()
+    }
+
+    @Test
     fun noSetter() {
         singleEntity("""
                 @PrimaryKey
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 7e0f759..5f24684 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -75,6 +75,7 @@
     androidTestImplementation(ANDROIDX_TEST_RUNNER)
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(TRUTH)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
 
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java
new file mode 100644
index 0000000..fd2afd2
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2019 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 androidx.room.integration.testapp.test;
+
+import static androidx.room.integration.testapp.test.BoxedPrimitivesTest.BaseBoxed.DEFAULT_BOOLEAN_VALUE;
+import static androidx.room.integration.testapp.test.BoxedPrimitivesTest.BaseBoxed.DEFAULT_NUMBER_VALUE;
+
+import android.content.Context;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Dao;
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.Query;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BoxedPrimitivesTest {
+    private BoxingTestDatabase mDb;
+
+    @Before
+    public void initDb() {
+        Context context = ApplicationProvider.getApplicationContext();
+        mDb = Room.inMemoryDatabaseBuilder(
+                context,
+                BoxingTestDatabase.class)
+                .build();
+    }
+
+    @After
+    public void closeDb() {
+        mDb.close();
+    }
+
+    @Test
+    public void unboxedConstructor() {
+        test(mDb.constructor());
+    }
+
+    @Test
+    public void unboxedGetter() {
+        test(mDb.field());
+    }
+
+    /**
+     * Assert that if a nullable pojo is provided, we can actually insert/read null
+     */
+    private void test(BaseDao<? extends BaseBoxed> dao) {
+        long rowId = dao.insert(new BoxedBooleanHolder(null, null));
+        BaseBoxed read = dao.find(rowId);
+        Truth.assertThat(read.mFlag).isNull();
+        Truth.assertThat(read.mNumber).isNull();
+    }
+
+    @Test
+    public void testInsert_constructor() {
+        long rowId = mDb.constructor().insertTyped(new ConstructorEntity(null, null));
+        testInsertedAsEntity(mDb.constructor(), rowId);
+    }
+
+    @Test
+    public void testInsert_field() {
+        long rowId = mDb.field().insertTyped(new FieldEntity());
+        testInsertedAsEntity(mDb.field(), rowId);
+    }
+
+    /**
+     * assert the case where row was inserted via entity hence we should've read the default values
+     * already.
+     **/
+    private void testInsertedAsEntity(BaseDao<? extends BaseBoxed> dao, long rowId) {
+        BaseBoxed read = dao.find(rowId);
+        // default getter value
+        Truth.assertThat(read.mFlag).isEqualTo(DEFAULT_BOOLEAN_VALUE);
+        Truth.assertThat(read.mNumber).isEqualTo(DEFAULT_NUMBER_VALUE);
+    }
+
+    static class BaseBoxed {
+        @ColumnInfo(name = "boxed_bool")
+        Boolean mFlag;
+        @ColumnInfo(name = "boxed_int")
+        Integer mNumber;
+
+        static final boolean DEFAULT_BOOLEAN_VALUE = true;
+        static final int DEFAULT_NUMBER_VALUE = 41;
+
+        @SuppressWarnings("unused")
+        boolean getFlag() {
+            return mFlag == null ? DEFAULT_BOOLEAN_VALUE : mFlag;
+        }
+
+        @SuppressWarnings("unused")
+        int getNumber() {
+            return mNumber == null ? DEFAULT_NUMBER_VALUE : mNumber;
+        }
+    }
+
+    @Entity
+    static class ConstructorEntity extends BaseBoxed {
+        @PrimaryKey(autoGenerate = true)
+        public long rowId = 0;
+
+        ConstructorEntity(Boolean flag, Integer number) {
+            this.mFlag = flag;
+            this.mNumber = number;
+        }
+    }
+
+    @Entity
+    static class FieldEntity extends BaseBoxed {
+        @PrimaryKey(autoGenerate = true)
+        public long rowId = 0;
+
+        void setBoxed(Boolean boxed) {
+            this.mFlag = boxed;
+        }
+
+        void setNumber(Integer number) {
+            this.mNumber = number;
+        }
+    }
+
+    static class BoxedBooleanHolder {
+        @ColumnInfo(name = "boxed_bool")
+        final Boolean mFlag;
+        @ColumnInfo(name = "boxed_int")
+        final Integer mNumber;
+
+        BoxedBooleanHolder(Boolean flag, Integer number) {
+            mFlag = flag;
+            mNumber = number;
+        }
+    }
+
+    interface BaseDao<T> {
+        long insert(BoxedBooleanHolder t);
+
+        @Insert
+        long insertTyped(T t);
+
+        T find(long rowId);
+    }
+
+    @Dao
+    interface BoxedConstructorDao extends BaseDao<ConstructorEntity> {
+        @Override
+        @Insert(entity = ConstructorEntity.class)
+        long insert(BoxedBooleanHolder item);
+
+        @Override
+        @Query("SELECT * FROM ConstructorEntity WHERE rowId = :rowId")
+        ConstructorEntity find(long rowId);
+    }
+
+    @Dao
+    interface BoxedFieldDao extends BaseDao<FieldEntity> {
+
+        @Insert(entity = FieldEntity.class)
+        long insert(BoxedBooleanHolder item);
+
+        @Override
+        @Query("SELECT * FROM FieldEntity WHERE rowId = :rowId")
+        FieldEntity find(long rowId);
+    }
+
+    @Database(
+            entities = {FieldEntity.class, ConstructorEntity.class},
+            version = 1,
+            exportSchema = false
+    )
+    abstract static class BoxingTestDatabase extends RoomDatabase {
+        abstract BoxedConstructorDao constructor();
+
+        abstract BoxedFieldDao field();
+    }
+}
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
index 5175929..500c1f6a 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
@@ -263,6 +263,8 @@
             }
         }
         assertTrue(latch.await(1, TimeUnit.SECONDS))
+
+        assertCountDownOnlyWhileEnabled(enabled, model)
     }
 
     @Test