Merge "Enforcing a NON NULL constraint on the PrimaryKey" into oc-mr1-dev
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index 710ccbe..44d5ff0 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -39,7 +39,6 @@
 dependencies {
     compile project(":arch:runtime")
     compile libs.support.annotations
-    compile libs.support.core_utils
     compile(libs.junit) {
         exclude module: 'hamcrest-core'
     }
diff --git a/app-toolkit/dependencies.gradle b/app-toolkit/dependencies.gradle
index 755c3d0..083325b 100644
--- a/app-toolkit/dependencies.gradle
+++ b/app-toolkit/dependencies.gradle
@@ -26,7 +26,7 @@
 ffVersions.auto_common = "0.6"
 ffVersions.javapoet = "1.8.0"
 ffVersions.compile_testing = "0.11"
-ffVersions.support_lib = "26.0.0"
+ffVersions.support_lib = "26.1.0"
 ffVersions.intellij_annotations = "12.0"
 ffVersions.rxjava2 = "2.0.6"
 ffVersions.reactivestreams = "1.0.0"
@@ -69,6 +69,11 @@
         recyclerview : getSupportLib(':recyclerview-v7', ffVersions.support_lib)
 ]
 
+ffLibs.support_exclude_config = {
+    exclude group: 'android.arch.core'
+    exclude group: 'android.arch.lifecycle'
+}
+
 ffLibs.javapoet = "com.squareup:javapoet:$ffVersions.javapoet"
 ffLibs.antlr = "org.antlr:antlr4:$ffVersions.antlr"
 ffLibs.xerial = "org.xerial:sqlite-jdbc:$ffVersions.xerial"
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index aeb9718..8f60355 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -94,6 +94,7 @@
 
 rootProject.ext.flatfootProjectGroups = [
         "room" : "android.arch.persistence.room",
+        "persistence" : "android.arch.persistence",
         "lifecycle" : "android.arch.lifecycle",
         "arch" : "android.arch.core",
         "paging" : "android.arch.paging",
diff --git a/app-toolkit/settings.gradle b/app-toolkit/settings.gradle
index 0977dc6..31fc0e1 100644
--- a/app-toolkit/settings.gradle
+++ b/app-toolkit/settings.gradle
@@ -75,11 +75,11 @@
 include ':room:migration'
 project(':room:migration').projectDir = new File(supportRoot, "room/migration")
 
-include ':room:db'
-project(':room:db').projectDir = new File(supportRoot, "room/db")
+include ':persistence:db'
+project(':persistence:db').projectDir = new File(supportRoot, "persistence/db")
 
-include ":room:db-impl"
-project(':room:db-impl').projectDir = new File(supportRoot, "room/db-impl")
+include ":persistence:db-framework"
+project(':persistence:db-framework').projectDir = new File(supportRoot, "persistence/db-framework")
 
 include ":room:testing"
 project(':room:testing').projectDir = new File(supportRoot, "room/testing")
diff --git a/buildSrc/src/main/groovy/android/support/SupportKotlinLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportKotlinLibraryPlugin.groovy
new file mode 100644
index 0000000..237aa97
--- /dev/null
+++ b/buildSrc/src/main/groovy/android/support/SupportKotlinLibraryPlugin.groovy
@@ -0,0 +1,43 @@
+/*
+ * 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);
+        SupportLibraryMavenUploader.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/compat/api/current.txt b/compat/api/current.txt
index 8dea70f..c4e7fd3 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -838,7 +838,7 @@
     method public static deprecated boolean isAtLeastN();
     method public static deprecated boolean isAtLeastNMR1();
     method public static deprecated boolean isAtLeastO();
-    method public static boolean isAtLeastOMR1();
+    method public static deprecated boolean isAtLeastOMR1();
     method public static boolean isAtLeastP();
   }
 
@@ -1651,7 +1651,7 @@
     method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
     method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
     method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
-    method public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
+    method public static deprecated void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
     method public static void setClipBounds(android.view.View, android.graphics.Rect);
     method public static void setElevation(android.view.View, float);
     method public static deprecated void setFitsSystemWindows(android.view.View, boolean);
diff --git a/compat/java/android/support/v4/os/BuildCompat.java b/compat/java/android/support/v4/os/BuildCompat.java
index 9a48c5f..586557d 100644
--- a/compat/java/android/support/v4/os/BuildCompat.java
+++ b/compat/java/android/support/v4/os/BuildCompat.java
@@ -60,6 +60,7 @@
      *             be removed in a future release of the Support Library. Instead use
      *             {@code Build.SDK_INT >= Build.VERSION_CODES#O}.
      */
+    @Deprecated
     public static boolean isAtLeastO() {
         return VERSION.SDK_INT >= 26;
     }
@@ -68,7 +69,11 @@
      * Checks if the device is running on a pre-release version of Android O MR1 or newer.
      * <p>
      * @return {@code true} if O MR1 APIs are available for use, {@code false} otherwise
+     * @deprecated Android O MR1 is a finalized release and this method is no longer necessary. It
+     *             will be removed in a future release of the Support Library. Instead, use
+     *             {@code Build.SDK_INT >= Build.VERSION_CODES#O_MR1}.
      */
+    @Deprecated
     public static boolean isAtLeastOMR1() {
         return VERSION.SDK_INT >= 27;
     }
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index e7443d7..34a198a 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -3029,7 +3029,10 @@
      *        {@link ViewGroup#getChildDrawingOrder(int, int)}, false otherwise
      *
      * <p>Prior to API 7 this will have no effect.</p>
+     *
+     * @deprecated Use {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean)} directly.
      */
+    @Deprecated
     public static void setChildrenDrawingOrderEnabled(ViewGroup viewGroup, boolean enabled) {
        IMPL.setChildrenDrawingOrderEnabled(viewGroup, enabled);
     }
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
index f9329fa..327be01 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
@@ -1863,7 +1863,7 @@
     }
 
     /**
-     * Sets whether this node is visible to the user.
+     * Gets whether this node is visible to the user.
      *
      * @return Whether the node is visible to the user.
      */
diff --git a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
index d36ae22..2181bab 100644
--- a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -341,7 +341,7 @@
         mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density);
 
         createProgressView();
-        ViewCompat.setChildrenDrawingOrderEnabled(this, true);
+        setChildrenDrawingOrderEnabled(true);
         // the absolute offset has to take into account that the circle starts at an offset
         mSpinnerOffsetEnd = (int) (DEFAULT_CIRCLE_TARGET * metrics.density);
         mTotalDragDistance = mSpinnerOffsetEnd;
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 20e8d9e..6e6caa0 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -1594,6 +1594,8 @@
     private void animateRemoveFragment(@NonNull final Fragment fragment,
             @NonNull AnimationOrAnimator anim, final int newState) {
         final View viewToAnimate = fragment.mView;
+        final ViewGroup container = fragment.mContainer;
+        container.startViewTransition(viewToAnimate);
         fragment.setStateAfterAnimating(newState);
         if (anim.animation != null) {
             Animation animation = anim.animation;
@@ -1603,6 +1605,8 @@
                 @Override
                 public void onAnimationEnd(Animation animation) {
                     super.onAnimationEnd(animation);
+                    container.endViewTransition(viewToAnimate);
+
                     if (fragment.getAnimatingAway() != null) {
                         fragment.setAnimatingAway(null);
                         moveToState(fragment, fragment.getStateAfterAnimating(), 0, 0, false);
@@ -1612,25 +1616,18 @@
             setHWLayerAnimListenerIfAlpha(viewToAnimate, anim);
             fragment.mView.startAnimation(animation);
         } else {
-            final Animator animator = anim.animator;
+            Animator animator = anim.animator;
             fragment.setAnimator(anim.animator);
-            final ViewGroup container = fragment.mContainer;
-            if (container != null) {
-                container.startViewTransition(viewToAnimate);
-            }
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator anim) {
-                    // AnimatorSet in API 26 (only) can end() during start(), so delay by posting
-                    if (container == null || container.indexOfChild(viewToAnimate) < 0) {
-                        finishAnimatedFragmentRemoval(fragment, container, viewToAnimate);
-                    } else {
-                        viewToAnimate.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                finishAnimatedFragmentRemoval(fragment, container, viewToAnimate);
-                            }
-                        });
+                    container.endViewTransition(viewToAnimate);
+                    // If an animator ends immediately, we can just pretend there is no animation.
+                    // When that happens the the fragment's view won't have been removed yet.
+                    Animator animator = fragment.getAnimator();
+                    fragment.setAnimator(null);
+                    if (animator != null && container.indexOfChild(viewToAnimate) < 0) {
+                        moveToState(fragment, fragment.getStateAfterAnimating(), 0, 0, false);
                     }
                 }
             });
@@ -1640,17 +1637,6 @@
         }
     }
 
-    void finishAnimatedFragmentRemoval(Fragment fragment, ViewGroup container, View view) {
-        if (container != null) {
-            container.endViewTransition(view);
-        }
-        if (fragment.getAnimator() != null) {
-            fragment.setAnimator(null);
-            moveToState(fragment, fragment.getStateAfterAnimating(), 0, 0,
-                    false);
-        }
-    }
-
     void moveToState(Fragment f) {
         moveToState(f, mCurState, 0, 0, false);
     }
@@ -2646,7 +2632,6 @@
                     // Give up waiting for the animation and just end it.
                     final int stateAfterAnimating = fragment.getStateAfterAnimating();
                     final View animatingAway = fragment.getAnimatingAway();
-                    fragment.setAnimatingAway(null);
                     Animation animation = animatingAway.getAnimation();
                     if (animation != null) {
                         animation.cancel();
@@ -2654,6 +2639,7 @@
                         // and will instead cause the animation to infinitely loop
                         animatingAway.clearAnimation();
                     }
+                    fragment.setAnimatingAway(null);
                     moveToState(fragment, stateAfterAnimating, 0, 0, false);
                 } else if (fragment.getAnimator() != null) {
                     fragment.getAnimator().end();
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index b1477f5..44bf15d 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -1,8 +1,6 @@
 import android.support.LibraryVersions
-
-apply plugin: 'kotlin'
-apply plugin: 'maven'
-apply plugin: 'checkstyle'
+import android.support.SupportLibraryExtension
+apply plugin: android.support.SupportKotlinLibraryPlugin
 
 sourceSets {
     test.java.srcDirs += 'src/tests/kotlin'
@@ -27,3 +25,11 @@
 
 version = LibraryVersions.LIFECYCLES_EXT.toString()
 createKotlinCheckstyle(project)
+
+supportLibrary {
+    name 'Android Lifecycles Compiler'
+    publish true
+    inceptionYear '2017'
+    description "Android Lifecycles annotation processor"
+    url SupportLibraryExtension.ARCHITECTURE_URL
+}
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
index dca78d5..4f12ff4 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
@@ -30,6 +30,7 @@
 import javax.lang.model.element.ExecutableElement
 import javax.lang.model.element.Modifier
 import javax.lang.model.element.TypeElement
+import javax.tools.StandardLocation
 
 fun writeModels(infos: List<AdapterClass>, processingEnv: ProcessingEnvironment) {
     infos.forEach({ writeAdapter(it, processingEnv) })
@@ -116,6 +117,8 @@
 
     JavaFile.builder(adapter.type.getPackageQName(), adapterTypeSpecBuilder.build())
             .build().writeTo(processingEnv.filer)
+
+    generateKeepRule(adapter.type, processingEnv)
 }
 
 private fun addGeneratedAnnotationIfAvailable(adapterTypeSpecBuilder: TypeSpec.Builder,
@@ -133,6 +136,25 @@
     }
 }
 
+private fun generateKeepRule(type: TypeElement, processingEnv: ProcessingEnvironment) {
+    val adapterClass = type.getPackageQName() + "." + getAdapterName(type)
+    val observerClass = type.toString()
+    val keepRule = """# Generated keep rule for Lifecycle observer adapter.
+        |-keep class $adapterClass {
+        |   ifused class $observerClass {
+        |       <init>(...);
+        |   };
+        |}
+        |""".trimMargin()
+
+    // Write the keep rule to the META-INF/proguard directory of the Jar file. The file name
+    // contains the fully qualified observer name so that file names are unique. This will allow any
+    // jar file merging to not overwrite keep rule files.
+    val path = "META-INF/proguard/$observerClass.pro"
+    val out = processingEnv.filer.createResource(StandardLocation.CLASS_OUTPUT, "", path)
+    out.openWriter().use { it.write(keepRule) }
+}
+
 private fun MethodSpec.Builder.writeMethodCalls(eventParam: ParameterSpec,
                                                 calls: List<EventMethodCall>,
                                                 ownerParam: ParameterSpec,
diff --git a/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt b/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt
index 66429a2..247d416 100644
--- a/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt
+++ b/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt
@@ -18,9 +18,11 @@
 
 import android.arch.lifecycle.utils.load
 import android.arch.lifecycle.utils.processClass
+import com.google.testing.compile.CompileTester
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import javax.tools.StandardLocation
 
 @RunWith(JUnit4::class)
 class ValidCasesTest {
@@ -33,7 +35,7 @@
     fun testOnAny() {
         processClass("foo.OnAnyMethod").compilesWithoutError().and().generatesSources(
                 load("foo.OnAnyMethod_LifecycleAdapter", "expected")
-        )
+        ).and().generatesProGuardRule("foo.OnAnyMethod.pro")
     }
 
     @Test
@@ -47,6 +49,8 @@
                 load("foo.InheritanceOk2Base_LifecycleAdapter", "expected"),
                 load("foo.InheritanceOk2Derived_LifecycleAdapter", "expected")
         )
+                .and().generatesProGuardRule("foo.InheritanceOk2Base.pro")
+                .and().generatesProGuardRule("foo.InheritanceOk2Derived.pro")
     }
 
     @Test
@@ -55,6 +59,8 @@
                 load("foo.InheritanceOk3Base_LifecycleAdapter", "expected"),
                 load("foo.InheritanceOk3Derived_LifecycleAdapter", "expected")
         )
+                .and().generatesProGuardRule("foo.InheritanceOk3Base.pro")
+                .and().generatesProGuardRule("foo.InheritanceOk3Derived.pro")
     }
 
     @Test
@@ -74,6 +80,9 @@
                 load("foo.InterfaceOk2Derived_LifecycleAdapter", "expected"),
                 load("foo.InterfaceOk2Interface_LifecycleAdapter", "expected")
         )
+                .and().generatesProGuardRule("foo.InterfaceOk2Base.pro")
+                .and().generatesProGuardRule("foo.InterfaceOk2Derived.pro")
+                .and().generatesProGuardRule("foo.InterfaceOk2Interface.pro")
     }
 
     @Test
@@ -83,6 +92,8 @@
                 load("foo.DifferentPackagesBase1_LifecycleAdapter", "expected"),
                 load("bar.DifferentPackagesDerived1_LifecycleAdapter", "expected")
         )
+                .and().generatesProGuardRule("foo.DifferentPackagesBase1.pro")
+                .and().generatesProGuardRule("bar.DifferentPackagesDerived1.pro")
     }
 
     @Test
@@ -92,5 +103,13 @@
                 load("foo.DifferentPackagesBase2_LifecycleAdapter", "expected"),
                 load("bar.DifferentPackagesDerived2_LifecycleAdapter", "expected")
         )
+                .and().generatesProGuardRule("foo.DifferentPackagesPreBase2.pro")
+                .and().generatesProGuardRule("foo.DifferentPackagesBase2.pro")
+                .and().generatesProGuardRule("bar.DifferentPackagesDerived2.pro")
+    }
+
+    private fun <T> CompileTester.GeneratedPredicateClause<T>.generatesProGuardRule(name: String):
+            CompileTester.SuccessfulFileClause<T> {
+        return generatesFileNamed(StandardLocation.CLASS_OUTPUT, "", "META-INF/proguard/$name")
     }
 }
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index 9f61b73..241e99a 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -43,7 +43,7 @@
     compile project(":lifecycle:runtime")
     compile project(":arch:common")
     compile project(":arch:runtime")
-    compile libs.support.fragments
+    compile libs.support.fragments, libs.support_exclude_config
 
     annotationProcessor project(":lifecycle:compiler")
 
@@ -53,7 +53,7 @@
 
     androidTestImplementation libs.test_runner,      { exclude module: 'support-annotations' }
     androidTestImplementation libs.espresso_core,    { exclude module: 'support-annotations' }
-    androidTestImplementation libs.support.app_compat
+    androidTestImplementation libs.support.app_compat, libs.support_exclude_config
 }
 
 createAndroidCheckstyle(project)
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleActivity.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleActivity.java
index 196a8d7..26bd508 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleActivity.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleActivity.java
@@ -19,17 +19,8 @@
 import android.support.v4.app.FragmentActivity;
 
 /**
- * Activity that implements {@link LifecycleOwner}.
- * <p>
- * This class is a temporary implementation detail until Lifecycles are integrated with support
- * library.
+ * @deprecated Use {@code android.support.v7.app.AppCompatActivity} instead of this class.
  */
-public class LifecycleActivity extends FragmentActivity implements LifecycleRegistryOwner {
-
-    private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);
-
-    @Override
-    public LifecycleRegistry getLifecycle() {
-        return mRegistry;
-    }
+@Deprecated
+public class LifecycleActivity extends FragmentActivity {
 }
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleFragment.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleFragment.java
index d8dbf38..c0da66b 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleFragment.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleFragment.java
@@ -19,17 +19,8 @@
 import android.support.v4.app.Fragment;
 
 /**
- * A fragment that is also a {@link LifecycleOwner}.
- * <p>
- * This class is a temporary implementation detail until Lifecycles are integrated with support
- * library.
+ * @deprecated Use {@link Fragment} instead of it.
  */
-// This class will be removed once we integrate with Fragment library.
-public class LifecycleFragment extends Fragment implements LifecycleRegistryOwner {
-    LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
-
-    @Override
-    public LifecycleRegistry getLifecycle() {
-        return mLifecycleRegistry;
-    }
+@Deprecated
+public class LifecycleFragment extends Fragment {
 }
diff --git a/lifecycle/integration-tests/testapp/build.gradle b/lifecycle/integration-tests/testapp/build.gradle
index b0da333..dca413b 100644
--- a/lifecycle/integration-tests/testapp/build.gradle
+++ b/lifecycle/integration-tests/testapp/build.gradle
@@ -52,7 +52,6 @@
 }
 
 dependencies {
-    compile fileTree(dir: 'libs', include: ['*.jar'])
     // IJ canont figure out transitive dependencies so need to declare them.
     compile project(":lifecycle:common")
     compile project(":lifecycle:runtime")
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index f973e0e..bd64a32 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -50,7 +50,7 @@
         testCompile(libs.test_runner) {
             exclude module: 'support-annotations'
         }
-        androidTestCompile libs.support.app_compat
+        androidTestCompile libs.support.app_compat, libs.support_exclude_config
     }
 }
 
diff --git a/lifecycle/runtime/api/1.0.0.txt b/lifecycle/runtime/api/1.0.0.txt
index 93a55fc..2b900b0 100644
--- a/lifecycle/runtime/api/1.0.0.txt
+++ b/lifecycle/runtime/api/1.0.0.txt
@@ -10,7 +10,7 @@
     method public void removeObserver(android.arch.lifecycle.LifecycleObserver);
   }
 
-  public abstract interface LifecycleRegistryOwner implements android.arch.lifecycle.LifecycleOwner {
+  public abstract deprecated interface LifecycleRegistryOwner implements android.arch.lifecycle.LifecycleOwner {
     method public abstract android.arch.lifecycle.LifecycleRegistry getLifecycle();
   }
 
diff --git a/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistryOwner.java b/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistryOwner.java
index 634cfc3..38eeb6d 100644
--- a/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistryOwner.java
+++ b/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistryOwner.java
@@ -17,14 +17,11 @@
 package android.arch.lifecycle;
 
 /**
- * Specialization of {@link LifecycleOwner} that explicitly returns {@link LifecycleRegistry}.
- * <p>
- * This method may be used if an object which updates state of {@link Lifecycle} doesn't own it.
- * <p>
- * This class is a temporary implementation detail until Lifecycles are integrated with support
- * library.
+ * @deprecated Use {@code android.support.v7.app.AppCompatActivity}
+ * which extends {@link LifecycleOwner}, so there are no use cases for this class.
  */
 @SuppressWarnings({"WeakerAccess", "unused"})
+@Deprecated
 public interface LifecycleRegistryOwner extends LifecycleOwner {
     @Override
     LifecycleRegistry getLifecycle();
diff --git a/lifecycle/runtime/src/main/java/android/arch/lifecycle/ReportFragment.java b/lifecycle/runtime/src/main/java/android/arch/lifecycle/ReportFragment.java
index 490028c..3e4ece8 100644
--- a/lifecycle/runtime/src/main/java/android/arch/lifecycle/ReportFragment.java
+++ b/lifecycle/runtime/src/main/java/android/arch/lifecycle/ReportFragment.java
@@ -110,8 +110,17 @@
     }
 
     private void dispatch(Lifecycle.Event event) {
-        if (getActivity() instanceof LifecycleRegistryOwner) {
-            ((LifecycleRegistryOwner) getActivity()).getLifecycle().handleLifecycleEvent(event);
+        Activity activity = getActivity();
+        if (activity instanceof LifecycleRegistryOwner) {
+            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
+            return;
+        }
+
+        if (activity instanceof LifecycleOwner) {
+            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
+            if (lifecycle instanceof LifecycleRegistry) {
+                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
+            }
         }
     }
 
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
index 8175aae..53b111a 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -550,7 +550,7 @@
     /**
      * All the info about a connection.
      */
-    private static class ConnectionRecord {
+    private class ConnectionRecord implements IBinder.DeathRecipient {
         String pkg;
         Bundle rootHints;
         ServiceCallbacks callbacks;
@@ -559,6 +559,16 @@
 
         ConnectionRecord() {
         }
+
+        @Override
+        public void binderDied() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mConnections.remove(callbacks.asBinder());
+                }
+            });
+        }
     }
 
     /**
@@ -747,6 +757,7 @@
                     } else {
                         try {
                             mConnections.put(b, connection);
+                            b.linkToDeath(connection, 0);
                             if (mSession != null) {
                                 callbacks.onConnect(connection.root.getRootId(),
                                         mSession, connection.root.getExtras());
@@ -771,6 +782,7 @@
                     final ConnectionRecord old = mConnections.remove(b);
                     if (old != null) {
                         // TODO
+                        old.callbacks.asBinder().unlinkToDeath(old, 0);
                     }
                 }
             });
@@ -852,6 +864,11 @@
                     connection.callbacks = callbacks;
                     connection.rootHints = rootHints;
                     mConnections.put(b, connection);
+                    try {
+                        b.linkToDeath(connection, 0);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "IBinder is already dead.");
+                    }
                 }
             });
         }
@@ -862,7 +879,10 @@
                 @Override
                 public void run() {
                     final IBinder b = callbacks.asBinder();
-                    mConnections.remove(b);
+                    ConnectionRecord old = mConnections.remove(b);
+                    if (old != null) {
+                        b.unlinkToDeath(old, 0);
+                    }
                 }
             });
         }
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index 78e12ba..bb9ad6b 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -28,7 +28,6 @@
     testCompile libs.mockito_core
     compile libs.support.annotations
     compile project(path: ':arch:common')
-    compile libs.junit
     testCompile libs.kotlin.stdlib
 }
 
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index 5356dd4..47f45d1 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -46,8 +46,8 @@
     compile project(':paging:runtime')
     compile 'com.android.support:multidex:1.0.1'
 
-    compile libs.support.recyclerview
-    compile libs.support.app_compat
+    compile libs.support.recyclerview, libs.support_exclude_config
+    compile libs.support.app_compat, libs.support_exclude_config
 }
 
 createAndroidCheckstyle(project)
diff --git a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java
index f002218..5d0117d 100644
--- a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java
+++ b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java
@@ -17,7 +17,6 @@
 package android.arch.paging.integration.testapp;
 
 import android.arch.lifecycle.LifecycleRegistry;
-import android.arch.lifecycle.LifecycleRegistryOwner;
 import android.arch.lifecycle.Observer;
 import android.arch.lifecycle.ViewModelProviders;
 import android.arch.paging.PagedList;
@@ -31,7 +30,7 @@
 /**
  * Sample NullPaddedList activity with artificial data source.
  */
-public class PagedListSampleActivity extends AppCompatActivity implements LifecycleRegistryOwner {
+public class PagedListSampleActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 990e140..0ee0c77 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -42,7 +42,7 @@
     compile project(":lifecycle:runtime")
     compile project(':lifecycle:extensions')
 
-    compile libs.support.recyclerview
+    compile libs.support.recyclerview, libs.support_exclude_config
 
     androidTestImplementation libs.junit
     androidTestImplementation libs.mockito_core,     { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
diff --git a/paging/runtime/src/androidTest/java/android/arch/paging/ListDataSource.java b/paging/runtime/src/androidTest/java/android/arch/paging/ListDataSource.java
index 241c8f0..f3e83d0 100644
--- a/paging/runtime/src/androidTest/java/android/arch/paging/ListDataSource.java
+++ b/paging/runtime/src/androidTest/java/android/arch/paging/ListDataSource.java
@@ -26,7 +26,7 @@
     }
 
     @Override
-    public int loadCount() {
+    public int countItems() {
         return mList.size();
     }
 
diff --git a/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java b/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java
index 821eac2..6304b29 100644
--- a/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java
+++ b/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java
@@ -28,8 +28,16 @@
  * Return type for data-loading system of an application or library to produce a
  * {@code LiveData<PagedList>}, while leaving the details of the paging mechanism up to the
  * consumer.
+ * <p>
+ * If you're using Room, it can generate a LivePagedListProvider from a query:
+ * <pre>
+ * {@literal @}Dao
+ * interface UserDao {
+ *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
+ *     public abstract LivePagedListProvider&lt;Integer, User> usersByLastName();
+ * }</pre>
  *
- * @param <Key> Tyep of input valued used to load data from the DataSource. Must be integer if
+ * @param <Key> Type of input valued used to load data from the DataSource. Must be integer if
  *             you're using TiledDataSource.
  * @param <Value> Data type produced by the DataSource, and held by the PagedLists.
  *
diff --git a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java
index 73c1b64..19a0c55 100644
--- a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java
+++ b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java
@@ -44,7 +44,7 @@
  * {@literal @}Dao
  * interface UserDao {
  *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
- *     public abstract LivePagedListProvider&lt;User> usersByLastName();
+ *     public abstract LivePagedListProvider&lt;Integer, User> usersByLastName();
  * }
  *
  * class MyViewModel extends ViewModel {
@@ -58,7 +58,7 @@
  *     }
  * }
  *
- * class MyActivity extends Activity implements LifecycleRegistryOwner {
+ * class MyActivity extends AppCompatActivity {
  *     {@literal @}Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
diff --git a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
index 7d7a922..4bff5fc 100644
--- a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
+++ b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
@@ -50,7 +50,7 @@
  * {@literal @}Dao
  * interface UserDao {
  *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
- *     public abstract LivePagedListProvider&lt;User> usersByLastName();
+ *     public abstract LivePagedListProvider&lt;Integer, User> usersByLastName();
  * }
  *
  * class MyViewModel extends ViewModel {
@@ -64,7 +64,7 @@
  *     }
  * }
  *
- * class MyActivity extends Activity implements LifecycleRegistryOwner {
+ * class MyActivity extends AppCompatActivity {
  *     {@literal @}Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
index 8035a27..e08cb53 100644
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
+++ b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
@@ -46,7 +46,7 @@
  *     }
  * }
  *
- * class MyActivity extends Activity implements LifecycleRegistryOwner {
+ * class MyActivity extends AppCompatActivity {
  *     {@literal @}Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java
index e4a53fd..b47b833 100644
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java
+++ b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java
@@ -55,7 +55,7 @@
  *     }
  * }
  *
- * class MyActivity extends Activity implements LifecycleRegistryOwner {
+ * class MyActivity extends AppCompatActivity {
  *     {@literal @}Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
diff --git a/room/db-impl/.gitignore b/persistence/db-framework/.gitignore
similarity index 100%
rename from room/db-impl/.gitignore
rename to persistence/db-framework/.gitignore
diff --git a/room/db-impl/build.gradle b/persistence/db-framework/build.gradle
similarity index 90%
rename from room/db-impl/build.gradle
rename to persistence/db-framework/build.gradle
index a5da1f1..0961ba5 100644
--- a/room/db-impl/build.gradle
+++ b/persistence/db-framework/build.gradle
@@ -42,7 +42,7 @@
 
 dependencies {
     compile libs.support.annotations
-    compile project(":room:db")
+    compile project(":persistence:db")
 }
 createAndroidCheckstyle(project)
 
@@ -58,9 +58,9 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android DB-Impl'
+    name 'Android Support SQLite - Framework Implementation'
     publish true
     inceptionYear '2017'
-    description "Android DB-Impl"
+    description "The implementation of Support SQLite library using the framework code."
     url SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/room/db-impl/src/main/AndroidManifest.xml b/persistence/db-framework/src/main/AndroidManifest.xml
similarity index 100%
rename from room/db-impl/src/main/AndroidManifest.xml
rename to persistence/db-framework/src/main/AndroidManifest.xml
diff --git a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteDatabase.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteDatabase.java
similarity index 98%
rename from room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteDatabase.java
rename to persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteDatabase.java
index 92a5820..e9c2b74 100644
--- a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteDatabase.java
+++ b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteDatabase.java
@@ -53,8 +53,7 @@
      *
      * @param delegate The delegate to receive all calls.
      */
-    @SuppressWarnings("WeakerAccess")
-    public FrameworkSQLiteDatabase(SQLiteDatabase delegate) {
+    FrameworkSQLiteDatabase(SQLiteDatabase delegate) {
         mDelegate = delegate;
     }
 
diff --git a/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper.java
new file mode 100644
index 0000000..a1690f4
--- /dev/null
+++ b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 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.db.framework;
+
+import android.arch.persistence.db.SupportSQLiteDatabase;
+import android.arch.persistence.db.SupportSQLiteOpenHelper;
+import android.content.Context;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+
+class FrameworkSQLiteOpenHelper implements SupportSQLiteOpenHelper {
+    private final OpenHelper mDelegate;
+
+    FrameworkSQLiteOpenHelper(Context context, String name,
+            Callback callback) {
+        mDelegate = createDelegate(context, name, callback);
+    }
+
+    private OpenHelper createDelegate(Context context, String name, Callback callback) {
+        final FrameworkSQLiteDatabase[] dbRef = new FrameworkSQLiteDatabase[1];
+        return new OpenHelper(context, name, dbRef, callback);
+    }
+
+    @Override
+    public String getDatabaseName() {
+        return mDelegate.getDatabaseName();
+    }
+
+    @Override
+    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+    public void setWriteAheadLoggingEnabled(boolean enabled) {
+        mDelegate.setWriteAheadLoggingEnabled(enabled);
+    }
+
+    @Override
+    public SupportSQLiteDatabase getWritableDatabase() {
+        return mDelegate.getWritableSupportDatabase();
+    }
+
+    @Override
+    public SupportSQLiteDatabase getReadableDatabase() {
+        return mDelegate.getReadableSupportDatabase();
+    }
+
+    @Override
+    public void close() {
+        mDelegate.close();
+    }
+
+    static class OpenHelper extends SQLiteOpenHelper {
+        /**
+         * This is used as an Object reference so that we can access the wrapped database inside
+         * the constructor. SQLiteOpenHelper requires the error handler to be passed in the
+         * constructor.
+         */
+        final FrameworkSQLiteDatabase[] mDbRef;
+        final Callback mCallback;
+
+        OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef,
+                final Callback callback) {
+            super(context, name, null, callback.version,
+                    new DatabaseErrorHandler() {
+                        @Override
+                        public void onCorruption(SQLiteDatabase dbObj) {
+                            FrameworkSQLiteDatabase db = dbRef[0];
+                            if (db != null) {
+                                callback.onCorruption(db);
+                            }
+                        }
+                    });
+            mCallback = callback;
+            mDbRef = dbRef;
+        }
+
+        SupportSQLiteDatabase getWritableSupportDatabase() {
+            SQLiteDatabase db = super.getWritableDatabase();
+            return getWrappedDb(db);
+        }
+
+        SupportSQLiteDatabase getReadableSupportDatabase() {
+            SQLiteDatabase db = super.getReadableDatabase();
+            return getWrappedDb(db);
+        }
+
+        FrameworkSQLiteDatabase getWrappedDb(SQLiteDatabase sqLiteDatabase) {
+            FrameworkSQLiteDatabase dbRef = mDbRef[0];
+            if (dbRef == null) {
+                dbRef = new FrameworkSQLiteDatabase(sqLiteDatabase);
+                mDbRef[0] = dbRef;
+            }
+            return mDbRef[0];
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase sqLiteDatabase) {
+            mCallback.onCreate(getWrappedDb(sqLiteDatabase));
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
+            mCallback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
+        }
+
+        @Override
+        public void onConfigure(SQLiteDatabase db) {
+            mCallback.onConfigure(getWrappedDb(db));
+        }
+
+        @Override
+        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            mCallback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            mCallback.onOpen(getWrappedDb(db));
+        }
+
+        @Override
+        public synchronized void close() {
+            super.close();
+            mDbRef[0] = null;
+        }
+    }
+}
diff --git a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory.java
similarity index 80%
rename from room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory.java
rename to persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory.java
index 7b4245b..ab11d49 100644
--- a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory.java
+++ b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory.java
@@ -23,12 +23,10 @@
  * framework.
  */
 @SuppressWarnings("unused")
-public class FrameworkSQLiteOpenHelperFactory implements SupportSQLiteOpenHelper.Factory {
+public final class FrameworkSQLiteOpenHelperFactory implements SupportSQLiteOpenHelper.Factory {
     @Override
     public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
         return new FrameworkSQLiteOpenHelper(
-                configuration.context, configuration.name,
-                configuration.version, configuration.errorHandler, configuration.callback
-        );
+                configuration.context, configuration.name, configuration.callback);
     }
 }
diff --git a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java
similarity index 100%
rename from room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java
rename to persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java
diff --git a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
similarity index 95%
rename from room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
rename to persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
index a2daf12..53a04bd 100644
--- a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
+++ b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
@@ -30,8 +30,7 @@
      *
      * @param delegate The SQLiteStatement to delegate calls to.
      */
-    @SuppressWarnings("WeakerAccess")
-    public FrameworkSQLiteStatement(SQLiteStatement delegate) {
+    FrameworkSQLiteStatement(SQLiteStatement delegate) {
         mDelegate = delegate;
     }
 
diff --git a/room/db/build.gradle b/persistence/db/build.gradle
similarity index 100%
rename from room/db/build.gradle
rename to persistence/db/build.gradle
diff --git a/room/db/src/main/AndroidManifest.xml b/persistence/db/src/main/AndroidManifest.xml
similarity index 100%
rename from room/db/src/main/AndroidManifest.xml
rename to persistence/db/src/main/AndroidManifest.xml
diff --git a/room/db/src/main/java/android/arch/persistence/db/SimpleSQLiteQuery.java b/persistence/db/src/main/java/android/arch/persistence/db/SimpleSQLiteQuery.java
similarity index 97%
rename from room/db/src/main/java/android/arch/persistence/db/SimpleSQLiteQuery.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SimpleSQLiteQuery.java
index b821176..e2a3829 100644
--- a/room/db/src/main/java/android/arch/persistence/db/SimpleSQLiteQuery.java
+++ b/persistence/db/src/main/java/android/arch/persistence/db/SimpleSQLiteQuery.java
@@ -20,7 +20,7 @@
  * A basic implemtation of {@link SupportSQLiteQuery} which receives a query and its args and binds
  * args based on the passed in Object type.
  */
-public class SimpleSQLiteQuery implements SupportSQLiteQuery {
+public final class SimpleSQLiteQuery implements SupportSQLiteQuery {
     private final String mQuery;
     private final Object[] mBindArgs;
 
diff --git a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteDatabase.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteDatabase.java
similarity index 100%
rename from room/db/src/main/java/android/arch/persistence/db/SupportSQLiteDatabase.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteDatabase.java
diff --git a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteOpenHelper.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteOpenHelper.java
similarity index 74%
rename from room/db/src/main/java/android/arch/persistence/db/SupportSQLiteOpenHelper.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteOpenHelper.java
index 5a96e5a..02e4e7d 100644
--- a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteOpenHelper.java
+++ b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteOpenHelper.java
@@ -17,13 +17,18 @@
 package android.arch.persistence.db;
 
 import android.content.Context;
-import android.database.DatabaseErrorHandler;
-import android.database.DefaultDatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
 
 /**
  * An interface to map the behavior of {@link android.database.sqlite.SQLiteOpenHelper}.
@@ -99,10 +104,29 @@
     void close();
 
     /**
-     * Matching callback methods from {@link android.database.sqlite.SQLiteOpenHelper}.
+     * Handles various lifecycle events for the SQLite connection, similar to
+     * {@link android.database.sqlite.SQLiteOpenHelper}.
      */
     @SuppressWarnings({"unused", "WeakerAccess"})
     abstract class Callback {
+        private static final String TAG = "SupportSQLite";
+        /**
+         * Version number of the database (starting at 1); if the database is older,
+         * {@link SupportSQLiteOpenHelper.Callback#onUpgrade(SupportSQLiteDatabase, int, int)}
+         * will be used to upgrade the database; if the database is newer,
+         * {@link SupportSQLiteOpenHelper.Callback#onDowngrade(SupportSQLiteDatabase, int, int)}
+         * will be used to downgrade the database.
+         */
+        public final int version;
+
+        /**
+         * Creates a new Callback to get database lifecycle events.
+         * @param version The version for the database instance. See {@link #version}.
+         */
+        public Callback(int version) {
+            this.version = version;
+        }
+
         /**
          * Called when the database connection is being configured, to enable features such as
          * write-ahead logging or foreign key support.
@@ -193,6 +217,81 @@
         public void onOpen(SupportSQLiteDatabase db) {
 
         }
+
+        /**
+         * The method invoked when database corruption is detected. Default implementation will
+         * delete the database file.
+         *
+         * @param db the {@link SupportSQLiteDatabase} object representing the database on which
+         *           corruption is detected.
+         */
+        public void onCorruption(SupportSQLiteDatabase db) {
+            // the following implementation is taken from {@link DefaultDatabaseErrorHandler}.
+
+            Log.e(TAG, "Corruption reported by sqlite on database: " + db.getPath());
+            // is the corruption detected even before database could be 'opened'?
+            if (!db.isOpen()) {
+                // database files are not even openable. delete this database file.
+                // NOTE if the database has attached databases, then any of them could be corrupt.
+                // and not deleting all of them could cause corrupted database file to remain and
+                // make the application crash on database open operation. To avoid this problem,
+                // the application should provide its own {@link DatabaseErrorHandler} impl class
+                // to delete ALL files of the database (including the attached databases).
+                deleteDatabaseFile(db.getPath());
+                return;
+            }
+
+            List<Pair<String, String>> attachedDbs = null;
+            try {
+                // Close the database, which will cause subsequent operations to fail.
+                // before that, get the attached database list first.
+                try {
+                    attachedDbs = db.getAttachedDbs();
+                } catch (SQLiteException e) {
+                /* ignore */
+                }
+                try {
+                    db.close();
+                } catch (IOException e) {
+                /* ignore */
+                }
+            } finally {
+                // Delete all files of this corrupt database and/or attached databases
+                if (attachedDbs != null) {
+                    for (Pair<String, String> p : attachedDbs) {
+                        deleteDatabaseFile(p.second);
+                    }
+                } else {
+                    // attachedDbs = null is possible when the database is so corrupt that even
+                    // "PRAGMA database_list;" also fails. delete the main database file
+                    deleteDatabaseFile(db.getPath());
+                }
+            }
+        }
+
+        private void deleteDatabaseFile(String fileName) {
+            if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
+                return;
+            }
+            Log.w(TAG, "deleting the database file: " + fileName);
+            try {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                    SQLiteDatabase.deleteDatabase(new File(fileName));
+                } else {
+                    try {
+                        final boolean deleted = new File(fileName).delete();
+                        if (!deleted) {
+                            Log.e(TAG, "Could not delete the database file " + fileName);
+                        }
+                    } catch (Exception error) {
+                        Log.e(TAG, "error while deleting corrupted database file", error);
+                    }
+                }
+            } catch (Exception e) {
+            /* print warning and ignore exception */
+                Log.w(TAG, "delete failed: ", e);
+            }
+        }
     }
 
     /**
@@ -211,33 +310,15 @@
         @Nullable
         public final String name;
         /**
-         * Version number of the database (starting at 1); if the database is older,
-         * {@link SupportSQLiteOpenHelper.Callback#onUpgrade(SupportSQLiteDatabase, int, int)}
-         * will be used to upgrade the database; if the database is newer,
-         * {@link SupportSQLiteOpenHelper.Callback#onDowngrade(SupportSQLiteDatabase, int, int)}
-         * will be used to downgrade the database.
-         */
-        public final int version;
-        /**
          * The callback class to handle creation, upgrade and downgrade.
          */
         @NonNull
         public final SupportSQLiteOpenHelper.Callback callback;
-        /**
-         * The {@link DatabaseErrorHandler} to be used when sqlite reports database
-         * corruption, or null to use the default error handler.
-         */
-        @Nullable
-        public final DatabaseErrorHandler errorHandler;
 
-        Configuration(@NonNull Context context, @Nullable String name,
-                int version, @Nullable DatabaseErrorHandler errorHandler,
-                @NonNull Callback callback) {
+        Configuration(@NonNull Context context, @Nullable String name, @NonNull Callback callback) {
             this.context = context;
             this.name = name;
-            this.version = version;
             this.callback = callback;
-            this.errorHandler = errorHandler;
         }
 
         /**
@@ -255,9 +336,7 @@
         public static class Builder {
             Context mContext;
             String mName;
-            int mVersion = 1;
             SupportSQLiteOpenHelper.Callback mCallback;
-            DatabaseErrorHandler mErrorHandler;
 
             public Configuration build() {
                 if (mCallback == null) {
@@ -268,11 +347,7 @@
                     throw new IllegalArgumentException("Must set a non-null context to create"
                             + " the configuration.");
                 }
-                if (mErrorHandler == null) {
-                    mErrorHandler = new DefaultDatabaseErrorHandler();
-                }
-                return new Configuration(mContext, mName, mVersion, mErrorHandler,
-                        mCallback);
+                return new Configuration(mContext, mName, mCallback);
             }
 
             Builder(@NonNull Context context) {
@@ -280,17 +355,6 @@
             }
 
             /**
-             * @param errorHandler The {@link DatabaseErrorHandler} to be used when sqlite
-             *                     reports database corruption, or null to use the default error
-             *                     handler.
-             * @return This
-             */
-            public Builder errorHandler(@Nullable DatabaseErrorHandler errorHandler) {
-                mErrorHandler = errorHandler;
-                return this;
-            }
-
-            /**
              * @param name Name of the database file, or null for an in-memory database.
              * @return This
              */
@@ -307,20 +371,6 @@
                 mCallback = callback;
                 return this;
             }
-
-            /**
-             * @param version Version number of the database (starting at 1); if the database is
-             * older,
-             * {@link SupportSQLiteOpenHelper.Callback#onUpgrade(SupportSQLiteDatabase, int, int)}
-             * will be used to upgrade the database; if the database is newer,
-             * {@link SupportSQLiteOpenHelper.Callback#onDowngrade(SupportSQLiteDatabase, int, int)}
-             * will be used to downgrade the database.
-             * @return this
-             */
-            public Builder version(int version) {
-                mVersion = version;
-                return this;
-            }
         }
     }
 
diff --git a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java
similarity index 100%
rename from room/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java
diff --git a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteQuery.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteQuery.java
similarity index 100%
rename from room/db/src/main/java/android/arch/persistence/db/SupportSQLiteQuery.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteQuery.java
diff --git a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteQueryBuilder.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteQueryBuilder.java
similarity index 98%
rename from room/db/src/main/java/android/arch/persistence/db/SupportSQLiteQueryBuilder.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteQueryBuilder.java
index 183fb0a..52957a3 100644
--- a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteQueryBuilder.java
+++ b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteQueryBuilder.java
@@ -22,7 +22,7 @@
  * A simple query builder to create SQL SELECT queries.
  */
 @SuppressWarnings("unused")
-public class SupportSQLiteQueryBuilder {
+public final class SupportSQLiteQueryBuilder {
     private static final Pattern sLimitPattern =
             Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
 
diff --git a/room/db/src/main/java/android/arch/persistence/db/SupportSQLiteStatement.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteStatement.java
similarity index 100%
rename from room/db/src/main/java/android/arch/persistence/db/SupportSQLiteStatement.java
rename to persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteStatement.java
diff --git a/room/common/src/main/java/android/arch/persistence/room/ColumnInfo.java b/room/common/src/main/java/android/arch/persistence/room/ColumnInfo.java
index 84f5844..65da379 100644
--- a/room/common/src/main/java/android/arch/persistence/room/ColumnInfo.java
+++ b/room/common/src/main/java/android/arch/persistence/room/ColumnInfo.java
@@ -33,6 +33,7 @@
 public @interface ColumnInfo {
     /**
      * Name of the column in the database. Defaults to the field name if not set.
+     *
      * @return Name of the column in the database.
      */
     String name() default INHERIT_FIELD_NAME;
@@ -40,13 +41,14 @@
     /**
      * The type affinity for the column, which will be used when constructing the database.
      * <p>
-     * If it is not specified, Room resolves it based on the field's type and available
-     * TypeConverters.
+     * If it is not specified, the value defaults to {@link #UNDEFINED} and Room resolves it based
+     * on the field's type and available TypeConverters.
      * <p>
      * See <a href="https://www.sqlite.org/datatype3.html">SQLite types documentation</a> for
      * details.
      *
-     * @return The type affinity of the column.
+     * @return The type affinity of the column. This is either {@link #UNDEFINED}, {@link #TEXT},
+     * {@link #INTEGER}, {@link #REAL}, or {@link #BLOB}.
      */
     @SuppressWarnings("unused") @SQLiteTypeAffinity int typeAffinity() default UNDEFINED;
 
@@ -60,6 +62,17 @@
     boolean index() default false;
 
     /**
+     * The collation sequence for the column, which will be used when constructing the database.
+     * <p>
+     * The default value is {@link #UNSPECIFIED}. In that case, Room does not add any
+     * collation sequence to the column, and SQLite treats it like {@link #BINARY}.
+     *
+     * @return The collation sequence of the column. This is either {@link #UNSPECIFIED},
+     * {@link #BINARY}, {@link #NOCASE}, or {@link #RTRIM}.
+     */
+    @Collate int collate() default UNSPECIFIED;
+
+    /**
      * Constant to let Room inherit the field name as the column name. If used, Room will use the
      * field name as the column name.
      */
@@ -67,22 +80,32 @@
 
     /**
      * Undefined type affinity. Will be resolved based on the type.
+     *
+     * @see #typeAffinity()
      */
     int UNDEFINED = 1;
     /**
      * Column affinity constant for strings.
+     *
+     * @see #typeAffinity()
      */
     int TEXT = 2;
     /**
      * Column affinity constant for integers or booleans.
+     *
+     * @see #typeAffinity()
      */
     int INTEGER = 3;
     /**
      * Column affinity constant for floats or doubles.
+     *
+     * @see #typeAffinity()
      */
     int REAL = 4;
     /**
      * Column affinity constant for binary data.
+     *
+     * @see #typeAffinity()
      */
     int BLOB = 5;
 
@@ -92,4 +115,34 @@
     @IntDef({UNDEFINED, TEXT, INTEGER, REAL, BLOB})
     @interface SQLiteTypeAffinity {
     }
+
+    /**
+     * Collation sequence is not specified. The match will behave like {@link #BINARY}.
+     *
+     * @see #collate()
+     */
+    int UNSPECIFIED = 1;
+    /**
+     * Collation sequence for case-sensitive match.
+     *
+     * @see #collate()
+     */
+    int BINARY = 2;
+    /**
+     * Collation sequence for case-insensitive match.
+     *
+     * @see #collate()
+     */
+    int NOCASE = 3;
+    /**
+     * Collation sequence for case-sensitive match except that trailing space characters are
+     * ignored.
+     *
+     * @see #collate()
+     */
+    int RTRIM = 4;
+
+    @IntDef({UNSPECIFIED, BINARY, NOCASE, RTRIM})
+    @interface Collate {
+    }
 }
diff --git a/room/common/src/main/java/android/arch/persistence/room/Entity.java b/room/common/src/main/java/android/arch/persistence/room/Entity.java
index f54f0f8..94ca3bf 100644
--- a/room/common/src/main/java/android/arch/persistence/room/Entity.java
+++ b/room/common/src/main/java/android/arch/persistence/room/Entity.java
@@ -36,6 +36,9 @@
  * When a class is marked as an Entity, all of its fields are persisted. If you would like to
  * exclude some of its fields, you can mark them with {@link Ignore}.
  * <p>
+ * If a field is {@code transient}, it is automatically ignored <b>unless</b> it is annotated with
+ * {@link ColumnInfo}, {@link Embedded} or {@link Relation}.
+ * <p>
  * Example:
  * <pre>
  * {@literal @}Entity
diff --git a/room/common/src/main/java/android/arch/persistence/room/Relation.java b/room/common/src/main/java/android/arch/persistence/room/Relation.java
index 0d2f152..7206699 100644
--- a/room/common/src/main/java/android/arch/persistence/room/Relation.java
+++ b/room/common/src/main/java/android/arch/persistence/room/Relation.java
@@ -41,7 +41,7 @@
  *
  * {@literal @}Dao
  * public interface UserPetDao {
- *     {@literal @}Query("SELECT id, name from User WHERE age &gte; ?")
+ *     {@literal @}Query("SELECT id, name from User WHERE age &gt; :minAge")
  *     public List&lt;UserNameAndAllPets&gt; loadUserAndPets(int minAge);
  * }
  * </pre>
@@ -67,7 +67,7 @@
  * }
  * {@literal @}Dao
  * public interface UserPetDao {
- *     {@literal @}Query("SELECT * from User WHERE age &gte; ?")
+ *     {@literal @}Query("SELECT * from User WHERE age &gt; :minAge")
  *     public List&lt;UserAllPets&gt; loadUserAndPets(int minAge);
  * }
  * </pre>
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index 8934f88..222a338 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -1,5 +1,3 @@
-import android.support.LibraryVersions
-
 /*
  * Copyright (C) 2016 The Android Open Source Project
  *
@@ -15,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import android.support.LibraryVersions
+import android.support.SupportLibraryExtension
 
-apply plugin: 'kotlin'
-apply plugin: 'maven'
+apply plugin: android.support.SupportKotlinLibraryPlugin
 
 def antlrOut = "$buildDir/generated/antlr/grammar-gen/"
 sourceSets {
@@ -57,7 +56,7 @@
             include : "android.jar")
     testCompile fileTree(dir: "${new File(project(":room:runtime").buildDir, "libJar")}",
             include : "*.jar")
-    testCompile fileTree(dir: "${new File(project(":room:db").buildDir, "libJar")}",
+    testCompile fileTree(dir: "${new File(project(":persistence:db").buildDir, "libJar")}",
             include : "*.jar")
     testCompile files(org.gradle.internal.jvm.Jvm.current().getToolsJar())
 }
@@ -74,7 +73,14 @@
 
 tasks.findByName("compileKotlin").dependsOn(generateAntlrTask)
 tasks.findByName("compileKotlin").dependsOn(":room:runtime:jarDebug")
-tasks.findByName("compileKotlin").dependsOn(":room:db:jarDebug")
+tasks.findByName("compileKotlin").dependsOn(":persistence:db:jarDebug")
 
 createKotlinCheckstyle(project)
 
+supportLibrary {
+    name 'Android Room Compiler'
+    publish true
+    inceptionYear '2017'
+    description "Android Room annotation processor"
+    url SupportLibraryExtension.ARCHITECTURE_URL
+}
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 09b6221..a74031d 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
@@ -47,13 +47,6 @@
                 || hasAnnotation(org.jetbrains.annotations.NotNull::class)
 
 /**
- * Checks if it has all of the annotations
- */
-fun Element.hasAllOf(vararg klasses: KClass<out Annotation>): Boolean {
-    return !klasses.any { !hasAnnotation(it) }
-}
-
-/**
  * gets all members including super privates. does not handle duplicate field names!!!
  */
 // TODO handle conflicts with super: b/35568142
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
index b71ba10..a4e8946 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
@@ -210,3 +210,20 @@
         }
     }
 }
+
+enum class Collate {
+    BINARY,
+    NOCASE,
+    RTRIM;
+
+    companion object {
+        fun fromAnnotationValue(value: Int): Collate? {
+            return when (value) {
+                ColumnInfo.BINARY -> BINARY
+                ColumnInfo.NOCASE -> NOCASE
+                ColumnInfo.RTRIM -> RTRIM
+                else -> null
+            }
+        }
+    }
+}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt
index 2d11588..8677bf6 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt
@@ -20,6 +20,7 @@
 import android.arch.persistence.room.ext.getAsBoolean
 import android.arch.persistence.room.ext.getAsInt
 import android.arch.persistence.room.ext.getAsString
+import android.arch.persistence.room.parser.Collate
 import android.arch.persistence.room.parser.SQLTypeAffinity
 import android.arch.persistence.room.vo.EmbeddedField
 import android.arch.persistence.room.vo.Field
@@ -42,6 +43,7 @@
         val name = element.simpleName.toString()
         val columnName: String
         val affinity : SQLTypeAffinity?
+        val collate: Collate?
         val fieldPrefix = fieldParent?.prefix ?: ""
         val indexed : Boolean
         if (columnInfoAnnotation.isPresent) {
@@ -63,6 +65,9 @@
                 null
             }
 
+            collate = Collate.fromAnnotationValue(AnnotationMirrors.getAnnotationValue(
+                    columnInfoAnnotation.get(), "collate").getAsInt(ColumnInfo.UNSPECIFIED)!!)
+
             indexed = AnnotationMirrors
                     .getAnnotationValue(columnInfoAnnotation.get(), "index")
                     .getAsBoolean(false)
@@ -70,6 +75,7 @@
         } else {
             columnName = fieldPrefix + name
             affinity = null
+            collate = null
             indexed = false
         }
         context.checker.notBlank(columnName, element,
@@ -82,6 +88,7 @@
                 element = element,
                 columnName = columnName,
                 affinity = affinity,
+                collate = collate,
                 parent = fieldParent,
                 indexed = indexed)
 
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 baa351d..e83d1ef 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
@@ -52,6 +52,7 @@
 import javax.lang.model.element.Modifier.PROTECTED
 import javax.lang.model.element.Modifier.PUBLIC
 import javax.lang.model.element.Modifier.STATIC
+import javax.lang.model.element.Modifier.TRANSIENT
 import javax.lang.model.element.TypeElement
 import javax.lang.model.element.VariableElement
 import javax.lang.model.type.DeclaredType
@@ -82,7 +83,12 @@
         // TODO handle conflicts with super: b/35568142
         val allFields = element.getAllFieldsIncludingPrivateSupers(context.processingEnv)
                 .filter {
-                    !it.hasAnnotation(Ignore::class) && !it.hasAnyOf(Modifier.STATIC)
+                    !it.hasAnnotation(Ignore::class)
+                            && !it.hasAnyOf(STATIC)
+                            && (!it.hasAnyOf(TRANSIENT)
+                                    || it.hasAnnotation(ColumnInfo::class)
+                                    || it.hasAnnotation(Embedded::class)
+                                    || it.hasAnnotation(Relation::class))
                 }
                 .groupBy { field ->
                     context.checker.check(
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt
index ee6f8a1..fa0575a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt
@@ -19,6 +19,7 @@
 import android.arch.persistence.room.ext.isNonNull
 import android.arch.persistence.room.ext.typeName
 import android.arch.persistence.room.migration.bundle.FieldBundle
+import android.arch.persistence.room.parser.Collate
 import android.arch.persistence.room.parser.SQLTypeAffinity
 import android.arch.persistence.room.solver.types.CursorValueReader
 import android.arch.persistence.room.solver.types.StatementValueBinder
@@ -28,6 +29,7 @@
 // used in cache matching, must stay as a data class or implement equals
 data class Field(val element: Element, val name: String, val type: TypeMirror,
                  var affinity: SQLTypeAffinity?,
+                 val collate: Collate? = null,
                  val columnName: String = name,
                  /* means that this field does not belong to parent, instead, it belongs to a
                  * embedded child of the main Pojo*/
@@ -117,6 +119,9 @@
         if (nonNull) {
             columnSpec.append(" NOT NULL")
         }
+        if (collate != null) {
+            columnSpec.append(" COLLATE ${collate.name}")
+        }
         return "`$columnName` ${(affinity ?: SQLTypeAffinity.TEXT).name}$columnSpec"
     }
 
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt
index 2bf471a..a2c7e62 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt
@@ -72,7 +72,7 @@
                 query.sections.forEach {
                     when (it.type) {
                         TEXT -> addStatement("$L.append($S)", stringBuilderVar, it.text)
-                        NEWLINE -> addStatement("$L.append($S)", "\n")
+                        NEWLINE -> addStatement("$L.append($S)", stringBuilderVar, "\n")
                         BIND_VAR -> {
                             // If it is null, will be reported as error before. We just try out
                             // best to generate as much code as possible.
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt
index afb12e9..bdc601f 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt
@@ -49,13 +49,12 @@
                     """
                     final $T $L = $T.builder($N.context)
                     .name($N.name)
-                    .version($L)
                     .callback($L)
                     .build()
                     """.trimIndent(),
                     SupportDbTypeNames.SQLITE_OPEN_HELPER_CONFIG, sqliteConfigVar,
                     SupportDbTypeNames.SQLITE_OPEN_HELPER_CONFIG,
-                    configuration, configuration, database.version, callbackVar)
+                    configuration, configuration, callbackVar)
             addStatement("final $T $N = $N.sqliteOpenHelperFactory.create($L)",
                     SupportDbTypeNames.SQLITE_OPEN_HELPER, outVar,
                     configuration, sqliteConfigVar)
@@ -63,7 +62,7 @@
     }
 
     private fun createOpenCallback(scope: CodeGenScope) : TypeSpec {
-        return TypeSpec.anonymousClassBuilder("").apply {
+        return TypeSpec.anonymousClassBuilder(L, database.version).apply {
             superclass(RoomTypeNames.OPEN_HELPER_DELEGATE)
             addMethod(createCreateAllTables())
             addMethod(createDropAllTables())
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index 39d4d42..80d73a9 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -23,7 +23,7 @@
     private volatile ComplexDao _complexDao;
 
     protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
-        final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate() {
+        final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1923) {
             public void createAllTables(SupportSQLiteDatabase _db) {
                 _db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`uid` INTEGER NOT NULL, `name` TEXT, `lastName` TEXT, `ageColumn` INTEGER NOT NULL, PRIMARY KEY(`uid`))");
                 _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
@@ -70,7 +70,6 @@
         }, "6773601c5bcf94c71ee4eb0de04f21a4");
         final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
                 .name(configuration.name)
-                .version(1923)
                 .callback(_openCallback)
                 .build();
         final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/FieldProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/FieldProcessorTest.kt
index 5498340..ef0170c 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/FieldProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/FieldProcessorTest.kt
@@ -17,6 +17,7 @@
 package android.arch.persistence.room.processor
 
 import android.arch.persistence.room.Entity
+import android.arch.persistence.room.parser.Collate
 import android.arch.persistence.room.parser.SQLTypeAffinity
 import android.arch.persistence.room.solver.types.ColumnTypeAdapter
 import android.arch.persistence.room.testing.TestInvocation
@@ -330,6 +331,25 @@
         }
     }
 
+    @Test
+    fun collate() {
+        Collate.values().forEach { collate ->
+            singleEntity("""
+            @PrimaryKey
+            @ColumnInfo(collate = ColumnInfo.${collate.name})
+            String code;
+            """) { field, invocation ->
+                assertThat(field, `is`(
+                        Field(name = "code",
+                                type = invocation.context.COMMON_TYPES.STRING,
+                                element = field.element,
+                                columnName = "code",
+                                collate = collate,
+                                affinity = SQLTypeAffinity.TEXT)))
+            }.compilesWithoutError()
+        }
+    }
+
     fun singleEntity(vararg input: String, handler: (Field, invocation: TestInvocation) -> Unit):
             CompileTester {
         return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
index faa6024..3ada5f6 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
@@ -18,6 +18,7 @@
 
 import COMMON
 import android.arch.persistence.room.parser.SQLTypeAffinity
+import android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD
 import android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_TYPE
 import android.arch.persistence.room.processor.ProcessorErrors.ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY
 import android.arch.persistence.room.processor.ProcessorErrors.POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME
@@ -100,6 +101,72 @@
     }
 
     @Test
+    fun transient_ignore() {
+        singleRun("""
+            transient int foo;
+            int bar;
+        """) { pojo ->
+            assertThat(pojo.fields.size, `is`(1))
+            assertThat(pojo.fields[0].name, `is`("bar"))
+        }.compilesWithoutError()
+    }
+
+    @Test
+    fun transient_withColumnInfo() {
+        singleRun("""
+            @ColumnInfo
+            transient int foo;
+            int bar;
+        """) { pojo ->
+            assertThat(pojo.fields.map { it.name }.toSet(), `is`(setOf("bar", "foo")))
+        }.compilesWithoutError()
+    }
+
+    @Test
+    fun transient_embedded() {
+        singleRun("""
+            @Embedded
+            transient Foo foo;
+            int bar;
+            static class Foo {
+                int x;
+            }
+        """) { pojo ->
+            assertThat(pojo.fields.map { it.name }.toSet(), `is`(setOf("x", "bar")))
+        }.compilesWithoutError()
+    }
+
+    @Test
+    fun transient_insideEmbedded() {
+        singleRun("""
+            @Embedded
+            Foo foo;
+            int bar;
+            static class Foo {
+                transient int x;
+                int y;
+            }
+        """) { pojo ->
+            assertThat(pojo.fields.map { it.name }.toSet(), `is`(setOf("bar", "y")))
+        }.compilesWithoutError()
+    }
+
+    @Test
+    fun transient_relation() {
+        singleRun(
+                """
+                int id;
+                @Relation(parentColumn = "id", entityColumn = "uid")
+                public transient List<User> user;
+                """, COMMON.USER
+        ) { pojo ->
+            assertThat(pojo.relations.size, `is`(1))
+            assertThat(pojo.relations.first().entityField.name, `is`("uid"))
+            assertThat(pojo.relations.first().parentField.name, `is`("id"))
+        }.compilesWithoutError().withWarningCount(0)
+    }
+
+    @Test
     fun embedded() {
         singleRun(
                 """
@@ -402,6 +469,20 @@
     }
 
     @Test
+    fun relation_badReturnTypeInGetter() {
+        singleRun(
+                """
+                int id;
+                @Relation(parentColumn = "id", entityColumn = "uid")
+                private List<User> user;
+                public void setUser(List<User> user){ this.user = user;}
+                public User getUser(){return null;}
+                """, COMMON.USER
+        ) { _ ->
+        }.failsToCompile().withErrorContaining(CANNOT_FIND_GETTER_FOR_FIELD)
+    }
+
+    @Test
     fun cache() {
         val pojo = """
             $HEADER
diff --git a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper.java b/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper.java
deleted file mode 100644
index aa08fa4..0000000
--- a/room/db-impl/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2016 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.db.framework;
-
-import android.arch.persistence.db.SupportSQLiteDatabase;
-import android.arch.persistence.db.SupportSQLiteOpenHelper;
-import android.content.Context;
-import android.database.DatabaseErrorHandler;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.os.Build;
-import android.support.annotation.RequiresApi;
-
-class FrameworkSQLiteOpenHelper implements SupportSQLiteOpenHelper {
-    private final OpenHelper mDelegate;
-
-    FrameworkSQLiteOpenHelper(Context context, String name, int version,
-            DatabaseErrorHandler errorHandler,
-            SupportSQLiteOpenHelper.Callback callback) {
-        mDelegate = createDelegate(context, name, version, errorHandler, callback);
-    }
-
-    private OpenHelper createDelegate(Context context, String name,
-            int version, DatabaseErrorHandler errorHandler,
-            final Callback callback) {
-        return new OpenHelper(context, name, null, version, errorHandler) {
-            @Override
-            public void onCreate(SQLiteDatabase sqLiteDatabase) {
-                mWrappedDb = new FrameworkSQLiteDatabase(sqLiteDatabase);
-                callback.onCreate(mWrappedDb);
-            }
-
-            @Override
-            public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
-                callback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
-            }
-
-            @Override
-            public void onConfigure(SQLiteDatabase db) {
-                callback.onConfigure(getWrappedDb(db));
-            }
-
-            @Override
-            public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-                callback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
-            }
-
-            @Override
-            public void onOpen(SQLiteDatabase db) {
-                callback.onOpen(getWrappedDb(db));
-            }
-        };
-    }
-
-    @Override
-    public String getDatabaseName() {
-        return mDelegate.getDatabaseName();
-    }
-
-    @Override
-    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
-    public void setWriteAheadLoggingEnabled(boolean enabled) {
-        mDelegate.setWriteAheadLoggingEnabled(enabled);
-    }
-
-    @Override
-    public SupportSQLiteDatabase getWritableDatabase() {
-        return mDelegate.getWritableSupportDatabase();
-    }
-
-    @Override
-    public SupportSQLiteDatabase getReadableDatabase() {
-        return mDelegate.getReadableSupportDatabase();
-    }
-
-    @Override
-    public void close() {
-        mDelegate.close();
-    }
-
-    abstract static class OpenHelper extends SQLiteOpenHelper {
-
-        FrameworkSQLiteDatabase mWrappedDb;
-
-        OpenHelper(Context context, String name,
-                SQLiteDatabase.CursorFactory factory, int version,
-                DatabaseErrorHandler errorHandler) {
-            super(context, name, factory, version, errorHandler);
-        }
-
-        SupportSQLiteDatabase getWritableSupportDatabase() {
-            SQLiteDatabase db = super.getWritableDatabase();
-            return getWrappedDb(db);
-        }
-
-        SupportSQLiteDatabase getReadableSupportDatabase() {
-            SQLiteDatabase db = super.getReadableDatabase();
-            return getWrappedDb(db);
-        }
-
-        FrameworkSQLiteDatabase getWrappedDb(SQLiteDatabase sqLiteDatabase) {
-            if (mWrappedDb == null) {
-                mWrappedDb = new FrameworkSQLiteDatabase(sqLiteDatabase);
-            }
-            return mWrappedDb;
-        }
-
-        @Override
-        public synchronized void close() {
-            super.close();
-            mWrappedDb = null;
-        }
-    }
-}
diff --git a/room/integration-tests/kotlintestapp/build.gradle b/room/integration-tests/kotlintestapp/build.gradle
index 0d70666..f4df9cf 100644
--- a/room/integration-tests/kotlintestapp/build.gradle
+++ b/room/integration-tests/kotlintestapp/build.gradle
@@ -50,12 +50,12 @@
 
 dependencies {
     implementation project(":room:common")
-    implementation project(":room:db")
-    implementation project(":room:db-impl")
+    implementation project(":persistence:db")
+    implementation project(":persistence:db-framework")
     implementation project(':room:runtime')
     implementation project(':arch:runtime')
 
-    implementation libs.support.app_compat
+    implementation libs.support.app_compat, libs.support_exclude_config
     kapt project(":room:compiler")
     kaptAndroidTest project(":room:compiler")
 
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
new file mode 100644
index 0000000..6425de7
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
@@ -0,0 +1,171 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 1,
+    "identityHash": "7beb328c9cd44a7782dfaa18c30ecb83",
+    "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)",
+        "fields": [
+          {
+            "fieldPath": "bookId",
+            "columnName": "bookId",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "title",
+            "columnName": "title",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "bookPublisherId",
+            "columnName": "bookPublisherId",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "bookId"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": [
+          {
+            "table": "Publisher",
+            "onDelete": "NO ACTION",
+            "onUpdate": "NO ACTION",
+            "columns": [
+              "bookPublisherId"
+            ],
+            "referencedColumns": [
+              "publisherId"
+            ]
+          }
+        ]
+      },
+      {
+        "tableName": "Author",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`authorId` TEXT NOT NULL, `name` TEXT NOT NULL, `dateOfBirth` INTEGER, `aList` TEXT, PRIMARY KEY(`authorId`))",
+        "fields": [
+          {
+            "fieldPath": "authorId",
+            "columnName": "authorId",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "dateOfBirth",
+            "columnName": "dateOfBirth",
+            "affinity": "INTEGER",
+            "notNull": false
+          },
+          {
+            "fieldPath": "aList",
+            "columnName": "aList",
+            "affinity": "TEXT",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "authorId"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Publisher",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`publisherId` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`publisherId`))",
+        "fields": [
+          {
+            "fieldPath": "publisherId",
+            "columnName": "publisherId",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "publisherId"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "BookAuthor",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bookId` TEXT NOT NULL, `authorId` TEXT NOT NULL, PRIMARY KEY(`bookId`, `authorId`), FOREIGN KEY(`bookId`) REFERENCES `Book`(`bookId`) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY(`authorId`) REFERENCES `Author`(`authorId`) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)",
+        "fields": [
+          {
+            "fieldPath": "bookId",
+            "columnName": "bookId",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "authorId",
+            "columnName": "authorId",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "bookId",
+            "authorId"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": [
+          {
+            "table": "Book",
+            "onDelete": "CASCADE",
+            "onUpdate": "CASCADE",
+            "columns": [
+              "bookId"
+            ],
+            "referencedColumns": [
+              "bookId"
+            ]
+          },
+          {
+            "table": "Author",
+            "onDelete": "CASCADE",
+            "onUpdate": "CASCADE",
+            "columns": [
+              "authorId"
+            ],
+            "referencedColumns": [
+              "authorId"
+            ]
+          }
+        ]
+      }
+    ],
+    "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, \"7beb328c9cd44a7782dfaa18c30ecb83\")"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/BooksDatabase.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt
similarity index 83%
rename from room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/BooksDatabase.kt
rename to room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt
index b5b6f26..b9344af 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/BooksDatabase.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt
@@ -18,6 +18,8 @@
 
 import android.arch.persistence.room.Database
 import android.arch.persistence.room.RoomDatabase
+import android.arch.persistence.room.integration.kotlintestapp.dao.BooksDao
+import android.arch.persistence.room.integration.kotlintestapp.dao.DerivedDao
 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
@@ -25,8 +27,9 @@
 
 @Database(entities = arrayOf(Book::class, Author::class, Publisher::class, BookAuthor::class),
         version = 1)
-abstract class BooksDatabase : RoomDatabase() {
+abstract class TestDatabase : RoomDatabase() {
 
     abstract fun booksDao(): BooksDao
 
+    abstract fun derivedDao(): DerivedDao
 }
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BaseDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BaseDao.kt
new file mode 100644
index 0000000..60d97ed
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BaseDao.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.arch.persistence.room.integration.kotlintestapp.dao
+
+import android.arch.persistence.room.Delete
+import android.arch.persistence.room.Insert
+import android.arch.persistence.room.OnConflictStrategy
+import android.arch.persistence.room.Update
+
+interface BaseDao<T> {
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insert(t: T)
+
+    @Update
+    fun update(t: T)
+
+    @Delete
+    fun delete(t: T)
+}
\ No newline at end of file
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/BooksDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
similarity index 79%
rename from room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/BooksDao.kt
rename to room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
index 6f4f91e..20e9d18 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/BooksDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
@@ -14,13 +14,18 @@
  * limitations under the License.
  */
 
-package android.arch.persistence.room.integration.kotlintestapp
+package android.arch.persistence.room.integration.kotlintestapp.dao
 
 import android.arch.lifecycle.LiveData
 import android.arch.persistence.room.Dao
 import android.arch.persistence.room.Insert
 import android.arch.persistence.room.Query
-import android.arch.persistence.room.integration.kotlintestapp.vo.*
+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.Publisher
+import android.arch.persistence.room.integration.kotlintestapp.vo.PublisherWithBooks
 import io.reactivex.Flowable
 import io.reactivex.Maybe
 import io.reactivex.Single
@@ -34,6 +39,9 @@
     @Insert
     fun addAuthors(vararg authors: Author)
 
+    @Query("SELECT * FROM author WHERE authorId = :authorId")
+    fun getAuthor(authorId: String): Author
+
     @Insert
     fun addBooks(vararg books: Book)
 
@@ -43,6 +51,11 @@
     @Query("SELECT * FROM book WHERE bookId = :bookId")
     fun getBook(bookId: String): Book
 
+    @Query("""SELECT * FROM book WHERE
+            bookId IN(:bookIds)
+            order by bookId DESC""")
+    fun getBooksMultiLineQuery(bookIds: List<String>): List<Book>
+
     @Query("SELECT * FROM book WHERE bookId = :bookId")
     fun getBookLiveData(bookId: String): LiveData<Book>
 
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt
new file mode 100644
index 0000000..01e8167
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.arch.persistence.room.integration.kotlintestapp.dao
+
+import android.arch.persistence.room.Dao
+import android.arch.persistence.room.Query
+import android.arch.persistence.room.integration.kotlintestapp.vo.Author
+
+
+@Dao
+interface DerivedDao : BaseDao<Author> {
+
+    @Query("SELECT * FROM author WHERE authorId = :authorId")
+    fun getAuthor(authorId: String): Author
+}
\ No newline at end of file
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 b918731..7985c77 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
@@ -16,15 +16,19 @@
 
 package android.arch.persistence.room.integration.kotlintestapp.test
 
+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.Publisher
 import android.database.sqlite.SQLiteConstraintException
+import org.hamcrest.CoreMatchers
 import org.hamcrest.CoreMatchers.`is`
 import org.hamcrest.CoreMatchers.instanceOf
 import org.hamcrest.MatcherAssert.assertThat
 import org.junit.Assert.assertNotNull
 import org.junit.Test
+import java.util.Date
+import kotlin.collections.ArrayList
 
 class BooksDaoTest : TestDatabaseTest() {
 
@@ -82,4 +86,35 @@
         assertThat(actualPublisherWithBooks.books?.get(0), `is`<Book>(TestUtil.BOOK_1))
         assertThat(actualPublisherWithBooks.books?.get(1), `is`<Book>(TestUtil.BOOK_2))
     }
+
+    @Test
+    fun insertAuthorWithAllFields() {
+        val author = Author("id", "name", Date(), ArrayList())
+        database.booksDao().addAuthors(author)
+
+        val authorDb = database.booksDao().getAuthor(author.authorId)
+
+        assertThat(authorDb, CoreMatchers.`is`<Author>(author))
+    }
+
+    @Test
+    fun insertInInheritedDao() {
+        database.derivedDao().insert(TestUtil.AUTHOR_1)
+
+        val author = database.derivedDao().getAuthor(TestUtil.AUTHOR_1.authorId)
+
+        assertThat(author, CoreMatchers.`is`<Author>(TestUtil.AUTHOR_1))
+    }
+
+    @Test
+    fun findBooksInMultiLineQuery() {
+        booksDao.addPublishers(TestUtil.PUBLISHER)
+        booksDao.addBooks(TestUtil.BOOK_1)
+        booksDao.addBooks(TestUtil.BOOK_2)
+
+        val books = database.booksDao().getBooksMultiLineQuery(arrayListOf(
+                TestUtil.BOOK_1.bookId,
+                TestUtil.BOOK_2.bookId))
+        assertThat(books, `is`(listOf(TestUtil.BOOK_2, TestUtil.BOOK_1)))
+    }
 }
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestDatabaseTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestDatabaseTest.kt
index 42815b2..520c4d3 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestDatabaseTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/TestDatabaseTest.kt
@@ -18,8 +18,8 @@
 
 import android.arch.core.executor.testing.InstantTaskExecutorRule
 import android.arch.persistence.room.Room
-import android.arch.persistence.room.integration.kotlintestapp.BooksDao
-import android.arch.persistence.room.integration.kotlintestapp.BooksDatabase
+import android.arch.persistence.room.integration.kotlintestapp.dao.BooksDao
+import android.arch.persistence.room.integration.kotlintestapp.TestDatabase
 import android.support.test.InstrumentationRegistry
 import org.junit.After
 import org.junit.Before
@@ -30,14 +30,14 @@
     @get:Rule
     var instantTaskExecutorRule = InstantTaskExecutorRule()
 
-    protected lateinit var database: BooksDatabase
+    protected lateinit var database: TestDatabase
     protected lateinit var booksDao: BooksDao
 
     @Before
     @Throws(Exception::class)
     fun setUp() {
         database = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(),
-                BooksDatabase::class.java)
+                TestDatabase::class.java)
                 // allowing main thread queries, just for testing
                 .allowMainThreadQueries()
                 .build()
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Author.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Author.kt
index a51c256..067fcb3 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Author.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/Author.kt
@@ -18,6 +18,13 @@
 
 import android.arch.persistence.room.Entity
 import android.arch.persistence.room.PrimaryKey
+import android.arch.persistence.room.TypeConverters
+import java.util.Date
 
 @Entity
-data class Author(@PrimaryKey val authorId: String, val name: String)
+@TypeConverters(DateConverter::class, StringToIntListConverters::class)
+data class Author(
+        @PrimaryKey val authorId: String,
+        val name: String,
+        val dateOfBirth: Date? = null,
+        val aList: List<Integer>? = null)
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/DateConverter.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/DateConverter.kt
new file mode 100755
index 0000000..62a3c21
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/DateConverter.kt
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+import java.util.Date
+
+class DateConverter {
+    @TypeConverter
+    fun toDate(timestamp: Long?): Date? {
+        return if (timestamp == null) null else Date(timestamp)
+    }
+
+    @TypeConverter
+    fun toTimestamp(date: Date?): Long? {
+        return date?.time
+    }
+}
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/StringToIntListConverters.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/StringToIntListConverters.kt
new file mode 100644
index 0000000..5c6620d
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/StringToIntListConverters.kt
@@ -0,0 +1,16 @@
+package android.arch.persistence.room.integration.kotlintestapp.vo
+
+import android.arch.persistence.room.TypeConverter
+import android.arch.persistence.room.util.StringUtil
+
+object StringToIntListConverters {
+    @TypeConverter
+    // Specifying that a static method should be generated. Otherwise, the compiler looks for the
+    // constructor of the class, and a object has a private constructor.
+    @JvmStatic
+    fun stringToIntList(data: String?): List<Int>? = if (data == null) null else StringUtil.splitToIntList(data)
+
+    @TypeConverter
+    @JvmStatic
+    fun intListToString(ints: List<Int>?): String? = if (ints == null) null else StringUtil.joinIntoString(ints)
+}
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 361c33a..6fefc29 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -48,8 +48,8 @@
 
 dependencies {
     compile project(":room:common")
-    compile project(":room:db")
-    compile project(":room:db-impl")
+    compile project(":persistence:db")
+    compile project(":persistence:db-framework")
     compile project(':room:runtime')
     compile project(':arch:runtime')
     compile project(':arch:common')
@@ -60,8 +60,8 @@
     compile project(':room:rxjava2')
     compile project(':paging:runtime')
 
-    compile libs.support.recyclerview
-    compile libs.support.app_compat
+    compile libs.support.recyclerview, libs.support_exclude_config
+    compile libs.support.app_compat, libs.support_exclude_config
     annotationProcessor project(":room:compiler")
     androidTestAnnotationProcessor project(":room:compiler")
 
@@ -79,6 +79,9 @@
     androidTestCompile(libs.espresso_core, {
         exclude group: 'com.android.support', module: 'support-annotations'
     })
+    androidTestImplementation libs.mockito_core,     { exclude group: 'net.bytebuddy' } // DexMaker has it's own MockMaker
+    androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it's own MockMaker
+
     testCompile libs.junit
 }
 
diff --git a/room/integration-tests/testapp/schemas/android.arch.persistence.room.integration.testapp.migration.MigrationDb/7.json b/room/integration-tests/testapp/schemas/android.arch.persistence.room.integration.testapp.migration.MigrationDb/7.json
index 93a9682..c8118b6 100644
--- a/room/integration-tests/testapp/schemas/android.arch.persistence.room.integration.testapp.migration.MigrationDb/7.json
+++ b/room/integration-tests/testapp/schemas/android.arch.persistence.room.integration.testapp.migration.MigrationDb/7.json
@@ -2,7 +2,7 @@
   "formatVersion": 1,
   "database": {
     "version": 7,
-    "identityHash": "03ff272b825e27b5c15545c85fe1b845",
+    "identityHash": "dbb4fd91128a81c867a779f0b5d304ff",
     "entities": [
       {
         "tableName": "Entity1",
@@ -73,7 +73,7 @@
       },
       {
         "tableName": "Entity4",
-        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`name`) REFERENCES `Entity1`(`name`) ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT COLLATE NOCASE, PRIMARY KEY(`id`), FOREIGN KEY(`name`) REFERENCES `Entity1`(`name`) ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)",
         "fields": [
           {
             "fieldPath": "id",
@@ -112,7 +112,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, \"03ff272b825e27b5c15545c85fe1b845\")"
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"dbb4fd91128a81c867a779f0b5d304ff\")"
     ]
   }
 }
\ No newline at end of file
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 428d87c..337c233 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
@@ -59,6 +59,9 @@
     @Query("select * from user where mId IN(:ids)")
     public abstract User[] loadByIds(int... ids);
 
+    @Query("select * from user where custommm = :customField")
+    public abstract List<User> findByCustomField(String customField);
+
     @Insert
     public abstract void insert(User user);
 
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationDb.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationDb.java
index 4a95ad8..ef207cf 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationDb.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationDb.java
@@ -17,6 +17,7 @@
 package android.arch.persistence.room.integration.testapp.migration;
 
 import android.arch.persistence.db.SupportSQLiteDatabase;
+import android.arch.persistence.room.ColumnInfo;
 import android.arch.persistence.room.Dao;
 import android.arch.persistence.room.Database;
 import android.arch.persistence.room.Entity;
@@ -75,6 +76,7 @@
         public static final String TABLE_NAME = "Entity4";
         @PrimaryKey
         public int id;
+        @ColumnInfo(collate = ColumnInfo.NOCASE)
         public String name;
     }
 
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java
index aa297ed..725d53f 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java
@@ -315,7 +315,7 @@
         @Override
         public void migrate(SupportSQLiteDatabase database) {
             database.execSQL("CREATE TABLE IF NOT EXISTS " + MigrationDb.Entity4.TABLE_NAME
-                    + " (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`),"
+                    + " (`id` INTEGER NOT NULL, `name` TEXT COLLATE NOCASE, PRIMARY KEY(`id`),"
                     + " FOREIGN KEY(`name`) REFERENCES `Entity1`(`name`)"
                     + " ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)");
         }
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/CustomDatabaseTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/CustomDatabaseTest.java
index 353c2e3..6f44546 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/CustomDatabaseTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/CustomDatabaseTest.java
@@ -55,7 +55,6 @@
         Customer customer = new Customer();
         for (int i = 0; i < 100; i++) {
             SampleDatabase db = builder.build();
-            customer.setId(i);
             db.getCustomerDao().insert(customer);
             // Give InvalidationTracker enough time to start #mRefreshRunnable and pass the
             // initialization check.
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 2b4a0e9..8861adb 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
@@ -265,6 +265,16 @@
     }
 
     @Test
+    public void findByCollateNoCase() {
+        User user = TestUtil.createUser(3);
+        user.setCustomField("abc");
+        mUserDao.insert(user);
+        List<User> users = mUserDao.findByCustomField("ABC");
+        assertThat(users, hasSize(1));
+        assertThat(users.get(0).getId(), is(3));
+    }
+
+    @Test
     public void deleteByAge() {
         User user1 = TestUtil.createUser(3);
         user1.setAge(30);
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 57cf585..a5b8839 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
@@ -43,7 +43,7 @@
 
     private Date mBirthday;
 
-    @ColumnInfo(name = "custommm")
+    @ColumnInfo(name = "custommm", collate = ColumnInfo.NOCASE)
     private String mCustomField;
 
     public int getId() {
diff --git a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java
index 5650829..818c46b 100644
--- a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java
+++ b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java
@@ -17,7 +17,6 @@
 package android.arch.persistence.room.integration.testapp;
 
 import android.arch.lifecycle.LifecycleRegistry;
-import android.arch.lifecycle.LifecycleRegistryOwner;
 import android.arch.lifecycle.LiveData;
 import android.arch.lifecycle.Observer;
 import android.arch.lifecycle.ViewModelProviders;
@@ -35,7 +34,7 @@
 /**
  * Sample PagedList activity which uses Room.
  */
-public class RoomPagedListActivity extends AppCompatActivity implements LifecycleRegistryOwner {
+public class RoomPagedListActivity extends AppCompatActivity {
 
     private RecyclerView mRecyclerView;
     private PagedListCustomerAdapter mAdapter;
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index 18fa660..a170c8e 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -46,13 +46,13 @@
 
 dependencies {
     api project(":room:common")
-    api project(":room:db")
-    api project(":room:db-impl")
+    api project(":persistence:db-framework")
+    api project(":persistence:db")
     api project(":arch:runtime")
     provided project(":paging:common")
     provided project(":lifecycle:runtime")
     provided project(":lifecycle:extensions")
-    compile libs.support.core_utils
+    compile libs.support.core_utils, libs.support_exclude_config
 
     testCompile project(":arch:core-testing")
     testCompile libs.junit
diff --git a/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java b/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
index c6eade5..8b7025b 100644
--- a/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
+++ b/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
@@ -199,8 +199,7 @@
                 SupportSQLiteOpenHelper.Configuration
                         .builder(InstrumentationRegistry.getTargetContext())
                         .name(null)
-                        .version(1)
-                        .callback(new SupportSQLiteOpenHelper.Callback() {
+                        .callback(new SupportSQLiteOpenHelper.Callback(1) {
                             @Override
                             public void onCreate(SupportSQLiteDatabase db) {
                                 for (String query : queries) {
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java b/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java
index 8767f06..47279d6 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java
@@ -44,6 +44,7 @@
 
     public RoomOpenHelper(@NonNull DatabaseConfiguration configuration, @NonNull Delegate delegate,
             @NonNull String identityHash) {
+        super(delegate.version);
         mConfiguration = configuration;
         mDelegate = delegate;
         mIdentityHash = identityHash;
@@ -135,6 +136,12 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public abstract static class Delegate {
+        public final int version;
+
+        public Delegate(int version) {
+            this.version = version;
+        }
+
         protected abstract void dropAllTables(SupportSQLiteDatabase database);
 
         protected abstract void createAllTables(SupportSQLiteDatabase database);
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/package-info.java b/room/runtime/src/main/java/android/arch/persistence/room/package-info.java
index faaa952..1dafc1b 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/package-info.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/package-info.java
@@ -39,8 +39,8 @@
  *     database row. For each {@link android.arch.persistence.room.Entity Entity}, a database table
  *     is created to hold the items. The Entity class must be referenced in the
  *     {@link android.arch.persistence.room.Database#entities() Database#entities} array. Each field
- *     of the Entity is persisted in the database unless it is annotated with
- *     {@link android.arch.persistence.room.Ignore Ignore}. Entities must have no-arg constructors.
+ *     of the Entity (and its super class) is persisted in the database unless it is denoted
+ *     otherwise (see {@link android.arch.persistence.room.Entity Entity} docs for details).
  *     </li>
  *     <li>{@link android.arch.persistence.room.Dao Dao}: This annotation marks a class or interface
  *     as a Data Access Object. Data access objects are the main component of Room that are
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index d35e7d5..7f86842 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -50,7 +50,7 @@
     compile project(":room:common")
     compile project(":room:runtime")
     compile project(":arch:runtime")
-    compile libs.support.core_utils
+    compile libs.support.core_utils, libs.support_exclude_config
     compile libs.rx_java
     testCompile libs.junit
     testCompile libs.mockito_core
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index ad25e64..078de88 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -42,11 +42,11 @@
 dependencies {
     compile project(":room:common")
     compile project(":room:runtime")
-    compile project(":room:db")
-    compile project(":room:db-impl")
+    compile project(":persistence:db")
+    compile project(":persistence:db-framework")
     compile project(":room:migration")
     compile project(":arch:runtime")
-    compile libs.support.core_utils
+    compile libs.support.core_utils, libs.support_exclude_config
     compile libs.junit
 }
 
diff --git a/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java b/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
index aea3e96..a27fe0f 100644
--- a/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
+++ b/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
@@ -146,7 +146,7 @@
         RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
                 new CreatingDelegate(schemaBundle.getDatabase()),
                 schemaBundle.getDatabase().getIdentityHash());
-        return openDatabase(name, version, roomOpenHelper);
+        return openDatabase(name, roomOpenHelper);
     }
 
     /**
@@ -189,17 +189,15 @@
         RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
                 new MigratingDelegate(schemaBundle.getDatabase(), validateDroppedTables),
                 schemaBundle.getDatabase().getIdentityHash());
-        return openDatabase(name, version, roomOpenHelper);
+        return openDatabase(name, roomOpenHelper);
     }
 
-    private SupportSQLiteDatabase openDatabase(String name, int version,
-            RoomOpenHelper roomOpenHelper) {
+    private SupportSQLiteDatabase openDatabase(String name, RoomOpenHelper roomOpenHelper) {
         SupportSQLiteOpenHelper.Configuration config =
                 SupportSQLiteOpenHelper.Configuration
                         .builder(mInstrumentation.getTargetContext())
                         .callback(roomOpenHelper)
                         .name(name)
-                        .version(version)
                         .build();
         SupportSQLiteDatabase db = mOpenFactory.create(config).getWritableDatabase();
         mManagedDatabases.add(new WeakReference<>(db));
@@ -401,6 +399,7 @@
         final DatabaseBundle mDatabaseBundle;
 
         RoomOpenHelperDelegate(DatabaseBundle databaseBundle) {
+            super(databaseBundle.getVersion());
             mDatabaseBundle = databaseBundle;
         }
 
diff --git a/samples/SupportContentDemos/build.gradle b/samples/SupportContentDemos/build.gradle
index 7e204b1..1ed1134 100644
--- a/samples/SupportContentDemos/build.gradle
+++ b/samples/SupportContentDemos/build.gradle
@@ -31,6 +31,13 @@
         targetSdkVersion project.ext.currentSdk
     }
 
+    signingConfigs {
+        debug {
+            // Use a local debug keystore to avoid build server issues.
+            storeFile project.rootProject.init.debugKeystore
+        }
+    }
+
     lintOptions {
         abortOnError true
         disable "SetTextI18n", "AppCompatResource", "WrongConstant", "AllowBackup",
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index 59b236d..4f5201e 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -1325,6 +1325,7 @@
     method protected void onHostStop();
     method public void pause();
     method public void play();
+    method public void playWhenPrepared();
     method public void previous();
     method public void removePlayerCallback(android.support.v17.leanback.media.PlaybackGlue.PlayerCallback);
     method public final void setHost(android.support.v17.leanback.media.PlaybackGlueHost);
diff --git a/v17/leanback/res/values-bn/strings.xml b/v17/leanback/res/values-bn/strings.xml
index 899c564..d0e08c4 100644
--- a/v17/leanback/res/values-bn/strings.xml
+++ b/v17/leanback/res/values-bn/strings.xml
@@ -21,7 +21,7 @@
     <string name="orb_search_action" msgid="5651268540267663887">"অনুসন্ধান অ্যাকশন"</string>
     <string name="lb_search_bar_hint" msgid="8325490927970116252">"অনুসন্ধান"</string>
     <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"অনুসন্ধান করতে বলুন"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> অনুসন্ধান করুন"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> খুঁজুন"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> অনুসন্ধান করতে বলুন"</string>
     <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
     <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
@@ -33,11 +33,11 @@
     <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"পেছনের দিকে যান %1$dX"</string>
     <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"সরাসরি পরেরটিতে চলে যান"</string>
     <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"সরাসরি আগেরটিতে চলে যান"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"আরো অ্যাকশন"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"আরও অ্যাকশন"</string>
     <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"উপরের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচন মুক্ত করুন"</string>
     <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"উপরের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচিত করুন"</string>
     <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"নীচের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচন মুক্ত করুন"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"নীচের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচন করুন"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"নীচের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন বেছে নিন"</string>
     <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"একটিরও পুনরাবৃত্তি করবেন না"</string>
     <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"সবগুলির পুনরাবৃত্তি করুন"</string>
     <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"একটির পুনরাবৃত্তি করুন"</string>
diff --git a/v17/leanback/res/values-hi/strings.xml b/v17/leanback/res/values-hi/strings.xml
index 6287f14..00ef8ab 100644
--- a/v17/leanback/res/values-hi/strings.xml
+++ b/v17/leanback/res/values-hi/strings.xml
@@ -41,11 +41,11 @@
     <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"कुछ भी न दोहराएं"</string>
     <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"सभी को दोहराएं"</string>
     <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"एक दोहराएं"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"फेर-बदल सक्षम करें"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"शफ़ल करना चालू करें"</string>
     <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"फेर-बदल अक्षम करें"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"उच्च गुणवत्ता सक्षम करें"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"अच्छी क्वालिटी में चलाएं"</string>
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करें"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षक सक्षम करें"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"सबटाइटल चालू करें"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षक अक्षम करें"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"चित्र मोड में चित्र डालें"</string>
     <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
@@ -55,5 +55,5 @@
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी रखें"</string>
     <string name="lb_media_player_error" msgid="3650250994187305396">"मीडिया प्लेयर गड़बड़ी कोड %1$d कुछ और %2$d"</string>
     <string name="lb_onboarding_get_started" msgid="6961440391306351139">"शुरू करें"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"अगला"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"आगे बढ़ें"</string>
 </resources>
diff --git a/v17/leanback/res/values-pa/strings.xml b/v17/leanback/res/values-pa/strings.xml
index 4b3c515..57956ee 100644
--- a/v17/leanback/res/values-pa/strings.xml
+++ b/v17/leanback/res/values-pa/strings.xml
@@ -18,7 +18,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="6215811486591629025">"ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਮੀਨੂ"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"ਖੋਜ ਕਿਰਿਆ"</string>
+    <string name="orb_search_action" msgid="5651268540267663887">"ਖੋਜ ਕਾਰਵਾਈ"</string>
     <string name="lb_search_bar_hint" msgid="8325490927970116252">"ਖੋਜੋ"</string>
     <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ਖੋਜਣ ਲਈ ਬੋਲੋ"</string>
     <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ਖੋਜੋ"</string>
@@ -27,12 +27,12 @@
     <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
     <string name="lb_playback_controls_play" msgid="731953341987346903">"ਪਲੇ ਕਰੋ"</string>
     <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ਰੋਕੋ"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ਅੱਗੇ ਭੇਜੋ"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX ਨੂੰ ਅੱਗੇ ਭੇਜੋ"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਭੇਜੋ"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX ਨੂੰ ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਭੇਜੋ"</string>
     <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ਰੀਵਾਈਂਡ"</string>
     <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX ਨੂੰ ਰੀਵਾਈਂਡ ਕਰੋ"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ਅਗਲਾ ਨੂੰ ਛੱਡੋ"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ਪਿਛਲਾ ਨੂੰ ਛੱਡੋ"</string>
+    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ਅਗਲੇ ਨੂੰ ਛੱਡੋ"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ਪਿਛਲੇ ਨੂੰ ਛੱਡੋ"</string>
     <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"ਹੋਰ ਕਿਰਿਆਵਾਂ"</string>
     <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"ਥੰਬ ਅਪ ਨੂੰ ਅਚੋਣਵਾਂ ਕਰੋ"</string>
     <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"ਥੰਬ ਅਪ ਨੂੰ ਚੁਣੋ"</string>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
index 7686c5c..d4c8d5d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -267,6 +267,10 @@
     void onExecuteEntranceTransition() {
         // wait till views get their initial position before start transition
         final View view = getView();
+        if (view == null) {
+            // fragment view destroyed, transition not needed
+            return;
+        }
         view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
index 213ed83..cbc4fa2 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
@@ -270,6 +270,10 @@
     void onExecuteEntranceTransition() {
         // wait till views get their initial position before start transition
         final View view = getView();
+        if (view == null) {
+            // fragment view destroyed, transition not needed
+            return;
+        }
         view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
diff --git a/v17/leanback/src/android/support/v17/leanback/media/PlaybackBannerControlGlue.java b/v17/leanback/src/android/support/v17/leanback/media/PlaybackBannerControlGlue.java
index ca424a8..e644632 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/PlaybackBannerControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/PlaybackBannerControlGlue.java
@@ -59,6 +59,24 @@
  * {@link #onPlayCompleted()}.
  * </p>
  *
+ * Sample Code:
+ * <pre><code>
+ * public class MyVideoFragment extends VideoFragment {
+ *     &#64;Override
+ *     public void onCreate(Bundle savedInstanceState) {
+ *         super.onCreate(savedInstanceState);
+ *         PlaybackBannerControlGlue<MediaPlayerAdapter> playerGlue =
+ *                 new PlaybackBannerControlGlue(getActivity(),
+ *                         new MediaPlayerAdapter(getActivity()));
+ *         playerGlue.setHost(new VideoFragmentGlueHost(this));
+ *         playerGlue.setSubtitle("Leanback artist");
+ *         playerGlue.setTitle("Leanback team at work");
+ *         String uriPath = "android.resource://com.example.android.leanback/raw/video";
+ *         playerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
+ *         playerGlue.playWhenPrepared();
+ *     }
+ * }
+ * </code></pre>
  * @param <T> Type of {@link PlayerAdapter} passed in constructor.
  */
 public class PlaybackBannerControlGlue<T extends PlayerAdapter>
diff --git a/v17/leanback/src/android/support/v17/leanback/media/PlaybackGlue.java b/v17/leanback/src/android/support/v17/leanback/media/PlaybackGlue.java
index 32d5545..020f660 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/PlaybackGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/PlaybackGlue.java
@@ -174,12 +174,32 @@
     }
 
     /**
-     * Starts the media player.
+     * Starts the media player. Does nothing if {@link #isPrepared()} is false. To wait
+     * {@link #isPrepared()} to be true before playing, use {@link #playWhenPrepared()}.
      */
     public void play() {
     }
 
     /**
+     * Starts play when {@link #isPrepared()} becomes true.
+     */
+    public void playWhenPrepared() {
+        if (isPrepared()) {
+            play();
+        } else {
+            addPlayerCallback(new PlayerCallback() {
+                @Override
+                public void onPreparedStateChanged(PlaybackGlue glue) {
+                    if (glue.isPrepared()) {
+                        removePlayerCallback(this);
+                        play();
+                    }
+                }
+            });
+        }
+    }
+
+    /**
      * Pauses the media player.
      */
     public void pause() {
diff --git a/v17/leanback/src/android/support/v17/leanback/media/PlaybackTransportControlGlue.java b/v17/leanback/src/android/support/v17/leanback/media/PlaybackTransportControlGlue.java
index d0496e4..4aa9bf6 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/PlaybackTransportControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/PlaybackTransportControlGlue.java
@@ -68,23 +68,15 @@
  *     &#64;Override
  *     public void onCreate(Bundle savedInstanceState) {
  *         super.onCreate(savedInstanceState);
- *         final PlaybackTransportControlGlue<MediaPlayerAdapter> playerGlue =
+ *         PlaybackTransportControlGlue<MediaPlayerAdapter> playerGlue =
  *                 new PlaybackTransportControlGlue(getActivity(),
  *                         new MediaPlayerAdapter(getActivity()));
  *         playerGlue.setHost(new VideoFragmentGlueHost(this));
- *         playerGlue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
- *             &#64;Override
- *             public void onPreparedStateChanged(PlaybackGlue glue) {
- *                 if (glue.isPrepared()) {
- *                     playerGlue.setSeekProvider(new MySeekProvider());
- *                     playerGlue.play();
- *                 }
- *             }
- *         });
  *         playerGlue.setSubtitle("Leanback artist");
  *         playerGlue.setTitle("Leanback team at work");
  *         String uriPath = "android.resource://com.example.android.leanback/raw/video";
  *         playerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
+ *         playerGlue.playWhenPrepared();
  *     }
  * }
  * </code></pre>
@@ -254,9 +246,7 @@
             // playing    paused                  paused
             // paused     playing       playing
             // ff/rw      playing       playing   paused
-            if (canPause
-                    && (canPlay ? mIsPlaying :
-                    !mIsPlaying)) {
+            if (canPause && mIsPlaying) {
                 mIsPlaying = false;
                 pause();
             } else if (canPlay && !mIsPlaying) {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
index 6787491..38d08c7 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
@@ -34,6 +34,7 @@
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
 import android.support.v17.leanback.media.MediaPlayerGlue;
@@ -1171,4 +1172,45 @@
         });
     }
 
+    public static class DetailsFragmentEntranceTransitionTimeout extends DetailsTestFragment {
+
+        public DetailsFragmentEntranceTransitionTimeout() {
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            prepareEntranceTransition();
+        }
+
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+    public void startEntranceTransitionAfterDestroyed() {
+        SingleFragmentTestActivity activity = launchAndWaitActivity(
+                DetailsFragmentEntranceTransition.class, new Options().uiVisibility(
+                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN),
+                1000);
+        final DetailsFragmentEntranceTransition detailsFragment =
+                (DetailsFragmentEntranceTransition)
+                        activity.getTestFragment();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                        android.support.v17.leanback.test.R.drawable.spiderman));
+            }
+        });
+        SystemClock.sleep(100);
+        activity.finish();
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.startEntranceTransition();
+            }
+        });
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
index d4a41e0..04f20bc 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
@@ -37,6 +37,7 @@
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
 import android.support.v17.leanback.media.MediaPlayerGlue;
@@ -1174,4 +1175,45 @@
         });
     }
 
+    public static class DetailsSupportFragmentEntranceTransitionTimeout extends DetailsTestSupportFragment {
+
+        public DetailsSupportFragmentEntranceTransitionTimeout() {
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            prepareEntranceTransition();
+        }
+
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+    public void startEntranceTransitionAfterDestroyed() {
+        SingleSupportFragmentTestActivity activity = launchAndWaitActivity(
+                DetailsSupportFragmentEntranceTransition.class, new Options().uiVisibility(
+                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN),
+                1000);
+        final DetailsSupportFragmentEntranceTransition detailsFragment =
+                (DetailsSupportFragmentEntranceTransition)
+                        activity.getTestFragment();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                        android.support.v17.leanback.test.R.drawable.spiderman));
+            }
+        });
+        SystemClock.sleep(100);
+        activity.finish();
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.startEntranceTransition();
+            }
+        });
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueTest.java
index 0f96196..38c73e8 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueTest.java
@@ -17,10 +17,13 @@
 package android.support.v17.leanback.media;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.support.test.InstrumentationRegistry;
@@ -114,4 +117,25 @@
         assertTrue(called[1]);
         assertEquals(2, glue.getPlayerCallbacks().size());
     }
+
+    @Test
+    public void playWhenPrepared() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        PlaybackGlue glue = Mockito.spy(new PlaybackGlueImpl(context));
+        PlaybackGlueHostImpl host = new PlaybackGlueHostImpl();
+
+        when(glue.isPrepared()).thenReturn(false);
+        glue.setHost(host);
+        glue.playWhenPrepared();
+        assertFalse(glue.isPrepared());
+        Mockito.verify(glue, never()).play();
+
+        when(glue.isPrepared()).thenReturn(true);
+        for (PlaybackGlue.PlayerCallback callback: glue.getPlayerCallbacks()) {
+            callback.onPreparedStateChanged(glue);
+        }
+        assertTrue(glue.isPrepared());
+        Mockito.verify(glue, times(1)).play();
+        assertEquals(0, glue.getPlayerCallbacks().size());
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java
index d6ce824..ab936ad 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertSame;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 
@@ -33,6 +34,7 @@
 import android.support.v17.leanback.widget.PlaybackTransportRowPresenter;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.view.ContextThemeWrapper;
+import android.view.KeyEvent;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
@@ -67,6 +69,41 @@
     Context mContext;
     PlaybackTransportControlGlueImpl mGlue;
     PlaybackTransportRowPresenter.ViewHolder mViewHolder;
+    PlayerAdapter mAdapter;
+
+    void setupWithMockAdapterAndViewHolder() {
+        mContext = new ContextThemeWrapper(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                android.support.v17.leanback.test.R.style.Theme_Leanback);
+
+        mAdapter = Mockito.mock(PlayerAdapter.class);
+        when(mAdapter.isPrepared()).thenReturn(true);
+        when(mAdapter.getCurrentPosition()).thenReturn(123L);
+        when(mAdapter.getDuration()).thenReturn(20000L);
+        when(mAdapter.getBufferedPosition()).thenReturn(321L);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mGlue = new PlaybackTransportControlGlueImpl(mContext, mAdapter);
+                PlaybackGlueHostImpl host = new PlaybackGlueHostImpl();
+                mGlue.setHost(host);
+
+                PlaybackTransportRowPresenter presenter = (PlaybackTransportRowPresenter)
+                        mGlue.getPlaybackRowPresenter();
+                FrameLayout parent = new FrameLayout(mContext);
+                mViewHolder = (PlaybackTransportRowPresenter.ViewHolder)
+                        presenter.onCreateViewHolder(parent);
+                presenter.onBindViewHolder(mViewHolder, mGlue.getControlsRow());
+            }
+        });
+    }
+
+    void playMockAdapter() {
+        mGlue.play();
+        Mockito.verify(mAdapter, times(1)).play();
+        when(mAdapter.isPlaying()).thenReturn(true);
+        mAdapter.getCallback().onPlayStateChanged(mAdapter);
+    }
 
     @Test
     public void usingDefaultRowAndPresenter() {
@@ -163,54 +200,30 @@
 
     @Test
     public void playerAdapterTest() {
-        mContext = new ContextThemeWrapper(
-                InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                android.support.v17.leanback.test.R.style.Theme_Leanback);
-
-        final PlayerAdapter impl = Mockito.mock(PlayerAdapter.class);
-        when(impl.isPrepared()).thenReturn(true);
-        when(impl.getCurrentPosition()).thenReturn(123L);
-        when(impl.getDuration()).thenReturn(20000L);
-        when(impl.getBufferedPosition()).thenReturn(321L);
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mGlue = new PlaybackTransportControlGlueImpl(mContext, impl);
-                PlaybackGlueHostImpl host = new PlaybackGlueHostImpl();
-                mGlue.setHost(host);
-
-                PlaybackTransportRowPresenter presenter = (PlaybackTransportRowPresenter)
-                        mGlue.getPlaybackRowPresenter();
-                FrameLayout parent = new FrameLayout(mContext);
-                mViewHolder = (PlaybackTransportRowPresenter.ViewHolder)
-                        presenter.onCreateViewHolder(parent);
-                presenter.onBindViewHolder(mViewHolder, mGlue.getControlsRow());
-            }
-        });
-
+        setupWithMockAdapterAndViewHolder();
 
         mGlue.play();
-        Mockito.verify(impl, times(1)).play();
+        Mockito.verify(mAdapter, times(1)).play();
         mGlue.pause();
-        Mockito.verify(impl, times(1)).pause();
+        Mockito.verify(mAdapter, times(1)).pause();
         mGlue.seekTo(123L);
-        Mockito.verify(impl, times(1)).seekTo(123L);
+        Mockito.verify(mAdapter, times(1)).seekTo(123L);
         assertEquals(123L, mGlue.getCurrentPosition());
         assertEquals(20000L, mGlue.getDuration());
         assertEquals(321L, mGlue.getBufferedPosition());
 
-        assertSame(mGlue.mAdapterCallback, impl.getCallback());
+        assertSame(mGlue.mAdapterCallback, mAdapter.getCallback());
 
-        when(impl.getCurrentPosition()).thenReturn(124L);
-        impl.getCallback().onCurrentPositionChanged(impl);
+        when(mAdapter.getCurrentPosition()).thenReturn(124L);
+        mAdapter.getCallback().onCurrentPositionChanged(mAdapter);
         assertEquals(124L, mGlue.getControlsRow().getCurrentPosition());
 
-        when(impl.getBufferedPosition()).thenReturn(333L);
-        impl.getCallback().onBufferedPositionChanged(impl);
+        when(mAdapter.getBufferedPosition()).thenReturn(333L);
+        mAdapter.getCallback().onBufferedPositionChanged(mAdapter);
         assertEquals(333L, mGlue.getControlsRow().getBufferedPosition());
 
-        when(impl.getDuration()).thenReturn((long) (Integer.MAX_VALUE) * 2);
-        impl.getCallback().onDurationChanged(impl);
+        when(mAdapter.getDuration()).thenReturn((long) (Integer.MAX_VALUE) * 2);
+        mAdapter.getCallback().onDurationChanged(mAdapter);
         assertEquals((long) (Integer.MAX_VALUE) * 2, mGlue.getControlsRow().getDuration());
 
     }
@@ -272,4 +285,60 @@
         Mockito.verify(hostCallback2, times(0)).onError(anyInt(), anyString());
     }
 
+    @Test
+    public void playStateReceivePlayPause() {
+        setupWithMockAdapterAndViewHolder();
+        playMockAdapter();
+
+        mGlue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+        Mockito.verify(mAdapter, times(1)).pause();
+    }
+
+    @Test
+    public void playStateReceivePause() {
+        setupWithMockAdapterAndViewHolder();
+        playMockAdapter();
+
+        mGlue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PAUSE));
+        Mockito.verify(mAdapter, times(1)).pause();
+    }
+
+    @Test
+    public void playStateReceivePlay() {
+        setupWithMockAdapterAndViewHolder();
+        playMockAdapter();
+
+        mGlue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY));
+        Mockito.verify(mAdapter, never()).pause();
+    }
+
+    @Test
+    public void pauseStateReceivePlayPause() {
+        setupWithMockAdapterAndViewHolder();
+
+        mGlue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+        Mockito.verify(mAdapter, times(1)).play();
+    }
+
+    @Test
+    public void pauseStateReceivePause() {
+        setupWithMockAdapterAndViewHolder();
+
+        mGlue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PAUSE));
+        Mockito.verify(mAdapter, never()).play();
+    }
+
+    @Test
+    public void pauseStateReceivePlay() {
+        setupWithMockAdapterAndViewHolder();
+
+        mGlue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY));
+        Mockito.verify(mAdapter, times(1)).play();
+    }
 }
diff --git a/v7/appcompat/res/values-bn/strings.xml b/v7/appcompat/res/values-bn/strings.xml
index 5959799..2ea7591 100644
--- a/v7/appcompat/res/values-bn/strings.xml
+++ b/v7/appcompat/res/values-bn/strings.xml
@@ -19,11 +19,11 @@
     <string name="abc_action_mode_done" msgid="4076576682505996667">"সম্পন্ন হয়েছে"</string>
     <string name="abc_action_bar_home_description" msgid="4600421777120114993">"হোম এ নেভিগেট করুন"</string>
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"উপরের দিকে নেভিগেট করুন"</string>
-    <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"আরো বিকল্প"</string>
+    <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"আরও বিকল্প"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"সঙ্কুচিত করুন"</string>
-    <string name="abc_searchview_description_search" msgid="8264924765203268293">"অনুসন্ধান করুন"</string>
+    <string name="abc_searchview_description_search" msgid="8264924765203268293">"খুঁজুন"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"অনুসন্ধান..."</string>
-    <string name="abc_searchview_description_query" msgid="2550479030709304392">"ক্যোয়ারী অনুসন্ধান করুন"</string>
+    <string name="abc_searchview_description_query" msgid="2550479030709304392">"ক্যোয়ারী খুঁজুন"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ক্যোয়ারী সাফ করুন"</string>
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ক্যোয়ারী জমা দিন"</string>
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"ভয়েস অনুসন্ধান"</string>
@@ -33,5 +33,5 @@
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"এর সাথে শেয়ার করুন"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"চালু"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"বন্ধ"</string>
-    <string name="search_menu_title" msgid="146198913615257606">"অনুসন্ধান করুন"</string>
+    <string name="search_menu_title" msgid="146198913615257606">"খুঁজুন"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hi/strings.xml b/v7/appcompat/res/values-hi/strings.xml
index 0d90e55..3a393c7 100644
--- a/v7/appcompat/res/values-hi/strings.xml
+++ b/v7/appcompat/res/values-hi/strings.xml
@@ -16,11 +16,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="abc_action_mode_done" msgid="4076576682505996667">"पूर्ण"</string>
+    <string name="abc_action_mode_done" msgid="4076576682505996667">"हो गया"</string>
     <string name="abc_action_bar_home_description" msgid="4600421777120114993">"होम पेज पर जाएं"</string>
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ऊपर जाएं"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ज़्यादा विकल्प"</string>
-    <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"संक्षिप्त करें"</string>
+    <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"छोटा करें"</string>
     <string name="abc_searchview_description_search" msgid="8264924765203268293">"सर्च करें"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"खोजा जा रहा है…"</string>
     <string name="abc_searchview_description_query" msgid="2550479030709304392">"सर्च क्वेरी"</string>
diff --git a/v7/appcompat/res/values-pa/strings.xml b/v7/appcompat/res/values-pa/strings.xml
index bc2e6ea..7f28ac8 100644
--- a/v7/appcompat/res/values-pa/strings.xml
+++ b/v7/appcompat/res/values-pa/strings.xml
@@ -17,13 +17,13 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_action_mode_done" msgid="4076576682505996667">"ਹੋ ਗਿਆ"</string>
-    <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ਹੋਮ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
-    <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ਉੱਪਰ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
+    <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ਹੋਮ \'ਤੇ ਜਾਓ"</string>
+    <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ਉੱਪਰ ਜਾਓ"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ਹੋਰ ਚੋਣਾਂ"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"ਨਸ਼ਟ ਕਰੋ"</string>
     <string name="abc_searchview_description_search" msgid="8264924765203268293">"ਖੋਜੋ"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"ਖੋਜ…"</string>
-    <string name="abc_searchview_description_query" msgid="2550479030709304392">"ਸਵਾਲ ਖੋਜੋ"</string>
+    <string name="abc_searchview_description_query" msgid="2550479030709304392">"ਖੋਜ ਪੁੱਛਗਿੱਛ"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ਸਵਾਲ ਹਟਾਓ"</string>
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ਸਵਾਲ ਪ੍ਰਸਤੁਤ ਕਰੋ"</string>
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"ਵੌਇਸ ਖੋਜ"</string>
@@ -33,5 +33,5 @@
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ਇਸ ਨਾਲ ਸਾਂਝਾ ਕਰੋ"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"ਤੇ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ਬੰਦ"</string>
-    <string name="search_menu_title" msgid="146198913615257606">"ਖੋਜ"</string>
+    <string name="search_menu_title" msgid="146198913615257606">"ਖੋਜੋ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ta/strings.xml b/v7/appcompat/res/values-ta/strings.xml
index 7daeaaf..4a2ad2f 100644
--- a/v7/appcompat/res/values-ta/strings.xml
+++ b/v7/appcompat/res/values-ta/strings.xml
@@ -31,7 +31,7 @@
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"எல்லாம் காட்டு"</string>
     <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> மூலம் பகிர்"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"இதனுடன் பகிர்"</string>
-    <string name="abc_capital_on" msgid="3405795526292276155">"இயக்கு"</string>
-    <string name="abc_capital_off" msgid="121134116657445385">"முடக்கு"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ஆன்"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ஆஃப்"</string>
     <string name="search_menu_title" msgid="146198913615257606">"தேடு"</string>
 </resources>
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index d48d826..52ae694 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -568,6 +568,9 @@
             <enum name="multiply" value="14" />
             <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
             <enum name="screen" value="15" />
+            <!-- Combines the tint and icon color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
         </attr>
     </declare-styleable>
 
@@ -1037,6 +1040,9 @@
             <enum name="multiply" value="14" />
             <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
             <enum name="screen" value="15" />
+            <!-- Combines the tint and icon color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
         </attr>
     </declare-styleable>
 
@@ -1175,6 +1181,9 @@
             <enum name="multiply" value="14" />
             <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
             <enum name="screen" value="15" />
+            <!-- Combines the tint and icon color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
         </attr>
     </declare-styleable>
 
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
index 90e6aa9..b2b1f10 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
@@ -23,7 +23,6 @@
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.Nullable;
@@ -102,14 +101,6 @@
     }
 
     @Override
-    public void setImageIcon(@Nullable Icon icon) {
-        super.setImageIcon(icon);
-        if (mImageHelper != null) {
-            mImageHelper.applySupportImageTint();
-        }
-    }
-
-    @Override
     public void setImageURI(@Nullable Uri uri) {
         super.setImageURI(uri);
         if (mImageHelper != null) {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
index 0844f9a..f50799e 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
@@ -23,7 +23,6 @@
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.Nullable;
@@ -112,14 +111,6 @@
     }
 
     @Override
-    public void setImageIcon(@Nullable Icon icon) {
-        super.setImageIcon(icon);
-        if (mImageHelper != null) {
-            mImageHelper.applySupportImageTint();
-        }
-    }
-
-    @Override
     public void setImageURI(@Nullable Uri uri) {
         super.setImageURI(uri);
         if (mImageHelper != null) {
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index adf3e88..f9ac43b 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -30,8 +30,8 @@
     <string name="mr_controller_play" msgid="683634565969987458">"चलाएं"</string>
     <string name="mr_controller_pause" msgid="5451884435510905406">"रोकें"</string>
     <string name="mr_controller_stop" msgid="735874641921425123">"बंद करें"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करें"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त करें"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तार करें"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"छोटा करें"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
     <string name="mr_controller_volume_slider" msgid="2361785992211841709">"वॉल्यूम स्लाइडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कोई मीडिया चयनित नहीं है"</string>
diff --git a/v7/mediarouter/res/values-ta/strings.xml b/v7/mediarouter/res/values-ta/strings.xml
index 59dac88..99c6172 100644
--- a/v7/mediarouter/res/values-ta/strings.xml
+++ b/v7/mediarouter/res/values-ta/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
+    <string name="mr_system_route_name" msgid="5441529851481176817">"சிஸ்டம்"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"திரையிடு பட்டன்"</string>
     <string name="mr_cast_button_disconnected" msgid="816305490427819240">"அனுப்புதல் பொத்தான். துண்டிக்கப்பட்டது"</string>
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/res/values/themes.xml
index 8c6e97a..586db92 100644
--- a/v7/mediarouter/res/values/themes.xml
+++ b/v7/mediarouter/res/values/themes.xml
@@ -17,6 +17,7 @@
 <resources>
 
     <style name="Theme.MediaRouter" parent="ThemeOverlay.AppCompat.Dark">
+        <item name="android:backgroundDimEnabled">true</item>
         <item name="windowNoTitle">true</item>
         <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.MediaRouteButton</item>
 
@@ -38,6 +39,7 @@
     </style>
 
     <style name="Theme.MediaRouter.Light" parent="ThemeOverlay.AppCompat.Light">
+        <item name="android:backgroundDimEnabled">true</item>
         <item name="windowNoTitle">true</item>
         <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
 
diff --git a/v7/preference/res/layout/preference_dialog_edittext.xml b/v7/preference/res/layout/preference_dialog_edittext.xml
index 9fbf2b7..34aa7f3 100644
--- a/v7/preference/res/layout/preference_dialog_edittext.xml
+++ b/v7/preference/res/layout/preference_dialog_edittext.xml
@@ -25,7 +25,8 @@
   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:padding="5dip"
+      android:layout_marginStart="24dp"
+      android:layout_marginEnd="24dp"
       android:orientation="vertical">
 
     <TextView android:id="@android:id/message"
@@ -35,10 +36,12 @@
         android:layout_height="wrap_content"
         android:textColor="?android:attr/textColorSecondary" />
 
-      <EditText
-          android:id="@android:id/edit"
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content" />
+    <EditText
+        android:id="@android:id/edit"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="-4dp"
+        android:layout_marginEnd="-4dp" />
 
   </LinearLayout>