Merge "Change theme application order" into oc-mr1-support-27.0-dev
diff --git a/annotations/build.gradle b/annotations/build.gradle
index af4174d..b50cd77 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportJavaLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
 
 jar {
     from sourceSets.main.output
@@ -27,12 +31,6 @@
     }
 }
 
-// custom tasks for creating source/javadoc jars
-task sourcesJar(type: Jar, dependsOn:classes) {
-    classifier = 'sources'
-    from sourceSets.main.allSource
-}
-
 task javadocJar(type: Jar, dependsOn:javadoc) {
     classifier         'javadoc'
     from               javadoc.destinationDir
@@ -46,14 +44,14 @@
 // add javadoc/source/annotations jar tasks as artifacts
 artifacts {
     archives jar
-    archives sourcesJar
     archives javadocJar
     archives annotationsZip
 }
 
 supportLibrary {
-    name 'Android Support Library Annotations'
-    publish true
-    inceptionYear '2013'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs."
+    name = "Android Support Library Annotations"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2013"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs."
 }
\ No newline at end of file
diff --git a/app-toolkit/build.gradle b/app-toolkit/build.gradle
index 155a836..9bcb827 100644
--- a/app-toolkit/build.gradle
+++ b/app-toolkit/build.gradle
@@ -18,10 +18,11 @@
     ext.supportRootFolder = new File(project.projectDir, "../")
     apply from: 'buildSrc/repos.gradle'
     apply from: 'init.gradle'
+    apply from: "buildSrc/build_dependencies.gradle"
     repos.addMavenRepositories(repositories)
     dependencies {
-        classpath libs.jacoco
-        classpath libs.gradle
-        classpath libs.kotlin.gradle_plugin
+        classpath build_libs.jacoco
+        classpath build_libs.gradle
+        classpath build_libs.kotlin.gradle_plugin
     }
 }
diff --git a/app-toolkit/common/build.gradle b/app-toolkit/common/build.gradle
index 4f51a49..42b0f5a 100644
--- a/app-toolkit/common/build.gradle
+++ b/app-toolkit/common/build.gradle
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
-apply plugin: android.support.SupportJavaLibraryPlugin
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
 
 dependencies {
     compile libs.support.annotations
@@ -30,9 +33,10 @@
 
 version = LibraryVersions.ARCH_CORE.toString()
 supportLibrary {
-    name 'Android Arch-Common'
-    publish true
-    inceptionYear '2017'
-    description "Android Arch-Common"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Arch-Common"
+    publish = true
+    mavenGroup = LibraryGroups.ARCH_CORE
+    inceptionYear = "2017"
+    description = "Android Arch-Common"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/app-toolkit/core-testing/api/1.0.0.txt b/app-toolkit/core-testing/api/1.0.0.txt
new file mode 100644
index 0000000..f1d206c
--- /dev/null
+++ b/app-toolkit/core-testing/api/1.0.0.txt
@@ -0,0 +1,15 @@
+package android.arch.core.executor.testing {
+
+  public class CountingTaskExecutorRule extends org.junit.rules.TestWatcher {
+    ctor public CountingTaskExecutorRule();
+    method public void drainTasks(int, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public boolean isIdle();
+    method protected void onIdle();
+  }
+
+  public class InstantTaskExecutorRule extends org.junit.rules.TestWatcher {
+    ctor public InstantTaskExecutorRule();
+  }
+
+}
+
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index 44d5ff0..296e7b7 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -14,34 +14,24 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
 dependencies {
     compile project(":arch:runtime")
     compile libs.support.annotations
-    compile(libs.junit) {
-        exclude module: 'hamcrest-core'
-    }
+    compile(libs.junit)
     compile libs.mockito_core, { exclude group: 'net.bytebuddy' }
 
     testCompile libs.junit
@@ -66,9 +56,10 @@
 
 version = LibraryVersions.ARCH_CORE_TESTING.toString()
 supportLibrary {
-    name 'Android Core-Testing'
-    publish true
-    inceptionYear '2017'
-    description "Android Core-Testing"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Core-Testing"
+    publish = true
+    mavenGroup = LibraryGroups.ARCH_CORE
+    inceptionYear = "2017"
+    description = "Android Core-Testing"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/app-toolkit/core-testing/lint-baseline.xml b/app-toolkit/core-testing/lint-baseline.xml
new file mode 100644
index 0000000..3ce85c7
--- /dev/null
+++ b/app-toolkit/core-testing/lint-baseline.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+    <issue
+        id="InvalidPackage"
+        message="Invalid package reference in library; not included in Android: `java.lang.management`. Referenced from `org.junit.internal.runners.statements.FailOnTimeout`.">
+        <location
+            file="../../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12.jar"/>
+    </issue>
+
+    <issue
+        id="InvalidPackage"
+        message="Invalid package reference in library; not included in Android: `java.lang.instrument`. Referenced from `org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker`.">
+        <location
+            file="../../../../prebuilts/tools/common/m2/repository/org/mockito/mockito-core/2.7.6/mockito-core-2.7.6.jar"/>
+    </issue>
+
+</issues>
diff --git a/app-toolkit/dependencies.gradle b/app-toolkit/dependencies.gradle
index cb68089..31fc2ae 100644
--- a/app-toolkit/dependencies.gradle
+++ b/app-toolkit/dependencies.gradle
@@ -42,7 +42,6 @@
 
 ffLibs.kotlin = [
         stdlib : "org.jetbrains.kotlin:kotlin-stdlib:$ffVersions.kotlin",
-        gradle_plugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$ffVersions.kotlin"
 ]
 ffLibs.auto_common = "com.google.auto:auto-common:$ffVersions.auto_common"
 ffLibs.apache = [
diff --git a/app-toolkit/gradle/wrapper/gradle-wrapper.properties b/app-toolkit/gradle/wrapper/gradle-wrapper.properties
index d90766a..9d09896 100644
--- a/app-toolkit/gradle/wrapper/gradle-wrapper.properties
+++ b/app-toolkit/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=../../../../../tools/external/gradle/gradle-4.1-bin.zip
+distributionUrl=../../../../../tools/external/gradle/gradle-4.3-bin.zip
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index cd56153..1d6b752 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -92,14 +92,6 @@
 buildServerAnchorTask.dependsOn createDiffArchive
 buildServerAnchorTask.dependsOn createArchive
 
-rootProject.ext.flatfootProjectGroups = [
-        "room" : "android.arch.persistence.room",
-        "persistence" : "android.arch.persistence",
-        "lifecycle" : "android.arch.lifecycle",
-        "arch" : "android.arch.core",
-        "paging" : "android.arch.paging",
-        "navigation" : "android.arch.navigation"]
-
 subprojects {
     repos.addMavenRepositories(project.repositories)
     if (project.name == 'doclava' || project.name == 'jdiff') {
@@ -111,18 +103,6 @@
         return
     }
 
-    def projectPath = project.getPath().split(":")
-    def mavenGroup = projectPath[1]
-    def finalGroup = rootProject.flatfootProjectGroups[mavenGroup]
-
-    if (finalGroup == null) {
-        return
-    }
-    if (projectPath.size() == 2) {// root project.
-        return
-    }
-    project.group = finalGroup
-
     if (project.getPath().contains("integration-tests")) {
         // disable upload tasks
         project.tasks.whenTaskAdded { task ->
@@ -147,35 +127,6 @@
         }
     }
 
-    project.plugins.whenPluginAdded { plugin ->
-        def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin"
-                .equals(plugin.class.name)
-        def isJavaLibrary = "org.gradle.api.plugins.JavaPlugin".equals(plugin.class.name)
-        if (isAndroidLibrary) {
-            // it is an android lib, enable sources.
-            def sourcesTask = project.tasks.create(name: "sourcesJar", type : Jar) {
-                classifier = 'sources'
-                from android.sourceSets.main.getJava().getSrcDirs()
-            }
-            project.artifacts {
-                archives sourcesTask
-            }
-            project.android.defaultConfig {
-                // Update the version meta-data in each Manifest.
-                addManifestPlaceholders(["version" : project.version])
-            }
-        } else if(isJavaLibrary && project.name == "common") {
-            // it is a shared lib, enable sources.
-            def sourcesTask = project.tasks.create(name: "sourcesJar", type : Jar) {
-                classifier = 'sources'
-                from sourceSets.main.allSource
-            }
-            project.artifacts {
-                archives sourcesTask
-            }
-        }
-    }
-
     project.tasks.whenTaskAdded { task ->
         if (task.name.startsWith("assembleAndroidTest")) {
             buildServerAnchorTask.dependsOn task
diff --git a/app-toolkit/runtime/api/1.0.0.txt b/app-toolkit/runtime/api/1.0.0.txt
new file mode 100644
index 0000000..af5b253
--- /dev/null
+++ b/app-toolkit/runtime/api/1.0.0.txt
@@ -0,0 +1,8 @@
+package android.arch.core.util {
+
+  public abstract interface Function<I, O> {
+    method public abstract O apply(I);
+  }
+
+}
+
diff --git a/app-toolkit/runtime/build.gradle b/app-toolkit/runtime/build.gradle
index 434d42b..c0d7224 100644
--- a/app-toolkit/runtime/build.gradle
+++ b/app-toolkit/runtime/build.gradle
@@ -14,29 +14,22 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.SupportLibraryExtension
 import android.support.LibraryVersions
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     testOptions {
         unitTests.returnDefaultValues = true
     }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
 dependencies {
@@ -58,9 +51,10 @@
 
 version = LibraryVersions.ARCH_RUNTIME.toString()
 supportLibrary {
-    name 'Android Arch-Runtime'
-    publish true
-    inceptionYear '2017'
-    description "Android Arch-Runtime"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Arch-Runtime"
+    publish = true
+    mavenGroup = LibraryGroups.ARCH_CORE
+    inceptionYear = "2017"
+    description = "Android Arch-Runtime"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/app-toolkit/runtime/lint-baseline.xml b/app-toolkit/runtime/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/app-toolkit/runtime/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/build.gradle b/build.gradle
index 8c32175..ec83da5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,14 +17,14 @@
 buildscript {
     ext.supportRootFolder = project.projectDir
     apply from: 'buildSrc/repos.gradle'
-
     apply from: 'buildSrc/init.gradle'
+    apply from: 'buildSrc/build_dependencies.gradle'
     init.setSdkInLocalPropertiesFile()
     repos.addMavenRepositories(repositories)
 
     dependencies {
-        classpath libs.gradle
-        classpath libs.jacoco
+        classpath build_libs.gradle
+        classpath build_libs.jacoco
     }
 }
 
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 9f648d9..9c0d8af 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -1,17 +1,37 @@
-apply plugin: 'groovy'
-apply plugin: 'java'
+buildscript {
+    def supportRootFolder = project.projectDir.getParentFile()
+    repositories {
+        maven {
+            url "${supportRootFolder}/../../prebuilts/tools/common/m2/repository"
+        }
+    }
 
-apply from: "dependencies.gradle"
+    apply from: "build_dependencies.gradle"
+
+    dependencies {
+        classpath build_libs.kotlin.gradle_plugin
+    }
+}
+
+apply from: "build_dependencies.gradle"
 
 ext.supportRootFolder = project.projectDir.getParentFile()
 apply from: 'repos.gradle'
 
 repos.addMavenRepositories(repositories)
 
+apply plugin: 'groovy'
+apply plugin: 'java'
+apply plugin: 'kotlin'
+
+compileGroovy {
+    dependsOn tasks.getByPath('compileKotlin')
+    classpath += files(compileKotlin.destinationDir)
+}
 dependencies {
-    compile libs.gradle
-    compile libs.jacoco
-    compile libs.error_prone
-    compile libs.jarjar_gradle
+    compile build_libs.gradle
+    compile build_libs.jacoco
+    compile build_libs.error_prone
+    compile build_libs.jarjar_gradle
     compile gradleApi()
 }
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
new file mode 100644
index 0000000..b7a5049
--- /dev/null
+++ b/buildSrc/build_dependencies.gradle
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+def build_libs = [:]
+
+def androidPluginVersionOverride = System.getenv("GRADLE_PLUGIN_VERSION")
+
+if (androidPluginVersionOverride != null) {
+    build_libs.gradle = 'com.android.tools.build:gradle:' + androidPluginVersionOverride
+} else {
+    // Keep gradle plugin version in sync with ub_supportlib-master manifest.
+    build_libs.gradle = 'com.android.tools.build:gradle:3.0.0'
+}
+
+// jarjar plugin
+build_libs.jarjar_gradle = 'org.anarres.jarjar:jarjar-gradle:1.0.0'
+build_libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.10'
+build_libs.jacoco = 'org.jacoco:org.jacoco.core:0.7.8'
+build_libs.kotlin = [gradle_plugin: "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.3"]
+
+rootProject.ext['build_libs'] = build_libs
diff --git a/buildSrc/dependencies.gradle b/buildSrc/dependencies.gradle
index ebeaa7e..b61cfc6 100644
--- a/buildSrc/dependencies.gradle
+++ b/buildSrc/dependencies.gradle
@@ -24,26 +24,12 @@
 libs.test_rules = 'com.android.support.test:rules:1.0.1'
 libs.espresso_core = 'com.android.support.test.espresso:espresso-core:3.0.1'
 libs.espresso_contrib = 'com.android.support.test.espresso:espresso-contrib:3.0.1'
-libs.jacoco = 'org.jacoco:org.jacoco.core:0.7.8'
-
-def androidPluginVersionOverride = System.getenv("GRADLE_PLUGIN_VERSION")
-
-if (androidPluginVersionOverride != null) {
-    libs.gradle = 'com.android.tools.build:gradle:' + androidPluginVersionOverride
-} else {
-    // Keep gradle plugin version in sync with ub_supportlib-master manifest.
-    libs.gradle = 'com.android.tools.build:gradle:3.0.0'
-}
 
 //arch components
-libs.arch_lifecycle_runtime = "android.arch.lifecycle:runtime:1.0.0@aar"
+libs.arch_lifecycle_runtime = "android.arch.lifecycle:runtime:1.0.3@aar"
 
 // Other dependencies
 libs.xml_parser_apis = 'xerces:xmlParserAPIs:2.6.2'
 libs.xerces_impl = 'xerces:xercesImpl:2.6.2'
-libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.10'
-
-// jarjar plugin
-libs.jarjar_gradle = 'org.anarres.jarjar:jarjar-gradle:1.0.0'
 
 rootProject.ext['libs'] = libs
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index 44116d6..8d9dff3 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -165,7 +165,6 @@
         apply plugin: 'maven'
 
         version = LibraryVersions.SUPPORT_LIBRARY.toString();
-        group = 'com.android.support'
 
         project.plugins.whenPluginAdded { plugin ->
             def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin"
diff --git a/buildSrc/src/main/groovy/android/support/FlatfootAndroidLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/FlatfootAndroidLibraryPlugin.groovy
deleted file mode 100644
index c6abac2..0000000
--- a/buildSrc/src/main/groovy/android/support/FlatfootAndroidLibraryPlugin.groovy
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support
-
-import com.google.common.collect.ImmutableMap
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-
-/**
- * Flatfoot Android library specific plugin that sets common configurations needed for
- * flatfoot library modules.
- */
-class FlatfootAndroidLibraryPlugin implements Plugin<Project> {
-    @Override
-    public void apply(Project project) {
-        SupportLibraryExtension supportLibraryExtension =
-                project.extensions.create("supportLibrary", SupportLibraryExtension, project);
-        SupportLibraryMavenUploader.apply(project, supportLibraryExtension);
-        VersionFileWriterTask.setUpAndroidLibrary(project);
-
-        project.apply(ImmutableMap.of("plugin", "com.android.library"));
-    }
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/android/support/SupportAndroidLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportAndroidLibraryPlugin.groovy
index 2170a50..6f1288e 100644
--- a/buildSrc/src/main/groovy/android/support/SupportAndroidLibraryPlugin.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportAndroidLibraryPlugin.groovy
@@ -38,6 +38,8 @@
 
     @Override
     public void apply(Project project) {
+        KotlinNoOp noOp = new KotlinNoOp()
+        noOp.noOp()
         SupportLibraryExtension supportLibraryExtension =
                 project.extensions.create("supportLibrary", SupportLibraryExtension, project);
         SupportLibraryMavenUploader.apply(project, supportLibraryExtension);
@@ -45,6 +47,23 @@
         project.afterEvaluate {
             LibraryExtension library = project.extensions.findByType(LibraryExtension.class);
 
+            if (supportLibraryExtension.legacySourceLocation) {
+                library.sourceSets {
+                    main {
+                        // We use a non-standard manifest path.
+                        manifest.srcFile 'AndroidManifest.xml'
+                    }
+
+                    androidTest {
+                        // We use a non-standard test directory structure.
+                        root 'tests'
+                        java.srcDir 'tests/src'
+                        res.srcDir 'tests/res'
+                        manifest.srcFile 'tests/AndroidManifest.xml'
+                    }
+                }
+            }
+
             // Java 8 is only fully supported on API 24+ and not all Java 8 features are binary
             // compatible with API < 24, so use Java 7 for both source AND target.
             final JavaVersion javaVersion;
@@ -88,21 +107,6 @@
             }
         }
 
-        library.sourceSets {
-            main {
-                // We use a non-standard manifest path.
-                manifest.srcFile 'AndroidManifest.xml'
-            }
-
-            androidTest {
-                // We use a non-standard test directory structure.
-                root 'tests'
-                java.srcDir 'tests/src'
-                res.srcDir 'tests/res'
-                manifest.srcFile 'tests/AndroidManifest.xml'
-            }
-        }
-
         // Always lint check NewApi as fatal.
         library.lintOptions {
             abortOnError true
@@ -135,21 +139,7 @@
             project.uploadArchives.dependsOn "lintRelease"
         }
 
-        // Create sources jar for release builds
-        library.getLibraryVariants().all(new Action<LibraryVariant>() {
-            @Override
-            public void execute(LibraryVariant libraryVariant) {
-                if (!libraryVariant.getBuildType().getName().equals(BuilderConstants.RELEASE)) {
-                    return; // Skip non-release builds.
-                }
-
-                Jar sourceJar = project.getTasks().create("sourceJarRelease", Jar.class);
-                sourceJar.preserveFileTimestamps = false;
-                sourceJar.setClassifier("sources");
-                sourceJar.from(library.getSourceSets().findByName("main").getJava().getSrcDirs());
-                project.getArtifacts().add("archives", sourceJar);
-            }
-        });
+        SourceJarTaskHelper.setUpAndroidProject(project, library);
 
         final ErrorProneToolChain toolChain = ErrorProneToolChain.create(project);
         library.getBuildTypes().create("errorProne")
diff --git a/buildSrc/src/main/groovy/android/support/SupportJavaLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportJavaLibraryPlugin.groovy
index ae0d55c..3113e6c 100644
--- a/buildSrc/src/main/groovy/android/support/SupportJavaLibraryPlugin.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportJavaLibraryPlugin.groovy
@@ -20,6 +20,7 @@
 import org.gradle.api.JavaVersion
 import org.gradle.api.Plugin
 import org.gradle.api.Project
+import org.gradle.api.plugins.JavaPluginConvention
 
 /**
  * Support java library specific plugin that sets common configurations needed for
@@ -41,5 +42,7 @@
                 targetCompatibility = version
             }
         }
+
+        SourceJarTaskHelper.setUpJavaProject(project);
     }
 }
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
index 93afb9a..1dac034 100644
--- a/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
@@ -29,11 +29,13 @@
 
     Project project
     String name;
+    String mavenGroup;
     String description;
     String inceptionYear;
     String url = SUPPORT_URL;
     Collection<License> licenses = [];
     boolean java8Library = false;
+    boolean legacySourceLocation = false;
     boolean publish = false;
 
     SupportLibraryExtension(Project project) {
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy
index 957cae8..6b11a21 100644
--- a/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy
@@ -26,6 +26,15 @@
 
 class SupportLibraryMavenUploader {
     static void apply(Project project, SupportLibraryExtension supportLibraryExtension) {
+        project.afterEvaluate {
+            if (supportLibraryExtension.publish) {
+                if (supportLibraryExtension.mavenGroup == null) {
+                    throw Exception("You must specify mavenGroup for " + project.name + " project");
+                }
+                project.group = supportLibraryExtension.mavenGroup
+            }
+        }
+
         project.apply(ImmutableMap.of("plugin", "maven"));
 
         // Set uploadArchives options.
diff --git a/buildSrc/src/main/java/android/support/LibraryGroups.java b/buildSrc/src/main/java/android/support/LibraryGroups.java
new file mode 100644
index 0000000..feaefbc
--- /dev/null
+++ b/buildSrc/src/main/java/android/support/LibraryGroups.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support;
+
+/**
+ * The list of maven group names of all the libraries in this project.
+ */
+public class LibraryGroups {
+    public static final String SUPPORT = "com.android.support";
+    public static final String ROOM = "android.arch.persistence.room";
+    public static final String PERSISTENCE = "android.arch.persistence";
+    public static final String LIFECYCLE = "android.arch.lifecycle";
+    public static final String ARCH_CORE = "android.arch.core";
+    public static final String PAGING = "android.arch.paging";
+    public static final String NAVIGATION = "android.arch.navigation";
+}
diff --git a/buildSrc/src/main/java/android/support/LibraryVersions.java b/buildSrc/src/main/java/android/support/LibraryVersions.java
index 19d5d6d..64f1840 100644
--- a/buildSrc/src/main/java/android/support/LibraryVersions.java
+++ b/buildSrc/src/main/java/android/support/LibraryVersions.java
@@ -23,12 +23,12 @@
     /**
      * Version code of the support library components.
      */
-    public static final Version SUPPORT_LIBRARY = new Version("27.0.0");
+    public static final Version SUPPORT_LIBRARY = new Version("27.0.1");
 
     /**
      * Version code for flatfoot 1.0 projects (room, lifecycles)
      */
-    private static final Version FLATFOOT_1_0_BATCH = new Version("1.0.0-rc1");
+    private static final Version FLATFOOT_1_0_BATCH = new Version("1.0.0");
 
     /**
      * Version code for Room
diff --git a/buildSrc/src/main/java/android/support/SourceJarTaskHelper.java b/buildSrc/src/main/java/android/support/SourceJarTaskHelper.java
new file mode 100644
index 0000000..9fbd1db
--- /dev/null
+++ b/buildSrc/src/main/java/android/support/SourceJarTaskHelper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support;
+
+import com.android.build.gradle.LibraryExtension;
+import com.android.builder.core.BuilderConstants;
+
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaPluginConvention;
+import org.gradle.api.tasks.bundling.Jar;
+
+/**
+ * Helper class to handle creation of source jars.
+ */
+public class SourceJarTaskHelper {
+    /**
+     * Sets up a source jar task for an Android library project.
+     */
+    public static void setUpAndroidProject(Project project, LibraryExtension extension) {
+        // Create sources jar for release builds
+        extension.getLibraryVariants().all(libraryVariant -> {
+            if (!libraryVariant.getBuildType().getName().equals(BuilderConstants.RELEASE)) {
+                return; // Skip non-release builds.
+            }
+
+            Jar sourceJar = project.getTasks().create("sourceJarRelease", Jar.class);
+            sourceJar.setPreserveFileTimestamps(false);
+            sourceJar.setClassifier("sources");
+            sourceJar.from(extension.getSourceSets().findByName("main").getJava().getSrcDirs());
+            project.getArtifacts().add("archives", sourceJar);
+        });
+    }
+
+    /**
+     * Sets up a source jar task for a Java library project.
+     */
+    public static void setUpJavaProject(Project project) {
+        Jar sourceJar = project.getTasks().create("sourceJar", Jar.class);
+        sourceJar.setPreserveFileTimestamps(false);
+        sourceJar.setClassifier("sources");
+        JavaPluginConvention convention =
+                project.getConvention().getPlugin(JavaPluginConvention.class);
+        sourceJar.from(convention.getSourceSets().findByName("main").getAllSource().getSrcDirs());
+        project.getArtifacts().add("archives", sourceJar);
+    }
+}
diff --git a/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt b/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt
new file mode 100644
index 0000000..968f6ca
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support
+
+class KotlinNoOp {
+
+    fun noOp() {
+    }
+
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
new file mode 100644
index 0000000..222602b
--- /dev/null
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
@@ -0,0 +1 @@
+implementation-class=android.support.SupportAndroidLibraryPlugin
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
new file mode 100644
index 0000000..89755b7
--- /dev/null
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
@@ -0,0 +1 @@
+implementation-class=android.support.SupportJavaLibraryPlugin
\ No newline at end of file
diff --git a/compat/build.gradle b/compat/build.gradle
index 1e5d847..a01767a 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -30,8 +34,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library compat'
-    publish true
-    inceptionYear '2015'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library compat"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/content/build.gradle b/content/build.gradle
index af33423..8b12174 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -32,8 +36,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Content'
-    publish true
-    inceptionYear '2017'
-    description 'Library providing support for paging across content exposed via a ContentProvider. Use of this library allows a client to avoid expensive interprocess "cursor window swaps" on the UI thread.'
+    name = "Android Support Content"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2017"
+    description = "Library providing support for paging across content exposed via a ContentProvider. Use of this library allows a client to avoid expensive interprocess \"cursor window swaps\" on the UI thread."
+    legacySourceLocation = true
 }
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 38a4fe2..f0fb49a 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -22,8 +26,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library core UI'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library core UI"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index 55fe2bb..cb82dee 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -17,8 +21,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library core utils'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library core utils"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index fc90301..ade1bda 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -20,8 +24,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Custom Tabs'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support Custom Tabs'
+    name = "Android Support Custom Tabs"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support Custom Tabs"
+    legacySourceLocation = true
 }
diff --git a/design/build.gradle b/design/build.gradle
index 4a82051..55e6206 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-v4')
@@ -59,8 +63,10 @@
 }
 
 supportLibrary {
-    name 'Android Design Support Library'
-    publish true
-    inceptionYear '2015'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Design Support Library"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 220758d..e5ecdd2 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-core-utils')
@@ -16,8 +20,10 @@
 }
 
 supportLibrary {
-    name 'Android Support DynamicAnimation'
-    publish true
-    inceptionYear '2017'
-    description "Physics-based animation in support library, where the animations are driven by physics force. You can use this Animation library to create smooth and realistic animations."
+    name = "Android Support DynamicAnimation"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2017"
+    description = "Physics-based animation in support library, where the animations are driven by physics force. You can use this Animation library to create smooth and realistic animations."
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index e22000c..27818aa 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api fileTree(include: ['*.jar'], dir: 'libs')
@@ -29,8 +33,10 @@
 }
 
 supportLibrary {
-    name 'Android Emoji AppCompat'
-    publish true
-    inceptionYear '2017'
-    description 'EmojiCompat Widgets for AppCompat integration'
+    name = "Android Emoji AppCompat"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2017"
+    description = "EmojiCompat Widgets for AppCompat integration"
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatEditText.java b/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatEditText.java
index 87c17c2..0ae4ea0 100644
--- a/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatEditText.java
+++ b/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatEditText.java
@@ -21,6 +21,7 @@
 import android.support.annotation.Nullable;
 import android.support.text.emoji.EmojiCompat;
 import android.support.v7.widget.AppCompatEditText;
+import android.text.method.KeyListener;
 import android.util.AttributeSet;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -67,8 +68,11 @@
     }
 
     @Override
-    public void setKeyListener(android.text.method.KeyListener input) {
-        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+    public void setKeyListener(@Nullable KeyListener keyListener) {
+        if (keyListener != null) {
+            keyListener = getEmojiEditTextHelper().getKeyListener(keyListener);
+        }
+        super.setKeyListener(keyListener);
     }
 
     @Override
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index 766d165..2941f06 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 ext {
     fontDir = project(':noto-emoji-compat').projectDir
@@ -19,18 +23,20 @@
 }
 
 supportLibrary {
-    name 'Android Emoji Compat'
-    publish true
-    inceptionYear '2017'
-    description 'Library bundled with assets to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.'
+    name = "Android Emoji Compat"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2017"
+    description = "Library bundled with assets to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters."
 
     license {
-        name 'SIL Open Font License, Version 1.1'
-        url  'http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web'
+        name = "SIL Open Font License, Version 1.1"
+        url = "http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web"
     }
 
     license {
-        name 'Unicode, Inc. License'
-        url 'http://www.unicode.org/copyright.html#License'
+        name = "Unicode, Inc. License"
+        url = "http://www.unicode.org/copyright.html#License"
     }
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index b4cd3fc..f4ef90c 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 ext {
     fontDir = project(':noto-emoji-compat').projectDir
@@ -29,13 +33,22 @@
     }
 
     sourceSets {
-        main.res.srcDirs += 'src/main/res-public'
-        main.resources {
-            srcDirs = [fontDir.getAbsolutePath()]
-            includes = ["LICENSE_UNICODE", "LICENSE_OFL"]
+        main {
+            // We use a non-standard manifest path.
+            manifest.srcFile 'AndroidManifest.xml'
+            res.srcDirs += 'src/main/res-public'
+            resources {
+                srcDirs = [fontDir.getAbsolutePath()]
+                includes = ["LICENSE_UNICODE", "LICENSE_OFL"]
+            }
         }
 
         androidTest {
+            // We use a non-standard test directory structure.
+            root 'tests'
+            java.srcDir 'tests/src'
+            res.srcDir 'tests/res'
+            manifest.srcFile 'tests/AndroidManifest.xml'
             assets {
                 srcDirs = [new File(fontDir, "font").getAbsolutePath(),
                            new File(fontDir, "supported-emojis").getAbsolutePath()]
@@ -45,18 +58,19 @@
 }
 
 supportLibrary {
-    name 'Android Emoji Compat'
-    publish true
-    inceptionYear '2017'
-    description 'Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.'
+    name = "Android Emoji Compat"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2017"
+    description = "Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters."
 
     license {
-        name 'SIL Open Font License, Version 1.1'
-        url  'http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web'
+        name = "SIL Open Font License, Version 1.1"
+        url = "http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web"
     }
 
     license {
-        name 'Unicode, Inc. License'
-        url 'http://www.unicode.org/copyright.html#License'
+        name = "Unicode, Inc. License"
+        url = "http://www.unicode.org/copyright.html#License"
     }
 }
diff --git a/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditText.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditText.java
index a0e8a69..70ca7a6 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditText.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditText.java
@@ -21,6 +21,7 @@
 import android.support.annotation.IntRange;
 import android.support.annotation.Nullable;
 import android.support.text.emoji.EmojiCompat;
+import android.text.method.KeyListener;
 import android.util.AttributeSet;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -73,8 +74,11 @@
     }
 
     @Override
-    public void setKeyListener(android.text.method.KeyListener keyListener) {
-        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
+    public void setKeyListener(@Nullable KeyListener keyListener) {
+        if (keyListener != null) {
+            keyListener = getEmojiEditTextHelper().getKeyListener(keyListener);
+        }
+        super.setKeyListener(keyListener);
     }
 
     @Override
diff --git a/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractEditText.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractEditText.java
index ca1868e..2e4d3ca 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractEditText.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractEditText.java
@@ -27,6 +27,7 @@
 import android.support.annotation.RestrictTo;
 import android.support.text.emoji.EmojiCompat;
 import android.support.text.emoji.EmojiSpan;
+import android.text.method.KeyListener;
 import android.util.AttributeSet;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -81,8 +82,11 @@
     }
 
     @Override
-    public void setKeyListener(android.text.method.KeyListener keyListener) {
-        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
+    public void setKeyListener(@Nullable KeyListener keyListener) {
+        if (keyListener != null) {
+            keyListener = getEmojiEditTextHelper().getKeyListener(keyListener);
+        }
+        super.setKeyListener(keyListener);
     }
 
     @Override
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextTest.java
index e4b452c..3528095 100644
--- a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextTest.java
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextTest.java
@@ -21,11 +21,13 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 
 import android.annotation.TargetApi;
 import android.app.Instrumentation;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.rule.ActivityTestRule;
@@ -82,6 +84,15 @@
     }
 
     @Test
+    @UiThreadTest
+    public void testSetKeyListener_withNull() {
+        final TestActivity activity = mActivityRule.getActivity();
+        final EmojiEditText editText = activity.findViewById(R.id.editTextWithMaxCount);
+        editText.setKeyListener(null);
+        assertNull(editText.getKeyListener());
+    }
+
+    @Test
     @SdkSuppress(minSdkVersion = 19)
     @TargetApi(19)
     public void testSetMaxCount() {
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java
index 8e1c6cf..6ed9b8e 100644
--- a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java
@@ -18,6 +18,7 @@
 
 import static android.support.text.emoji.util.EmojiMatcher.sameCharSequence;
 
+import static junit.framework.Assert.assertNull;
 import static junit.framework.TestCase.assertFalse;
 
 import static org.junit.Assert.assertEquals;
@@ -88,6 +89,21 @@
 
     @Test
     @UiThreadTest
+    public void testSetKeyListener_withNull() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
+                .inflate(android.support.text.emoji.test.R.layout.extract_view, null);
+
+        final EmojiExtractEditText extractEditText = layout.findViewById(
+                android.R.id.inputExtractEditText);
+        assertNotNull(extractEditText);
+
+        extractEditText.setKeyListener(null);
+        assertNull(extractEditText.getKeyListener());
+    }
+
+    @Test
+    @UiThreadTest
     public void testSetEmojiReplaceStrategy() {
         final Context context = InstrumentationRegistry.getTargetContext();
 
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index 3e034b1..74333b2 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -13,8 +17,10 @@
 }
 
 supportLibrary {
-    name 'Android Support ExifInterface'
-    publish true
-    inceptionYear '2016'
-    description 'Android Support ExifInterface'
+    name = "Android Support ExifInterface"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2016"
+    description = "Android Support ExifInterface"
+    legacySourceLocation = true
 }
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 3a86f38..95886be 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -19,9 +23,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library fragment'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library fragment"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
-
diff --git a/fragment/src/main/java/android/support/v4/app/FragmentActivity.java b/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
index 614ff35..78161a8 100644
--- a/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
+++ b/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
@@ -536,7 +536,7 @@
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        markState(getSupportFragmentManager(), Lifecycle.State.CREATED);
+        markFragmentsCreated();
         Parcelable p = mFragments.saveAllState();
         if (p != null) {
             outState.putParcelable(FRAGMENTS_TAG, p);
@@ -591,7 +591,7 @@
         super.onStop();
 
         mStopped = true;
-        markState(getSupportFragmentManager(), Lifecycle.State.CREATED);
+        markFragmentsCreated();
         mHandler.sendEmptyMessage(MSG_REALLY_STOPPED);
 
         mFragments.dispatchStop();
@@ -970,18 +970,30 @@
         }
     }
 
-    private static void markState(FragmentManager manager, Lifecycle.State state) {
+    private void markFragmentsCreated() {
+        boolean reiterate;
+        do {
+            reiterate = markState(getSupportFragmentManager(), Lifecycle.State.CREATED);
+        } while (reiterate);
+    }
+
+    private static boolean markState(FragmentManager manager, Lifecycle.State state) {
+        boolean hadNotMarked = false;
         Collection<Fragment> fragments = manager.getFragments();
         for (Fragment fragment : fragments) {
             if (fragment == null) {
                 continue;
             }
-            fragment.mLifecycleRegistry.markState(state);
+            if (fragment.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
+                fragment.mLifecycleRegistry.markState(state);
+                hadNotMarked = true;
+            }
 
             FragmentManager childFragmentManager = fragment.peekChildFragmentManager();
             if (childFragmentManager != null) {
-                markState(childFragmentManager, state);
+                hadNotMarked |= markState(childFragmentManager, state);
             }
         }
+        return hadNotMarked;
     }
 }
diff --git a/fragment/tests/java/android/support/v4/app/FragmentArchLifecycleTest.java b/fragment/tests/java/android/support/v4/app/FragmentArchLifecycleTest.java
new file mode 100644
index 0000000..7e8ed1f
--- /dev/null
+++ b/fragment/tests/java/android/support/v4/app/FragmentArchLifecycleTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.LifecycleObserver;
+import android.arch.lifecycle.OnLifecycleEvent;
+import android.os.Bundle;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.test.EmptyFragmentTestActivity;
+
+import junit.framework.Assert;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class FragmentArchLifecycleTest {
+
+    @Rule
+    public ActivityTestRule<EmptyFragmentTestActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyFragmentTestActivity.class);
+
+    @Test
+    @UiThreadTest
+    public void testFragmentAdditionDuringOnStop() {
+        final EmptyFragmentTestActivity activity = mActivityRule.getActivity();
+        final FragmentManager fm = activity.getSupportFragmentManager();
+
+        final Fragment first = new Fragment();
+        final Fragment second = new Fragment();
+        fm.beginTransaction().add(first, "first").commitNow();
+        first.getLifecycle().addObserver(new LifecycleObserver() {
+            @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+            public void onStop() {
+                fm.beginTransaction().add(second, "second").commitNow();
+                first.getLifecycle().removeObserver(this);
+            }
+        });
+        activity.onSaveInstanceState(new Bundle());
+        Assert.assertEquals(Lifecycle.State.CREATED, first.getLifecycle().getCurrentState());
+        Assert.assertEquals(Lifecycle.State.CREATED, second.getLifecycle().getCurrentState());
+        Assert.assertEquals(Lifecycle.State.CREATED, activity.getLifecycle().getCurrentState());
+    }
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 6314766..96e6dab 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=../../../../tools/external/gradle/gradle-4.1-bin.zip
+distributionUrl=../../../../tools/external/gradle/gradle-4.3-bin.zip
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index 6036284..aa17f9b 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-vector-drawable')
@@ -25,8 +29,10 @@
 }
 
 supportLibrary {
-    name 'Android Support AnimatedVectorDrawable'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support AnimatedVectorDrawable'
+    name = "Android Support AnimatedVectorDrawable"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support AnimatedVectorDrawable"
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index 949ba89..c6b2584 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -20,8 +24,10 @@
 }
 
 supportLibrary {
-    name 'Android Support VectorDrawable'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support VectorDrawable'
-}
+    name = "Android Support VectorDrawable"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support VectorDrawable"
+    legacySourceLocation = true
+}
\ No newline at end of file
diff --git a/lifecycle/common-java8/api/1.0.0.txt b/lifecycle/common-java8/api/1.0.0.txt
new file mode 100644
index 0000000..f111850
--- /dev/null
+++ b/lifecycle/common-java8/api/1.0.0.txt
@@ -0,0 +1,13 @@
+package android.arch.lifecycle {
+
+  public abstract interface DefaultLifecycleObserver {
+    method public default void onCreate(android.arch.lifecycle.LifecycleOwner);
+    method public default void onDestroy(android.arch.lifecycle.LifecycleOwner);
+    method public default void onPause(android.arch.lifecycle.LifecycleOwner);
+    method public default void onResume(android.arch.lifecycle.LifecycleOwner);
+    method public default void onStart(android.arch.lifecycle.LifecycleOwner);
+    method public default void onStop(android.arch.lifecycle.LifecycleOwner);
+  }
+
+}
+
diff --git a/lifecycle/common-java8/build.gradle b/lifecycle/common-java8/build.gradle
index fccc813..d328cc3 100644
--- a/lifecycle/common-java8/build.gradle
+++ b/lifecycle/common-java8/build.gradle
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions;
 import android.support.SupportLibraryExtension;
 
-apply plugin: android.support.SupportJavaLibraryPlugin
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
 
 dependencies {
     testCompile libs.junit
@@ -30,10 +33,11 @@
 
 version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
-    name 'Android Lifecycle-Common for Java 8 Language'
-    publish true
-    inceptionYear '2017'
-    description "Android Lifecycle-Common for Java 8 Language"
-    url SupportLibraryExtension.ARCHITECTURE_URL
-    java8Library true
+    name = "Android Lifecycle-Common for Java 8 Language"
+    publish = true
+    mavenGroup = LibraryGroups.LIFECYCLE
+    inceptionYear = "2017"
+    description = "Android Lifecycle-Common for Java 8 Language"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
+    java8Library = true
 }
diff --git a/lifecycle/common/build.gradle b/lifecycle/common/build.gradle
index 57cfd00..107058b 100644
--- a/lifecycle/common/build.gradle
+++ b/lifecycle/common/build.gradle
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions;
 import android.support.SupportLibraryExtension;
 
-apply plugin: android.support.SupportJavaLibraryPlugin
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
 
 dependencies {
     testCompile libs.junit
@@ -29,9 +32,10 @@
 
 version = LibraryVersions.LIFECYCLES_CORE.toString()
 supportLibrary {
-    name 'Android Lifecycle-Common'
-    publish true
-    inceptionYear '2017'
-    description "Android Lifecycle-Common"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Lifecycle-Common"
+    publish = true
+    mavenGroup = LibraryGroups.LIFECYCLE
+    inceptionYear = "2017"
+    description = "Android Lifecycle-Common"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index e784f80..979d050 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -1,3 +1,4 @@
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 apply plugin: android.support.SupportKotlinLibraryPlugin
@@ -40,9 +41,10 @@
 }
 
 supportLibrary {
-    name 'Android Lifecycles Compiler'
-    publish true
-    inceptionYear '2017'
-    description "Android Lifecycles annotation processor"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Lifecycles Compiler"
+    publish = true
+    mavenGroup = LibraryGroups.LIFECYCLE
+    inceptionYear = "2017"
+    description = "Android Lifecycles annotation processor"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
diff --git a/lifecycle/extensions/api/1.0.0.txt b/lifecycle/extensions/api/1.0.0.txt
new file mode 100644
index 0000000..13a85ba
--- /dev/null
+++ b/lifecycle/extensions/api/1.0.0.txt
@@ -0,0 +1,121 @@
+package android.arch.lifecycle {
+
+  public class AndroidViewModel extends android.arch.lifecycle.ViewModel {
+    ctor public AndroidViewModel(android.app.Application);
+    method public <T extends android.app.Application> T getApplication();
+  }
+
+  public deprecated class LifecycleActivity extends android.support.v4.app.FragmentActivity {
+    ctor public LifecycleActivity();
+  }
+
+  public deprecated class LifecycleFragment extends android.support.v4.app.Fragment {
+    ctor public LifecycleFragment();
+  }
+
+  public class LifecycleService extends android.app.Service implements android.arch.lifecycle.LifecycleOwner {
+    ctor public LifecycleService();
+    method public android.arch.lifecycle.Lifecycle getLifecycle();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onStart(android.content.Intent, int);
+  }
+
+  public abstract class LiveData<T> {
+    ctor public LiveData();
+    method public T getValue();
+    method public boolean hasActiveObservers();
+    method public boolean hasObservers();
+    method public void observe(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.Observer<T>);
+    method public void observeForever(android.arch.lifecycle.Observer<T>);
+    method protected void onActive();
+    method protected void onInactive();
+    method protected void postValue(T);
+    method public void removeObserver(android.arch.lifecycle.Observer<T>);
+    method public void removeObservers(android.arch.lifecycle.LifecycleOwner);
+    method protected void setValue(T);
+  }
+
+  public class MediatorLiveData<T> extends android.arch.lifecycle.MutableLiveData {
+    ctor public MediatorLiveData();
+    method public <S> void addSource(android.arch.lifecycle.LiveData<S>, android.arch.lifecycle.Observer<S>);
+    method public <S> void removeSource(android.arch.lifecycle.LiveData<S>);
+  }
+
+  public class MutableLiveData<T> extends android.arch.lifecycle.LiveData {
+    ctor public MutableLiveData();
+    method public void postValue(T);
+    method public void setValue(T);
+  }
+
+  public abstract interface Observer<T> {
+    method public abstract void onChanged(T);
+  }
+
+  public class ProcessLifecycleOwner implements android.arch.lifecycle.LifecycleOwner {
+    method public static android.arch.lifecycle.LifecycleOwner get();
+    method public android.arch.lifecycle.Lifecycle getLifecycle();
+  }
+
+  public class ServiceLifecycleDispatcher {
+    ctor public ServiceLifecycleDispatcher(android.arch.lifecycle.LifecycleOwner);
+    method public android.arch.lifecycle.Lifecycle getLifecycle();
+    method public void onServicePreSuperOnBind();
+    method public void onServicePreSuperOnCreate();
+    method public void onServicePreSuperOnDestroy();
+    method public void onServicePreSuperOnStart();
+  }
+
+  public class Transformations {
+    method public static <X, Y> android.arch.lifecycle.LiveData<Y> map(android.arch.lifecycle.LiveData<X>, android.arch.core.util.Function<X, Y>);
+    method public static <X, Y> android.arch.lifecycle.LiveData<Y> switchMap(android.arch.lifecycle.LiveData<X>, android.arch.core.util.Function<X, android.arch.lifecycle.LiveData<Y>>);
+  }
+
+  public abstract class ViewModel {
+    ctor public ViewModel();
+    method protected void onCleared();
+  }
+
+  public class ViewModelProvider {
+    ctor public ViewModelProvider(android.arch.lifecycle.ViewModelStoreOwner, android.arch.lifecycle.ViewModelProvider.Factory);
+    ctor public ViewModelProvider(android.arch.lifecycle.ViewModelStore, android.arch.lifecycle.ViewModelProvider.Factory);
+    method public <T extends android.arch.lifecycle.ViewModel> T get(java.lang.Class<T>);
+    method public <T extends android.arch.lifecycle.ViewModel> T get(java.lang.String, java.lang.Class<T>);
+  }
+
+  public static abstract interface ViewModelProvider.Factory {
+    method public abstract <T extends android.arch.lifecycle.ViewModel> T create(java.lang.Class<T>);
+  }
+
+  public static class ViewModelProvider.NewInstanceFactory implements android.arch.lifecycle.ViewModelProvider.Factory {
+    ctor public ViewModelProvider.NewInstanceFactory();
+    method public <T extends android.arch.lifecycle.ViewModel> T create(java.lang.Class<T>);
+  }
+
+  public class ViewModelProviders {
+    ctor public ViewModelProviders();
+    method public static android.arch.lifecycle.ViewModelProvider of(android.support.v4.app.Fragment);
+    method public static android.arch.lifecycle.ViewModelProvider of(android.support.v4.app.FragmentActivity);
+    method public static android.arch.lifecycle.ViewModelProvider of(android.support.v4.app.Fragment, android.arch.lifecycle.ViewModelProvider.Factory);
+    method public static android.arch.lifecycle.ViewModelProvider of(android.support.v4.app.FragmentActivity, android.arch.lifecycle.ViewModelProvider.Factory);
+  }
+
+  public static class ViewModelProviders.DefaultFactory extends android.arch.lifecycle.ViewModelProvider.NewInstanceFactory {
+    ctor public ViewModelProviders.DefaultFactory(android.app.Application);
+  }
+
+  public class ViewModelStore {
+    ctor public ViewModelStore();
+    method public final void clear();
+  }
+
+  public abstract interface ViewModelStoreOwner {
+    method public abstract android.arch.lifecycle.ViewModelStore getViewModelStore();
+  }
+
+  public class ViewModelStores {
+    method public static android.arch.lifecycle.ViewModelStore of(android.support.v4.app.FragmentActivity);
+    method public static android.arch.lifecycle.ViewModelStore of(android.support.v4.app.Fragment);
+  }
+
+}
+
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index 79be36c..50c2744 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -14,20 +14,17 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     buildTypes.all {
@@ -58,9 +55,10 @@
 
 version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
-    name 'Android Lifecycle Extensions'
-    publish true
-    inceptionYear '2017'
-    description "Android Lifecycle Extensions"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Lifecycle Extensions"
+    publish = true
+    mavenGroup = LibraryGroups.LIFECYCLE
+    inceptionYear = "2017"
+    description = "Android Lifecycle Extensions"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/lifecycle/extensions/lint-baseline.xml b/lifecycle/extensions/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/lifecycle/extensions/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/AndroidViewModel.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/AndroidViewModel.java
index 106b2ef..e8895bd 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/AndroidViewModel.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/AndroidViewModel.java
@@ -37,6 +37,7 @@
     /**
      * Return the application.
      */
+    @SuppressWarnings("TypeParameterUnusedInFormals")
     @NonNull
     public <T extends Application> T getApplication() {
         //noinspection unchecked
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProvider.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProvider.java
index 29cbab8..a7b3aeb 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProvider.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProvider.java
@@ -138,6 +138,7 @@
      */
     public static class NewInstanceFactory implements Factory {
 
+        @SuppressWarnings("ClassNewInstance")
         @NonNull
         @Override
         public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
diff --git a/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java b/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java
index 647d5d7..c1dc54d 100644
--- a/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java
+++ b/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java
@@ -45,6 +45,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mockito;
 
@@ -52,11 +53,22 @@
 @RunWith(JUnit4.class)
 public class LiveDataTest {
     private PublicLiveData<String> mLiveData;
-    private LifecycleOwner mOwner;
-    private LifecycleOwner mOwner2;
-    private LifecycleRegistry mRegistry;
-    private LifecycleRegistry mRegistry2;
     private MethodExec mActiveObserversChanged;
+
+    private LifecycleOwner mOwner;
+    private LifecycleRegistry mRegistry;
+
+    private LifecycleOwner mOwner2;
+    private LifecycleRegistry mRegistry2;
+
+    private LifecycleOwner mOwner3;
+    private Lifecycle mLifecycle3;
+    private Observer<String> mObserver3;
+
+    private LifecycleOwner mOwner4;
+    private Lifecycle mLifecycle4;
+    private Observer<String> mObserver4;
+
     private boolean mInObserver;
 
     @Before
@@ -67,12 +79,10 @@
         mLiveData.activeObserversChanged = mActiveObserversChanged;
 
         mOwner = mock(LifecycleOwner.class);
-
         mRegistry = new LifecycleRegistry(mOwner);
         when(mOwner.getLifecycle()).thenReturn(mRegistry);
 
         mOwner2 = mock(LifecycleOwner.class);
-
         mRegistry2 = new LifecycleRegistry(mOwner2);
         when(mOwner2.getLifecycle()).thenReturn(mRegistry2);
 
@@ -80,6 +90,19 @@
     }
 
     @Before
+    public void initNonLifecycleRegistry() {
+        mOwner3 = mock(LifecycleOwner.class);
+        mLifecycle3 = mock(Lifecycle.class);
+        mObserver3 = (Observer<String>) mock(Observer.class);
+        when(mOwner3.getLifecycle()).thenReturn(mLifecycle3);
+
+        mOwner4 = mock(LifecycleOwner.class);
+        mLifecycle4 = mock(Lifecycle.class);
+        mObserver4 = (Observer<String>) mock(Observer.class);
+        when(mOwner4.getLifecycle()).thenReturn(mLifecycle4);
+    }
+
+    @Before
     public void swapExecutorDelegate() {
         ArchTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
     }
@@ -572,100 +595,195 @@
         verify(mActiveObserversChanged, never()).onCall(anyBoolean());
     }
 
-    /**
-     * Verifies that if a lifecycle's state changes without an event, and changes to something that
-     * LiveData would become inactive in response to, LiveData will detect the change upon new data
-     * being set and become inactive.  Also verifies that once the lifecycle enters into a state
-     * that LiveData should become active to, that it does indeed become active.
-     */
     @Test
-    public void liveDataActiveStateIsManagedCorrectlyWithoutEvent_oneObserver() {
-        Observer<String> observer = (Observer<String>) mock(Observer.class);
-        mLiveData.observe(mOwner, observer);
+    public void setValue_lifecycleIsCreatedNoEvent_liveDataBecomesInactiveAndObserverNotCalled() {
 
-        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
+        // Arrange.
 
-        // Marking state as CREATED should call onInactive.
+        mLiveData.observe(mOwner3, mObserver3);
+
+        GenericLifecycleObserver lifecycleObserver = getGenericLifecycleObserver(mLifecycle3);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
+
         reset(mActiveObserversChanged);
-        mRegistry.markState(Lifecycle.State.CREATED);
-        verify(mActiveObserversChanged).onCall(false);
-        reset(mActiveObserversChanged);
+        reset(mObserver3);
 
-        // Setting a new value should trigger LiveData to realize the Lifecycle it is observing
-        // is in a state where the LiveData should be inactive, so the LiveData will call onInactive
-        // and the Observer shouldn't be affected.
+        // Act.
+
         mLiveData.setValue("1");
 
-        // state is already CREATED so should not call again
-        verify(mActiveObserversChanged, never()).onCall(anyBoolean());
-        verify(observer, never()).onChanged(anyString());
+        // Assert.
 
-        // Sanity check.  Because we've only marked the state as CREATED, sending ON_START
-        // should re-dispatch events.
-        reset(mActiveObserversChanged);
-        reset(observer);
-        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
-        verify(mActiveObserversChanged).onCall(true);
-        verify(observer).onChanged("1");
+        verify(mActiveObserversChanged).onCall(false);
+        verify(mObserver3, never()).onChanged(anyString());
     }
 
-    /**
-     *  This test verifies that LiveData will detect changes in LifecycleState that would make it
-     *  inactive upon the setting of new data, but only if all of the Lifecycles it's observing
-     *  are all in those states.  It also makes sure that once it is inactive, that it will become
-     *  active again once one of the lifecycles it's observing moves to an appropriate state.
+    /*
+     * Arrange: LiveData was made inactive via SetValue (because the Lifecycle it was
+     * observing was in the CREATED state and no event was dispatched).
+     * Act: Lifecycle enters Started state and dispatches event.
+     * Assert: LiveData becomes active and dispatches new value to observer.
      */
     @Test
-    public void liveDataActiveStateIsManagedCorrectlyWithoutEvent_twoObservers() {
-        Observer<String> observer1 = mock(Observer.class);
-        Observer<String> observer2 = mock(Observer.class);
+    public void test_liveDataInactiveViaSetValueThenLifecycleResumes() {
 
-        mLiveData.observe(mOwner, observer1);
-        mLiveData.observe(mOwner2, observer2);
+        // Arrange.
 
-        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
-        mRegistry2.handleLifecycleEvent(Lifecycle.Event.ON_START);
+        mLiveData.observe(mOwner3, mObserver3);
 
-        // Marking the state to created won't change LiveData to be inactive.
-        reset(mActiveObserversChanged);
-        mRegistry.markState(Lifecycle.State.CREATED);
-        verify(mActiveObserversChanged, never()).onCall(anyBoolean());
+        GenericLifecycleObserver lifecycleObserver = getGenericLifecycleObserver(mLifecycle3);
 
-        // After setting a value, the LiveData will stay active because there is still a STARTED
-        // lifecycle being observed.  The one Observer associated with the STARTED lifecycle will
-        // also have been called, but the other Observer will not have been called.
-        reset(observer1);
-        reset(observer2);
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
         mLiveData.setValue("1");
-        verify(mActiveObserversChanged, never()).onCall(anyBoolean());
-        verify(observer1, never()).onChanged(anyString());
-        verify(observer2).onChanged("1");
 
-        // Now we set the other Lifecycle to be inactive, live data should become inactive.
-        reset(observer1);
-        reset(observer2);
-        mRegistry2.markState(Lifecycle.State.CREATED);
-        verify(mActiveObserversChanged).onCall(false);
-        verify(observer1, never()).onChanged(anyString());
-        verify(observer2, never()).onChanged(anyString());
-
-        // Now we post another value, because both lifecycles are in the Created state, live data
-        // will not dispatch any values
         reset(mActiveObserversChanged);
-        mLiveData.setValue("2");
-        verify(mActiveObserversChanged, never()).onCall(anyBoolean());
-        verify(observer1, never()).onChanged(anyString());
-        verify(observer2, never()).onChanged(anyString());
+        reset(mObserver3);
 
-        // Now that the first Lifecycle has been moved back to the Resumed state, the LiveData will
-        // be made active and it's associated Observer will be called with the new value, but the
-        // Observer associated with the Lifecycle that is still in the Created state won't be
-        // called.
-        reset(mActiveObserversChanged);
-        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+        // Act.
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+
+        // Assert.
+
         verify(mActiveObserversChanged).onCall(true);
-        verify(observer1).onChanged("2");
-        verify(observer2, never()).onChanged(anyString());
+        verify(mObserver3).onChanged("1");
+    }
+
+    /*
+     * Arrange: One of two Lifecycles enter the CREATED state without sending an event.
+     * Act: Lifecycle's setValue method is called with new value.
+     * Assert: LiveData stays active and new value is dispatched to Lifecycle that is still at least
+     * STARTED.
+     */
+    @Test
+    public void setValue_oneOfTwoLifecyclesAreCreatedNoEvent() {
+
+        // Arrange.
+
+        mLiveData.observe(mOwner3, mObserver3);
+        mLiveData.observe(mOwner4, mObserver4);
+
+        GenericLifecycleObserver lifecycleObserver3 = getGenericLifecycleObserver(mLifecycle3);
+        GenericLifecycleObserver lifecycleObserver4 = getGenericLifecycleObserver(mLifecycle4);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+        lifecycleObserver4.onStateChanged(mOwner4, Lifecycle.Event.ON_START);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
+
+        reset(mActiveObserversChanged);
+        reset(mObserver3);
+        reset(mObserver4);
+
+        // Act.
+
+        mLiveData.setValue("1");
+
+        // Assert.
+
+        verify(mActiveObserversChanged, never()).onCall(anyBoolean());
+        verify(mObserver3, never()).onChanged(anyString());
+        verify(mObserver4).onChanged("1");
+    }
+
+    /*
+     * Arrange: Two observed Lifecycles enter the CREATED state without sending an event.
+     * Act: Lifecycle's setValue method is called with new value.
+     * Assert: LiveData becomes inactive and nothing is dispatched to either observer.
+     */
+    @Test
+    public void setValue_twoLifecyclesAreCreatedNoEvent() {
+
+        // Arrange.
+
+        mLiveData.observe(mOwner3, mObserver3);
+        mLiveData.observe(mOwner4, mObserver4);
+
+        GenericLifecycleObserver lifecycleObserver3 = getGenericLifecycleObserver(mLifecycle3);
+        GenericLifecycleObserver lifecycleObserver4 = getGenericLifecycleObserver(mLifecycle4);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+        lifecycleObserver4.onStateChanged(mOwner4, Lifecycle.Event.ON_START);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
+        when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
+
+        reset(mActiveObserversChanged);
+        reset(mObserver3);
+        reset(mObserver4);
+
+        // Act.
+
+        mLiveData.setValue("1");
+
+        // Assert.
+
+        verify(mActiveObserversChanged).onCall(false);
+        verify(mObserver3, never()).onChanged(anyString());
+        verify(mObserver3, never()).onChanged(anyString());
+    }
+
+    /*
+     * Arrange: LiveData was made inactive via SetValue (because both Lifecycles it was
+     * observing were in the CREATED state and no event was dispatched).
+     * Act: One Lifecycle enters STARTED state and dispatches lifecycle event.
+     * Assert: LiveData becomes active and dispatches new value to observer associated with started
+     * Lifecycle.
+     */
+    @Test
+    public void test_liveDataInactiveViaSetValueThenOneLifecycleResumes() {
+
+        // Arrange.
+
+        mLiveData.observe(mOwner3, mObserver3);
+        mLiveData.observe(mOwner4, mObserver4);
+
+        GenericLifecycleObserver lifecycleObserver3 = getGenericLifecycleObserver(mLifecycle3);
+        GenericLifecycleObserver lifecycleObserver4 = getGenericLifecycleObserver(mLifecycle4);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+        lifecycleObserver4.onStateChanged(mOwner4, Lifecycle.Event.ON_START);
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
+        when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
+
+        mLiveData.setValue("1");
+
+        reset(mActiveObserversChanged);
+        reset(mObserver3);
+        reset(mObserver4);
+
+        // Act.
+
+        when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
+        lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
+
+        // Assert.
+
+        verify(mActiveObserversChanged).onCall(true);
+        verify(mObserver3).onChanged("1");
+        verify(mObserver4, never()).onChanged(anyString());
+    }
+
+    private GenericLifecycleObserver getGenericLifecycleObserver(Lifecycle lifecycle) {
+        ArgumentCaptor<GenericLifecycleObserver> captor =
+                ArgumentCaptor.forClass(GenericLifecycleObserver.class);
+        verify(lifecycle).addObserver(captor.capture());
+        return (captor.getValue());
     }
 
     @SuppressWarnings("WeakerAccess")
diff --git a/lifecycle/gradle/wrapper/gradle-wrapper.properties b/lifecycle/gradle/wrapper/gradle-wrapper.properties
index 467c103..b519e0a 100644
--- a/lifecycle/gradle/wrapper/gradle-wrapper.properties
+++ b/lifecycle/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4-bin.zip
diff --git a/lifecycle/reactivestreams/api/1.0.0.txt b/lifecycle/reactivestreams/api/1.0.0.txt
new file mode 100644
index 0000000..4a509e9
--- /dev/null
+++ b/lifecycle/reactivestreams/api/1.0.0.txt
@@ -0,0 +1,9 @@
+package android.arch.lifecycle {
+
+  public final class LiveDataReactiveStreams {
+    method public static <T> android.arch.lifecycle.LiveData<T> fromPublisher(org.reactivestreams.Publisher<T>);
+    method public static <T> org.reactivestreams.Publisher<T> toPublisher(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.LiveData<T>);
+  }
+
+}
+
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index bd64a32..1f375e1 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -14,20 +14,17 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     testOptions {
@@ -58,9 +55,10 @@
 
 version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
-    name 'Android Lifecycle Reactivestreams'
-    publish true
-    inceptionYear '2017'
-    description "Android Lifecycle Reactivestreams"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Lifecycle Reactivestreams"
+    publish = true
+    mavenGroup = LibraryGroups.LIFECYCLE
+    inceptionYear = "2017"
+    description = "Android Lifecycle Reactivestreams"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/lifecycle/reactivestreams/lint-baseline.xml b/lifecycle/reactivestreams/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/lifecycle/reactivestreams/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
index 2b25bc9..ba76f8e 100644
--- a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
+++ b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
@@ -24,7 +24,7 @@
 import org.reactivestreams.Subscriber;
 import org.reactivestreams.Subscription;
 
-import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Adapts {@link LiveData} input and output to the ReactiveStreams spec.
@@ -53,83 +53,114 @@
     public static <T> Publisher<T> toPublisher(
             final LifecycleOwner lifecycle, final LiveData<T> liveData) {
 
-        return new Publisher<T>() {
+        return new LiveDataPublisher<>(lifecycle, liveData);
+    }
+
+    private static final class LiveDataPublisher<T> implements Publisher<T> {
+        final LifecycleOwner mLifecycle;
+        final LiveData<T> mLiveData;
+
+        LiveDataPublisher(final LifecycleOwner lifecycle, final LiveData<T> liveData) {
+            this.mLifecycle = lifecycle;
+            this.mLiveData = liveData;
+        }
+
+        @Override
+        public void subscribe(Subscriber<? super T> subscriber) {
+            subscriber.onSubscribe(new LiveDataSubscription<T>(subscriber, mLifecycle, mLiveData));
+        }
+
+        static final class LiveDataSubscription<T> implements Subscription, Observer<T> {
+            final Subscriber<? super T> mSubscriber;
+            final LifecycleOwner mLifecycle;
+            final LiveData<T> mLiveData;
+
+            volatile boolean mCanceled;
+            // used on main thread only
             boolean mObserving;
-            boolean mCanceled;
             long mRequested;
+            // used on main thread only
             @Nullable
             T mLatest;
 
+            LiveDataSubscription(final Subscriber<? super T> subscriber,
+                    final LifecycleOwner lifecycle, final LiveData<T> liveData) {
+                this.mSubscriber = subscriber;
+                this.mLifecycle = lifecycle;
+                this.mLiveData = liveData;
+            }
+
             @Override
-            public void subscribe(final Subscriber<? super T> subscriber) {
-                final Observer<T> observer = new Observer<T>() {
+            public void onChanged(T t) {
+                if (mCanceled) {
+                    return;
+                }
+                if (mRequested > 0) {
+                    mLatest = null;
+                    mSubscriber.onNext(t);
+                    if (mRequested != Long.MAX_VALUE) {
+                        mRequested--;
+                    }
+                } else {
+                    mLatest = t;
+                }
+            }
+
+            @Override
+            public void request(final long n) {
+                if (mCanceled) {
+                    return;
+                }
+                ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
                     @Override
-                    public void onChanged(@Nullable T t) {
+                    public void run() {
                         if (mCanceled) {
                             return;
                         }
-                        if (mRequested > 0) {
+                        if (n <= 0L) {
+                            mCanceled = true;
+                            if (mObserving) {
+                                mLiveData.removeObserver(LiveDataSubscription.this);
+                                mObserving = false;
+                            }
                             mLatest = null;
-                            subscriber.onNext(t);
-                            if (mRequested != Long.MAX_VALUE) {
-                                mRequested--;
-                            }
-                        } else {
-                            mLatest = t;
-                        }
-                    }
-                };
-
-                subscriber.onSubscribe(new Subscription() {
-                    @Override
-                    public void request(final long n) {
-                        if (n < 0 || mCanceled) {
+                            mSubscriber.onError(
+                                    new IllegalArgumentException("Non-positive request"));
                             return;
                         }
-                        ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
-                            @Override
-                            public void run() {
-                                if (mCanceled) {
-                                    return;
-                                }
-                                // Prevent overflowage.
-                                mRequested = mRequested + n >= mRequested
-                                        ? mRequested + n : Long.MAX_VALUE;
-                                if (!mObserving) {
-                                    mObserving = true;
-                                    liveData.observe(lifecycle, observer);
-                                } else if (mLatest != null) {
-                                    observer.onChanged(mLatest);
-                                    mLatest = null;
-                                }
-                            }
-                        });
-                    }
 
-                    @Override
-                    public void cancel() {
-                        if (mCanceled) {
-                            return;
+                        // Prevent overflowage.
+                        mRequested = mRequested + n >= mRequested
+                                ? mRequested + n : Long.MAX_VALUE;
+                        if (!mObserving) {
+                            mObserving = true;
+                            mLiveData.observe(mLifecycle, LiveDataSubscription.this);
+                        } else if (mLatest != null) {
+                            onChanged(mLatest);
+                            mLatest = null;
                         }
-                        ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
-                            @Override
-                            public void run() {
-                                if (mCanceled) {
-                                    return;
-                                }
-                                if (mObserving) {
-                                    liveData.removeObserver(observer);
-                                    mObserving = false;
-                                }
-                                mLatest = null;
-                                mCanceled = true;
-                            }
-                        });
                     }
                 });
             }
 
-        };
+            @Override
+            public void cancel() {
+                if (mCanceled) {
+                    return;
+                }
+                mCanceled = true;
+                ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mObserving) {
+                            mLiveData.removeObserver(LiveDataSubscription.this);
+                            mObserving = false;
+                        }
+                        mLatest = null;
+                    }
+                });
+            }
+        }
     }
 
     /**
@@ -145,6 +176,10 @@
      * Therefore, in the case of a hot RxJava Observable, when a new LiveData {@link Observer} is
      * added, it will automatically notify with the last value held in LiveData,
      * which might not be the last value emitted by the Publisher.
+     * <p>
+     * Note that LiveData does NOT handle errors and it expects that errors are treated as states
+     * in the data that's held. In case of an error being emitted by the publisher, an error will
+     * be propagated to the main thread and the app will crash.
      *
      * @param <T> The type of data hold by this instance.
      */
@@ -166,67 +201,80 @@
      * added, it will automatically notify with the last value held in LiveData,
      * which might not be the last value emitted by the Publisher.
      *
+     * <p>
+     * Note that LiveData does NOT handle errors and it expects that errors are treated as states
+     * in the data that's held. In case of an error being emitted by the publisher, an error will
+     * be propagated to the main thread and the app will crash.
+     *
      * @param <T> The type of data hold by this instance.
      */
     private static class PublisherLiveData<T> extends LiveData<T> {
-        private WeakReference<Subscription> mSubscriptionRef;
         private final Publisher mPublisher;
-        private final Object mLock = new Object();
+        final AtomicReference<LiveDataSubscriber> mSubscriber;
 
         PublisherLiveData(@NonNull final Publisher publisher) {
             mPublisher = publisher;
+            mSubscriber = new AtomicReference<>();
         }
 
         @Override
         protected void onActive() {
             super.onActive();
-
-            mPublisher.subscribe(new Subscriber<T>() {
-                @Override
-                public void onSubscribe(Subscription s) {
-                    // Don't worry about backpressure. If the stream is too noisy then
-                    // backpressure can be handled upstream.
-                    synchronized (mLock) {
-                        s.request(Long.MAX_VALUE);
-                        mSubscriptionRef = new WeakReference<>(s);
-                    }
-                }
-
-                @Override
-                public void onNext(final T t) {
-                    postValue(t);
-                }
-
-                @Override
-                public void onError(Throwable t) {
-                    synchronized (mLock) {
-                        mSubscriptionRef = null;
-                    }
-                    // Errors should be handled upstream, so propagate as a crash.
-                    throw new RuntimeException(t);
-                }
-
-                @Override
-                public void onComplete() {
-                    synchronized (mLock) {
-                        mSubscriptionRef = null;
-                    }
-                }
-            });
-
+            LiveDataSubscriber s = new LiveDataSubscriber();
+            mSubscriber.set(s);
+            mPublisher.subscribe(s);
         }
 
         @Override
         protected void onInactive() {
             super.onInactive();
-            synchronized (mLock) {
-                WeakReference<Subscription> subscriptionRef = mSubscriptionRef;
-                if (subscriptionRef != null) {
-                    Subscription subscription = subscriptionRef.get();
-                    if (subscription != null) {
-                        subscription.cancel();
+            LiveDataSubscriber s = mSubscriber.getAndSet(null);
+            if (s != null) {
+                s.cancelSubscription();
+            }
+        }
+
+        final class LiveDataSubscriber extends AtomicReference<Subscription>
+                implements Subscriber<T> {
+
+            @Override
+            public void onSubscribe(Subscription s) {
+                if (compareAndSet(null, s)) {
+                    s.request(Long.MAX_VALUE);
+                } else {
+                    s.cancel();
+                }
+            }
+
+            @Override
+            public void onNext(T item) {
+                postValue(item);
+            }
+
+            @Override
+            public void onError(final Throwable ex) {
+                mSubscriber.compareAndSet(this, null);
+
+                ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        // Errors should be handled upstream, so propagate as a crash.
+                        throw new RuntimeException("LiveData does not handle errors. Errors from "
+                                + "publishers should be handled upstream and propagated as "
+                                + "state", ex);
                     }
-                    mSubscriptionRef = null;
+                });
+            }
+
+            @Override
+            public void onComplete() {
+                mSubscriber.compareAndSet(this, null);
+            }
+
+            public void cancelSubscription() {
+                Subscription s = get();
+                if (s != null) {
+                    s.cancel();
                 }
             }
         }
diff --git a/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java b/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
index 7278847..83e543c 100644
--- a/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
+++ b/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
@@ -16,6 +16,9 @@
 
 package android.arch.lifecycle;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
@@ -34,6 +37,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import io.reactivex.Flowable;
 import io.reactivex.disposables.Disposable;
@@ -115,6 +119,41 @@
     }
 
     @Test
+    public void convertsFromPublisherSubscribeWithDelay() {
+        PublishProcessor<String> processor = PublishProcessor.create();
+        processor.delaySubscription(100, TimeUnit.SECONDS, sBackgroundScheduler);
+        LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
+
+        liveData.observe(mLifecycleOwner, mObserver);
+
+        processor.onNext("foo");
+        liveData.removeObserver(mObserver);
+        sBackgroundScheduler.triggerActions();
+        liveData.observe(mLifecycleOwner, mObserver);
+
+        processor.onNext("bar");
+        processor.onNext("baz");
+
+        assertThat(mLiveDataOutput, is(Arrays.asList("foo", "foo", "bar", "baz")));
+    }
+
+    @Test
+    public void convertsFromPublisherThrowsException() {
+        PublishProcessor<String> processor = PublishProcessor.create();
+        LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
+
+        liveData.observe(mLifecycleOwner, mObserver);
+
+        IllegalStateException exception = new IllegalStateException("test exception");
+        try {
+            processor.onError(exception);
+            fail("Runtime Exception expected");
+        } catch (RuntimeException ex) {
+            assertEquals(ex.getCause(), exception);
+        }
+    }
+
+    @Test
     public void convertsFromPublisherWithMultipleObservers() {
         final List<String> output2 = new ArrayList<>();
         PublishProcessor<String> processor = PublishProcessor.create();
@@ -125,7 +164,7 @@
         processor.onNext("foo");
         processor.onNext("bar");
 
-        // The second mObserver should only get the newest value and any later values.
+        // The second observer should only get the newest value and any later values.
         liveData.observe(mLifecycleOwner, new Observer<String>() {
             @Override
             public void onChanged(@Nullable String s) {
@@ -140,6 +179,32 @@
     }
 
     @Test
+    public void convertsFromPublisherWithMultipleObserversAfterInactive() {
+        final List<String> output2 = new ArrayList<>();
+        PublishProcessor<String> processor = PublishProcessor.create();
+        LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
+
+        liveData.observe(mLifecycleOwner, mObserver);
+
+        processor.onNext("foo");
+        processor.onNext("bar");
+
+        // The second observer should only get the newest value and any later values.
+        liveData.observe(mLifecycleOwner, new Observer<String>() {
+            @Override
+            public void onChanged(@Nullable String s) {
+                output2.add(s);
+            }
+        });
+
+        liveData.removeObserver(mObserver);
+        processor.onNext("baz");
+
+        assertThat(mLiveDataOutput, is(Arrays.asList("foo", "bar")));
+        assertThat(output2, is(Arrays.asList("bar", "baz")));
+    }
+
+    @Test
     public void convertsFromPublisherAfterInactive() {
         PublishProcessor<String> processor = PublishProcessor.create();
         LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
@@ -156,7 +221,7 @@
     }
 
     @Test
-    public void convertsFromPublisherManagesSubcriptions() {
+    public void convertsFromPublisherManagesSubscriptions() {
         PublishProcessor<String> processor = PublishProcessor.create();
         LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
 
@@ -198,7 +263,7 @@
 
         assertThat(
                 mOutputProcessor.getValues(new String[]{}),
-                is(new String[] {"foo", "bar", "baz"}));
+                is(new String[]{"foo", "bar", "baz"}));
     }
 
     @Test
@@ -263,10 +328,10 @@
         final Subscription subscription = subscriptionSubject.blockingSingle();
 
         subscription.request(1);
-        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[] {}));
+        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[]{}));
 
         liveData.setValue("foo");
-        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[] {"foo"}));
+        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[]{"foo"}));
 
         subscription.request(2);
         liveData.setValue("baz");
@@ -274,7 +339,7 @@
 
         assertThat(
                 mOutputProcessor.getValues(new String[]{}),
-                is(new String[] {"foo", "baz", "fizz"}));
+                is(new String[]{"foo", "baz", "fizz"}));
 
         // 'nyan' will be dropped as there is nothing currently requesting a stream.
         liveData.setValue("nyan");
@@ -282,13 +347,13 @@
 
         assertThat(
                 mOutputProcessor.getValues(new String[]{}),
-                is(new String[] {"foo", "baz", "fizz"}));
+                is(new String[]{"foo", "baz", "fizz"}));
 
         // When a new request comes in, the latest value will be pushed.
         subscription.request(1);
         assertThat(
                 mOutputProcessor.getValues(new String[]{}),
-                is(new String[] {"foo", "baz", "fizz", "cat"}));
+                is(new String[]{"foo", "baz", "fizz", "cat"}));
     }
 
     @Test
@@ -301,17 +366,17 @@
 
         liveData.setValue("foo");
 
-        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[] {}));
+        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[]{}));
         sBackgroundScheduler.triggerActions();
-        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[] {"foo"}));
+        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[]{"foo"}));
 
         liveData.setValue("bar");
         liveData.setValue("baz");
 
-        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[] {"foo"}));
+        assertThat(mOutputProcessor.getValues(new String[]{}), is(new String[]{"foo"}));
         sBackgroundScheduler.triggerActions();
         assertThat(mOutputProcessor.getValues(
                 new String[]{}),
-                is(new String[] {"foo", "bar", "baz"}));
+                is(new String[]{"foo", "bar", "baz"}));
     }
 }
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index 111429c..4084d58 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -1,18 +1,14 @@
+import android.support.LibraryGroups
 import android.support.LibraryVersions
-
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     buildTypes.all {
@@ -43,6 +39,7 @@
 supportLibrary {
     name 'Android Lifecycle Runtime'
     publish true
+    mavenGroup LibraryGroups.LIFECYCLE
     inceptionYear '2017'
     description "Android Lifecycle Runtime"
     url SupportLibraryExtension.ARCHITECTURE_URL
diff --git a/lifecycle/runtime/lint-baseline.xml b/lifecycle/runtime/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/lifecycle/runtime/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/media-compat-test-client/build.gradle b/media-compat-test-client/build.gradle
index e4cec1d..47141db 100644
--- a/media-compat-test-client/build.gradle
+++ b/media-compat-test-client/build.gradle
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-apply plugin: android.support.SupportAndroidLibraryPlugin
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     androidTestImplementation project(':support-annotations')
@@ -30,4 +33,8 @@
     defaultConfig {
         minSdkVersion 14
     }
+}
+
+supportLibrary {
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/media-compat-test-service/build.gradle b/media-compat-test-service/build.gradle
index 1912719..946d48b 100644
--- a/media-compat-test-service/build.gradle
+++ b/media-compat-test-service/build.gradle
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-apply plugin: android.support.SupportAndroidLibraryPlugin
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     androidTestImplementation project(':support-annotations')
@@ -30,3 +33,7 @@
         minSdkVersion 14
     }
 }
+
+supportLibrary {
+    legacySourceLocation = true
+}
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index c504996..b0097d5 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -35,8 +39,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library media compat'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library media compat"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
index 85f5a51..7adf7d7 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
@@ -676,17 +676,15 @@
         WeakReference<Subscription> mSubscriptionRef;
 
         public SubscriptionCallback() {
+            mToken = new Binder();
             if (Build.VERSION.SDK_INT >= 26) {
                 mSubscriptionCallbackObj =
                         MediaBrowserCompatApi26.createSubscriptionCallback(new StubApi26());
-                mToken = null;
             } else if (Build.VERSION.SDK_INT >= 21) {
                 mSubscriptionCallbackObj =
                         MediaBrowserCompatApi21.createSubscriptionCallback(new StubApi21());
-                mToken = new Binder();
             } else {
                 mSubscriptionCallbackObj = null;
-                mToken = new Binder();
             }
         }
 
@@ -1958,22 +1956,30 @@
         @Override
         public void subscribe(@NonNull String parentId, @Nullable Bundle options,
                 @NonNull SubscriptionCallback callback) {
-            if (options == null) {
-                MediaBrowserCompatApi21.subscribe(
-                        mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
+            if (mServiceBinderWrapper == null) {
+                if (options == null) {
+                    MediaBrowserCompatApi21.subscribe(
+                            mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
+                } else {
+                    MediaBrowserCompatApi26.subscribe(
+                            mBrowserObj, parentId, options, callback.mSubscriptionCallbackObj);
+                }
             } else {
-                MediaBrowserCompatApi26.subscribe(
-                        mBrowserObj, parentId, options, callback.mSubscriptionCallbackObj);
+                super.subscribe(parentId, options, callback);
             }
         }
 
         @Override
         public void unsubscribe(@NonNull String parentId, SubscriptionCallback callback) {
-            if (callback == null) {
-                MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
+            if (mServiceBinderWrapper == null) {
+                if (callback == null) {
+                    MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
+                } else {
+                    MediaBrowserCompatApi26.unsubscribe(mBrowserObj, parentId,
+                            callback.mSubscriptionCallbackObj);
+                }
             } else {
-                MediaBrowserCompatApi26.unsubscribe(mBrowserObj, parentId,
-                        callback.mSubscriptionCallbackObj);
+                super.unsubscribe(parentId, callback);
             }
         }
     }
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
index 53b111a..debc66e 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -422,11 +422,15 @@
 
         @Override
         public void notifyChildrenChanged(final String parentId, final Bundle options) {
-            if (options == null) {
-                MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId);
+            if (mMessenger == null) {
+                if (options == null) {
+                    MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId);
+                } else {
+                    MediaBrowserServiceCompatApi26.notifyChildrenChanged(mServiceObj, parentId,
+                            options);
+                }
             } else {
-                MediaBrowserServiceCompatApi26.notifyChildrenChanged(mServiceObj, parentId,
-                        options);
+                super.notifyChildrenChanged(parentId, options);
             }
         }
 
diff --git a/media-compat/java/android/support/v4/media/MediaMetadataCompat.java b/media-compat/java/android/support/v4/media/MediaMetadataCompat.java
index 3ddf255..00f16cb 100644
--- a/media-compat/java/android/support/v4/media/MediaMetadataCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaMetadataCompat.java
@@ -365,10 +365,12 @@
 
     MediaMetadataCompat(Bundle bundle) {
         mBundle = new Bundle(bundle);
+        mBundle.setClassLoader(MediaMetadataCompat.class.getClassLoader());
     }
 
     MediaMetadataCompat(Parcel in) {
         mBundle = in.readBundle();
+        mBundle.setClassLoader(MediaMetadataCompat.class.getClassLoader());
     }
 
     /**
diff --git a/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java b/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
index df700cc..6356e33 100644
--- a/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
@@ -176,6 +176,39 @@
 
     @Test
     @SmallTest
+    public void testSubscriptionWithCustomOptionsWithRemoteService() throws Exception {
+        final String mediaId = "1000";
+        createMediaBrowser(TEST_REMOTE_BROWSER_SERVICE);
+        assertFalse(mMediaBrowser.isConnected());
+
+        connectMediaBrowserService();
+        assertTrue(mMediaBrowser.isConnected());
+
+        MediaMetadataCompat mediaMetadataCompat = new MediaMetadataCompat.Builder()
+                .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaId)
+                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title")
+                .putRating(MediaMetadataCompat.METADATA_KEY_RATING,
+                        RatingCompat.newPercentageRating(0.5f))
+                .putRating(MediaMetadataCompat.METADATA_KEY_USER_RATING,
+                        RatingCompat.newPercentageRating(0.8f))
+                .build();
+        Bundle options = new Bundle();
+        options.putParcelable(
+                StubRemoteMediaBrowserServiceCompat.MEDIA_METADATA, mediaMetadataCompat);
+
+        // Remote MediaBrowserService will create a media item with the given MediaMetadataCompat
+        mMediaBrowser.subscribe(mMediaBrowser.getRoot(), options, mSubscriptionCallback);
+        synchronized (mSubscriptionCallback.mWaitLock) {
+            mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
+            assertEquals(1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
+            assertEquals(1, mSubscriptionCallback.mLastChildMediaItems.size());
+            assertEquals(mediaId, mSubscriptionCallback.mLastChildMediaItems.get(0).getMediaId());
+        }
+        mMediaBrowser.disconnect();
+    }
+
+    @Test
+    @SmallTest
     public void testConnectTwice() throws Exception {
         createMediaBrowser(TEST_BROWSER_SERVICE);
         connectMediaBrowserService();
@@ -185,6 +218,7 @@
         } catch (IllegalStateException e) {
             // expected
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -199,6 +233,7 @@
         assertTrue(mConnectionCallback.mConnectionFailedCount > 0);
         assertEquals(0, mConnectionCallback.mConnectedCount);
         assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -256,6 +291,7 @@
             assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0],
                     mItemCallback.mLastMediaItem.getMediaId());
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -330,6 +366,7 @@
         }
         // onChildrenLoaded should not be called.
         assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -386,6 +423,7 @@
         }
         // onChildrenLoaded should not be called.
         assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -401,6 +439,7 @@
             assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_INVALID,
                     mSubscriptionCallback.mLastErrorId);
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -427,6 +466,7 @@
             assertEquals(pageSize,
                     mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE));
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -474,6 +514,7 @@
         for (StubSubscriptionCallback callback : subscriptionCallbacks) {
             assertEquals(0, callback.mChildrenLoadedWithOptionCount);
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -533,6 +574,7 @@
                 }
             }
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -549,6 +591,7 @@
             assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0],
                     mItemCallback.mLastMediaItem.getMediaId());
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -564,6 +607,7 @@
             assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_ON_LOAD_ITEM_NOT_IMPLEMENTED,
                     mItemCallback.mLastErrorId);
         }
+        mMediaBrowser.disconnect();
     }
 
     @Test
@@ -580,6 +624,7 @@
             assertNull(mItemCallback.mLastMediaItem);
             assertNull(mItemCallback.mLastErrorId);
         }
+        mMediaBrowser.disconnect();
     }
 
     private void createMediaBrowser(final ComponentName component) {
diff --git a/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java b/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java
index 9d7e73d..8e03ab2 100644
--- a/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java
+++ b/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java
@@ -31,6 +31,7 @@
     static final String EXTRAS_VALUE = "test_extras_value";
 
     static final String MEDIA_ID_ROOT = "test_media_id_root";
+    static final String MEDIA_METADATA = "test_media_metadata";
 
     static final String[] MEDIA_ID_CHILDREN = new String[]{
             "test_media_id_children_0", "test_media_id_children_1",
@@ -66,6 +67,19 @@
         }
     }
 
+    @Override
+    public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result,
+            final Bundle options) {
+        MediaMetadataCompat metadata = options.getParcelable(MEDIA_METADATA);
+        if (metadata == null) {
+            super.onLoadChildren(parentMediaId, result, options);
+        } else {
+            List<MediaItem> mediaItems = new ArrayList<>();
+            mediaItems.add(new MediaItem(metadata.getDescription(), MediaItem.FLAG_PLAYABLE));
+            result.sendResult(mediaItems);
+        }
+    }
+
     private MediaItem createMediaItem(String id) {
         return new MediaItem(new MediaDescriptionCompat.Builder()
                 .setMediaId(id).setExtras(getBrowserRootHints()).build(),
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index bb9ad6b..791c130 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
-apply plugin: android.support.SupportJavaLibraryPlugin
-apply plugin: 'kotlin'
+plugins {
+    id("SupportJavaLibraryPlugin")
+    id("kotlin")
+}
 
 dependencies {
     compile libs.support.annotations
@@ -36,9 +39,10 @@
 
 version = LibraryVersions.PAGING.toString()
 supportLibrary {
-    name 'Android Paging-Common'
-    publish true
-    inceptionYear '2017'
-    description "Android Paging-Common"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Paging-Common"
+    publish = true
+    mavenGroup = LibraryGroups.PAGING
+    inceptionYear = "2017"
+    description = "Android Paging-Common"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index c318c65..b4c6e28 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -14,26 +14,18 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
-apply plugin: 'kotlin-android'
+plugins {
+    id("SupportAndroidLibraryPlugin")
+    id("kotlin-android")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
     }
 }
 
@@ -69,9 +61,10 @@
 
 version = LibraryVersions.PAGING.toString()
 supportLibrary {
-    name 'Android Lifecycle Extensions'
-    publish true
-    inceptionYear '2017'
-    description "Android Lifecycle Extensions"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Lifecycle Extensions"
+    publish = true
+    mavenGroup = LibraryGroups.PAGING
+    inceptionYear = "2017"
+    description = "Android Lifecycle Extensions"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/paging/runtime/lint-baseline.xml b/paging/runtime/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/paging/runtime/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/percent/build.gradle b/percent/build.gradle
index aecaa28..a1d540d 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -18,8 +22,10 @@
 }
 
 supportLibrary {
-    name 'Android Percent Support Library'
-    publish true
-    inceptionYear '2015'
-    description 'Android Percent Support Library'
+    name = "Android Percent Support Library"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Percent Support Library"
+    legacySourceLocation = true
 }
diff --git a/persistence/db-framework/api/1.0.0.txt b/persistence/db-framework/api/1.0.0.txt
new file mode 100644
index 0000000..f460993
--- /dev/null
+++ b/persistence/db-framework/api/1.0.0.txt
@@ -0,0 +1,9 @@
+package android.arch.persistence.db.framework {
+
+  public final class FrameworkSQLiteOpenHelperFactory {
+    ctor public FrameworkSQLiteOpenHelperFactory();
+    method public android.arch.persistence.db.SupportSQLiteOpenHelper create(android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration);
+  }
+
+}
+
diff --git a/persistence/db-framework/build.gradle b/persistence/db-framework/build.gradle
index 0961ba5..1979e8f 100644
--- a/persistence/db-framework/build.gradle
+++ b/persistence/db-framework/build.gradle
@@ -14,30 +14,22 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
     }
 
     testOptions {
         unitTests.returnDefaultValues = true
     }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
 dependencies {
@@ -58,9 +50,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android Support SQLite - Framework Implementation'
-    publish true
-    inceptionYear '2017'
-    description "The implementation of Support SQLite library using the framework code."
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Support SQLite - Framework Implementation"
+    publish = true
+    mavenGroup = LibraryGroups.PERSISTENCE
+    inceptionYear = "2017"
+    description = "The implementation of Support SQLite library using the framework code."
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/persistence/db-framework/lint-baseline.xml b/persistence/db-framework/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/persistence/db-framework/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/persistence/db/api/1.0.0.txt b/persistence/db/api/1.0.0.txt
new file mode 100644
index 0000000..0e7aea9
--- /dev/null
+++ b/persistence/db/api/1.0.0.txt
@@ -0,0 +1,123 @@
+package android.arch.persistence.db {
+
+  public final class SimpleSQLiteQuery implements android.arch.persistence.db.SupportSQLiteQuery {
+    ctor public SimpleSQLiteQuery(java.lang.String, java.lang.Object[]);
+    ctor public SimpleSQLiteQuery(java.lang.String);
+    method public static void bind(android.arch.persistence.db.SupportSQLiteProgram, java.lang.Object[]);
+    method public void bindTo(android.arch.persistence.db.SupportSQLiteProgram);
+    method public java.lang.String getSql();
+  }
+
+  public abstract interface SupportSQLiteDatabase {
+    method public abstract void beginTransaction();
+    method public abstract void beginTransactionNonExclusive();
+    method public abstract void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
+    method public abstract void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
+    method public abstract android.arch.persistence.db.SupportSQLiteStatement compileStatement(java.lang.String);
+    method public abstract int delete(java.lang.String, java.lang.String, java.lang.Object[]);
+    method public abstract void disableWriteAheadLogging();
+    method public abstract boolean enableWriteAheadLogging();
+    method public abstract void endTransaction();
+    method public abstract void execSQL(java.lang.String) throws android.database.SQLException;
+    method public abstract void execSQL(java.lang.String, java.lang.Object[]) throws android.database.SQLException;
+    method public abstract java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttachedDbs();
+    method public abstract long getMaximumSize();
+    method public abstract long getPageSize();
+    method public abstract java.lang.String getPath();
+    method public abstract int getVersion();
+    method public abstract boolean inTransaction();
+    method public abstract long insert(java.lang.String, int, android.content.ContentValues) throws android.database.SQLException;
+    method public abstract boolean isDatabaseIntegrityOk();
+    method public abstract boolean isDbLockedByCurrentThread();
+    method public abstract boolean isOpen();
+    method public abstract boolean isReadOnly();
+    method public abstract boolean isWriteAheadLoggingEnabled();
+    method public abstract boolean needUpgrade(int);
+    method public abstract android.database.Cursor query(java.lang.String);
+    method public abstract android.database.Cursor query(java.lang.String, java.lang.Object[]);
+    method public abstract android.database.Cursor query(android.arch.persistence.db.SupportSQLiteQuery);
+    method public abstract android.database.Cursor query(android.arch.persistence.db.SupportSQLiteQuery, android.os.CancellationSignal);
+    method public abstract void setForeignKeyConstraintsEnabled(boolean);
+    method public abstract void setLocale(java.util.Locale);
+    method public abstract void setMaxSqlCacheSize(int);
+    method public abstract long setMaximumSize(long);
+    method public abstract void setPageSize(long);
+    method public abstract void setTransactionSuccessful();
+    method public abstract void setVersion(int);
+    method public abstract int update(java.lang.String, int, android.content.ContentValues, java.lang.String, java.lang.Object[]);
+    method public abstract boolean yieldIfContendedSafely();
+    method public abstract boolean yieldIfContendedSafely(long);
+  }
+
+  public abstract interface SupportSQLiteOpenHelper {
+    method public abstract void close();
+    method public abstract java.lang.String getDatabaseName();
+    method public abstract android.arch.persistence.db.SupportSQLiteDatabase getReadableDatabase();
+    method public abstract android.arch.persistence.db.SupportSQLiteDatabase getWritableDatabase();
+    method public abstract void setWriteAheadLoggingEnabled(boolean);
+  }
+
+  public static abstract class SupportSQLiteOpenHelper.Callback {
+    ctor public SupportSQLiteOpenHelper.Callback(int);
+    method public void onConfigure(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public void onCorruption(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public abstract void onCreate(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public void onDowngrade(android.arch.persistence.db.SupportSQLiteDatabase, int, int);
+    method public void onOpen(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public abstract void onUpgrade(android.arch.persistence.db.SupportSQLiteDatabase, int, int);
+    field public final int version;
+  }
+
+  public static class SupportSQLiteOpenHelper.Configuration {
+    method public static android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration.Builder builder(android.content.Context);
+    field public final android.arch.persistence.db.SupportSQLiteOpenHelper.Callback callback;
+    field public final android.content.Context context;
+    field public final java.lang.String name;
+  }
+
+  public static class SupportSQLiteOpenHelper.Configuration.Builder {
+    method public android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration build();
+    method public android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration.Builder callback(android.arch.persistence.db.SupportSQLiteOpenHelper.Callback);
+    method public android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration.Builder name(java.lang.String);
+  }
+
+  public static abstract interface SupportSQLiteOpenHelper.Factory {
+    method public abstract android.arch.persistence.db.SupportSQLiteOpenHelper create(android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration);
+  }
+
+  public abstract interface SupportSQLiteProgram {
+    method public abstract void bindBlob(int, byte[]);
+    method public abstract void bindDouble(int, double);
+    method public abstract void bindLong(int, long);
+    method public abstract void bindNull(int);
+    method public abstract void bindString(int, java.lang.String);
+    method public abstract void clearBindings();
+  }
+
+  public abstract interface SupportSQLiteQuery {
+    method public abstract void bindTo(android.arch.persistence.db.SupportSQLiteProgram);
+    method public abstract java.lang.String getSql();
+  }
+
+  public final class SupportSQLiteQueryBuilder {
+    method public static android.arch.persistence.db.SupportSQLiteQueryBuilder builder(java.lang.String);
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder columns(java.lang.String[]);
+    method public android.arch.persistence.db.SupportSQLiteQuery create();
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder distinct();
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder groupBy(java.lang.String);
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder having(java.lang.String);
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder limit(java.lang.String);
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder orderBy(java.lang.String);
+    method public android.arch.persistence.db.SupportSQLiteQueryBuilder selection(java.lang.String, java.lang.Object[]);
+  }
+
+  public abstract interface SupportSQLiteStatement implements android.arch.persistence.db.SupportSQLiteProgram {
+    method public abstract void execute();
+    method public abstract long executeInsert();
+    method public abstract int executeUpdateDelete();
+    method public abstract long simpleQueryForLong();
+    method public abstract java.lang.String simpleQueryForString();
+  }
+
+}
+
diff --git a/persistence/db/build.gradle b/persistence/db/build.gradle
index 4757a79..1670f68 100644
--- a/persistence/db/build.gradle
+++ b/persistence/db/build.gradle
@@ -14,30 +14,22 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
     }
 
     testOptions {
         unitTests.returnDefaultValues = true
     }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
 dependencies {
@@ -57,9 +49,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android DB'
-    publish true
-    inceptionYear '2017'
-    description "Android DB"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android DB"
+    publish = true
+    mavenGroup = LibraryGroups.PERSISTENCE
+    inceptionYear = "2017"
+    description = "Android DB"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/persistence/db/lint-baseline.xml b/persistence/db/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/persistence/db/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index 0c38487..ed9f975 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -11,8 +15,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Recommendation'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support Recommendation'
+    name = "Android Support Recommendation"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support Recommendation"
+    legacySourceLocation = true
 }
diff --git a/room/common/api/1.0.0.txt b/room/common/api/1.0.0.txt
new file mode 100644
index 0000000..0ba41ee
--- /dev/null
+++ b/room/common/api/1.0.0.txt
@@ -0,0 +1,107 @@
+package android.arch.persistence.room {
+
+  public abstract class ColumnInfo implements java.lang.annotation.Annotation {
+    field public static final int BINARY = 2; // 0x2
+    field public static final int BLOB = 5; // 0x5
+    field public static final java.lang.String INHERIT_FIELD_NAME = "[field-name]";
+    field public static final int INTEGER = 3; // 0x3
+    field public static final int NOCASE = 3; // 0x3
+    field public static final int REAL = 4; // 0x4
+    field public static final int RTRIM = 4; // 0x4
+    field public static final int TEXT = 2; // 0x2
+    field public static final int UNDEFINED = 1; // 0x1
+    field public static final int UNSPECIFIED = 1; // 0x1
+  }
+
+  public static abstract class ColumnInfo.Collate implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ColumnInfo.SQLiteTypeAffinity implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Dao implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Database implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Delete implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Embedded implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Entity implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class ForeignKey implements java.lang.annotation.Annotation {
+    field public static final int CASCADE = 5; // 0x5
+    field public static final int NO_ACTION = 1; // 0x1
+    field public static final int RESTRICT = 2; // 0x2
+    field public static final int SET_DEFAULT = 4; // 0x4
+    field public static final int SET_NULL = 3; // 0x3
+  }
+
+  public static abstract class ForeignKey.Action implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Ignore implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Index implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Insert implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class OnConflictStrategy implements java.lang.annotation.Annotation {
+    field public static final int ABORT = 3; // 0x3
+    field public static final int FAIL = 4; // 0x4
+    field public static final int IGNORE = 5; // 0x5
+    field public static final int REPLACE = 1; // 0x1
+    field public static final int ROLLBACK = 2; // 0x2
+  }
+
+  public abstract class PrimaryKey implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Query implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Relation implements java.lang.annotation.Annotation {
+  }
+
+  public class RoomWarnings {
+    ctor public RoomWarnings();
+    field public static final java.lang.String CANNOT_CREATE_VERIFICATION_DATABASE = "ROOM_CANNOT_CREATE_VERIFICATION_DATABASE";
+    field public static final java.lang.String CURSOR_MISMATCH = "ROOM_CURSOR_MISMATCH";
+    field public static final java.lang.String DEFAULT_CONSTRUCTOR = "ROOM_DEFAULT_CONSTRUCTOR";
+    field public static final java.lang.String INDEX_FROM_EMBEDDED_ENTITY_IS_DROPPED = "ROOM_EMBEDDED_ENTITY_INDEX_IS_DROPPED";
+    field public static final java.lang.String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
+    field public static final java.lang.String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
+    field public static final java.lang.String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final java.lang.String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
+    field public static final java.lang.String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
+    field public static final java.lang.String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
+    field public static final java.lang.String PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED = "ROOM_EMBEDDED_PRIMARY_KEY_IS_DROPPED";
+    field public static final java.lang.String RELATION_QUERY_WITHOUT_TRANSACTION = "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
+    field public static final java.lang.String RELATION_TYPE_MISMATCH = "ROOM_RELATION_TYPE_MISMATCH";
+  }
+
+  public abstract class SkipQueryVerification implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Transaction implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TypeConverter implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TypeConverters implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Update implements java.lang.annotation.Annotation {
+  }
+
+}
+
diff --git a/room/common/build.gradle b/room/common/build.gradle
index 4336583..6b8f9a5 100644
--- a/room/common/build.gradle
+++ b/room/common/build.gradle
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
-apply plugin: android.support.SupportJavaLibraryPlugin
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
 
 dependencies {
     compile libs.support.annotations
@@ -29,9 +32,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android Room-Common'
-    publish true
-    inceptionYear '2017'
-    description "Android Room-Common"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Room-Common"
+    publish = true
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2017"
+    description = "Android Room-Common"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index 222a338..dda922a 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
@@ -78,9 +80,10 @@
 createKotlinCheckstyle(project)
 
 supportLibrary {
-    name 'Android Room Compiler'
-    publish true
-    inceptionYear '2017'
-    description "Android Room annotation processor"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Room Compiler"
+    publish = true
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2017"
+    description = "Android Room annotation processor"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
diff --git a/room/gradle/wrapper/gradle-wrapper.properties b/room/gradle/wrapper/gradle-wrapper.properties
index a5292b0..2f8bf03 100644
--- a/room/gradle/wrapper/gradle-wrapper.properties
+++ b/room/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4-bin.zip
diff --git a/room/migration/api/1.0.0.txt b/room/migration/api/1.0.0.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/room/migration/api/1.0.0.txt
diff --git a/room/migration/build.gradle b/room/migration/build.gradle
index 45785ef..2003c1d 100644
--- a/room/migration/build.gradle
+++ b/room/migration/build.gradle
@@ -14,15 +14,17 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
-apply plugin: android.support.SupportJavaLibraryPlugin
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
 
 sourceSets {
     test.java.srcDirs += 'src/tests/kotlin'
 }
-project.ext.noDocs = true
 dependencies {
     compile project(":room:common")
     compile libs.kotlin.stdlib
@@ -34,9 +36,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android Room Migration'
-    publish true
-    inceptionYear '2017'
-    description "Android Room Migration"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Room Migration"
+    publish = true
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2017"
+    description = "Android Room Migration"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/room/runtime/api/1.0.0.txt b/room/runtime/api/1.0.0.txt
new file mode 100644
index 0000000..f163ca6
--- /dev/null
+++ b/room/runtime/api/1.0.0.txt
@@ -0,0 +1,88 @@
+package android.arch.persistence.room {
+
+  public class DatabaseConfiguration {
+    field public final boolean allowMainThreadQueries;
+    field public final java.util.List<android.arch.persistence.room.RoomDatabase.Callback> callbacks;
+    field public final android.content.Context context;
+    field public final android.arch.persistence.room.RoomDatabase.MigrationContainer migrationContainer;
+    field public final java.lang.String name;
+    field public final boolean requireMigration;
+    field public final android.arch.persistence.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
+  }
+
+  public class InvalidationTracker {
+    method public void addObserver(android.arch.persistence.room.InvalidationTracker.Observer);
+    method public void refreshVersionsAsync();
+    method public void removeObserver(android.arch.persistence.room.InvalidationTracker.Observer);
+  }
+
+  public static abstract class InvalidationTracker.Observer {
+    ctor protected InvalidationTracker.Observer(java.lang.String, java.lang.String...);
+    ctor public InvalidationTracker.Observer(java.lang.String[]);
+    method public abstract void onInvalidated(java.util.Set<java.lang.String>);
+  }
+
+  public class Room {
+    ctor public Room();
+    method public static <T extends android.arch.persistence.room.RoomDatabase> android.arch.persistence.room.RoomDatabase.Builder<T> databaseBuilder(android.content.Context, java.lang.Class<T>, java.lang.String);
+    method public static <T extends android.arch.persistence.room.RoomDatabase> android.arch.persistence.room.RoomDatabase.Builder<T> inMemoryDatabaseBuilder(android.content.Context, java.lang.Class<T>);
+    field public static final java.lang.String MASTER_TABLE_NAME = "room_master_table";
+  }
+
+  public abstract class RoomDatabase {
+    ctor public RoomDatabase();
+    method public void beginTransaction();
+    method public void close();
+    method public android.arch.persistence.db.SupportSQLiteStatement compileStatement(java.lang.String);
+    method protected abstract android.arch.persistence.room.InvalidationTracker createInvalidationTracker();
+    method protected abstract android.arch.persistence.db.SupportSQLiteOpenHelper createOpenHelper(android.arch.persistence.room.DatabaseConfiguration);
+    method public void endTransaction();
+    method public android.arch.persistence.room.InvalidationTracker getInvalidationTracker();
+    method public android.arch.persistence.db.SupportSQLiteOpenHelper getOpenHelper();
+    method public boolean inTransaction();
+    method public void init(android.arch.persistence.room.DatabaseConfiguration);
+    method protected void internalInitInvalidationTracker(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public boolean isOpen();
+    method public android.database.Cursor query(java.lang.String, java.lang.Object[]);
+    method public android.database.Cursor query(android.arch.persistence.db.SupportSQLiteQuery);
+    method public void runInTransaction(java.lang.Runnable);
+    method public <V> V runInTransaction(java.util.concurrent.Callable<V>);
+    method public void setTransactionSuccessful();
+    field protected java.util.List<android.arch.persistence.room.RoomDatabase.Callback> mCallbacks;
+    field protected volatile android.arch.persistence.db.SupportSQLiteDatabase mDatabase;
+  }
+
+  public static class RoomDatabase.Builder<T extends android.arch.persistence.room.RoomDatabase> {
+    method public android.arch.persistence.room.RoomDatabase.Builder<T> addCallback(android.arch.persistence.room.RoomDatabase.Callback);
+    method public android.arch.persistence.room.RoomDatabase.Builder<T> addMigrations(android.arch.persistence.room.migration.Migration...);
+    method public android.arch.persistence.room.RoomDatabase.Builder<T> allowMainThreadQueries();
+    method public T build();
+    method public android.arch.persistence.room.RoomDatabase.Builder<T> fallbackToDestructiveMigration();
+    method public android.arch.persistence.room.RoomDatabase.Builder<T> openHelperFactory(android.arch.persistence.db.SupportSQLiteOpenHelper.Factory);
+  }
+
+  public static abstract class RoomDatabase.Callback {
+    ctor public RoomDatabase.Callback();
+    method public void onCreate(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public void onOpen(android.arch.persistence.db.SupportSQLiteDatabase);
+  }
+
+  public static class RoomDatabase.MigrationContainer {
+    ctor public RoomDatabase.MigrationContainer();
+    method public void addMigrations(android.arch.persistence.room.migration.Migration...);
+    method public java.util.List<android.arch.persistence.room.migration.Migration> findMigrationPath(int, int);
+  }
+
+}
+
+package android.arch.persistence.room.migration {
+
+  public abstract class Migration {
+    ctor public Migration(int, int);
+    method public abstract void migrate(android.arch.persistence.db.SupportSQLiteDatabase);
+    field public final int endVersion;
+    field public final int startVersion;
+  }
+
+}
+
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index a170c8e..a95eba0 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -14,21 +14,17 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
     }
 
     buildTypes.all {
@@ -38,10 +34,6 @@
     testOptions {
         unitTests.returnDefaultValues = true
     }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
 dependencies {
@@ -78,9 +70,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android Room-Runtime'
-    publish true
-    inceptionYear '2017'
-    description "Android Room-Runtime"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Room-Runtime"
+    publish = true
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2017"
+    description = "Android Room-Runtime"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/room/runtime/lint-baseline.xml b/room/runtime/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/room/runtime/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/EntityDeletionOrUpdateAdapter.java b/room/runtime/src/main/java/android/arch/persistence/room/EntityDeletionOrUpdateAdapter.java
index 6f4aa68..373b122 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/EntityDeletionOrUpdateAdapter.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/EntityDeletionOrUpdateAdapter.java
@@ -45,6 +45,7 @@
      *
      * @return An SQL query that can delete or update instances of T.
      */
+    @Override
     protected abstract String createQuery();
 
     /**
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/Room.java b/room/runtime/src/main/java/android/arch/persistence/room/Room.java
index 2850b55..9b168fc 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/Room.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/Room.java
@@ -72,6 +72,7 @@
         return new RoomDatabase.Builder<>(context, klass, null);
     }
 
+    @SuppressWarnings({"TypeParameterUnusedInFormals", "ClassNewInstance"})
     @NonNull
     static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) {
         final String fullPackage = klass.getPackage().getName();
diff --git a/room/rxjava2/api/1.0.0.txt b/room/rxjava2/api/1.0.0.txt
new file mode 100644
index 0000000..a7cffd3
--- /dev/null
+++ b/room/rxjava2/api/1.0.0.txt
@@ -0,0 +1,14 @@
+package android.arch.persistence.room {
+
+  public class EmptyResultSetException extends java.lang.RuntimeException {
+    ctor public EmptyResultSetException(java.lang.String);
+  }
+
+  public class RxRoom {
+    ctor public RxRoom();
+    method public static io.reactivex.Flowable<java.lang.Object> createFlowable(android.arch.persistence.room.RoomDatabase, java.lang.String...);
+    field public static final java.lang.Object NOTHING;
+  }
+
+}
+
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index 7f86842..430efbe 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -14,36 +14,22 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
-    }
-    buildTypes {
-        release {
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-        }
     }
 
     testOptions {
         unitTests.returnDefaultValues = true
     }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
 dependencies {
@@ -71,9 +57,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android Room RXJava2'
-    publish true
-    inceptionYear '2017'
-    description "Android Room RXJava2"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Room RXJava2"
+    publish = true
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2017"
+    description = "Android Room RXJava2"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/room/rxjava2/lint-baseline.xml b/room/rxjava2/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/room/rxjava2/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/room/testing/api/1.0.0.txt b/room/testing/api/1.0.0.txt
new file mode 100644
index 0000000..e93487f
--- /dev/null
+++ b/room/testing/api/1.0.0.txt
@@ -0,0 +1,13 @@
+package android.arch.persistence.room.testing {
+
+  public class MigrationTestHelper extends org.junit.rules.TestWatcher {
+    ctor public MigrationTestHelper(android.app.Instrumentation, java.lang.String);
+    ctor public MigrationTestHelper(android.app.Instrumentation, java.lang.String, android.arch.persistence.db.SupportSQLiteOpenHelper.Factory);
+    method public void closeWhenFinished(android.arch.persistence.db.SupportSQLiteDatabase);
+    method public void closeWhenFinished(android.arch.persistence.room.RoomDatabase);
+    method public android.arch.persistence.db.SupportSQLiteDatabase createDatabase(java.lang.String, int) throws java.io.IOException;
+    method public android.arch.persistence.db.SupportSQLiteDatabase runMigrationsAndValidate(java.lang.String, int, boolean, android.arch.persistence.room.migration.Migration...) throws java.io.IOException;
+  }
+
+}
+
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index 078de88..c02f135 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -14,29 +14,22 @@
  * limitations under the License.
  */
 
+import android.support.LibraryGroups
 import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
-apply plugin: android.support.FlatfootAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 android {
-    compileSdkVersion tools.current_sdk
-    buildToolsVersion tools.build_tools_version
-
     defaultConfig {
         minSdkVersion flatfoot.min_sdk
-        targetSdkVersion tools.current_sdk
-
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     testOptions {
         unitTests.returnDefaultValues = true
     }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
 }
 
 dependencies {
@@ -64,9 +57,10 @@
 
 version = LibraryVersions.ROOM.toString()
 supportLibrary {
-    name 'Android Room Testimg'
-    publish true
-    inceptionYear '2017'
-    description "Android Room Testing"
-    url SupportLibraryExtension.ARCHITECTURE_URL
+    name = "Android Room Testing"
+    publish = true
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2017"
+    description = "Android Room Testing"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
 }
\ No newline at end of file
diff --git a/room/testing/lint-baseline.xml b/room/testing/lint-baseline.xml
new file mode 100644
index 0000000..dee4355
--- /dev/null
+++ b/room/testing/lint-baseline.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+    <issue
+        id="InvalidPackage"
+        message="Invalid package reference in library; not included in Android: `java.lang.management`. Referenced from `org.junit.internal.runners.statements.FailOnTimeout`.">
+        <location
+            file="../../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12.jar"/>
+    </issue>
+
+</issues>
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 18e0a14..2e93bbe 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
@@ -341,7 +341,7 @@
         return 0;
     }
 
-    class MigratingDelegate extends RoomOpenHelperDelegate {
+    static class MigratingDelegate extends RoomOpenHelperDelegate {
         private final boolean mVerifyDroppedTables;
 
         MigratingDelegate(DatabaseBundle databaseBundle, boolean verifyDroppedTables) {
diff --git a/testutils/build.gradle b/testutils/build.gradle
index f1be70d..15eabaf 100644
--- a/testutils/build.gradle
+++ b/testutils/build.gradle
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-apply plugin: android.support.SupportAndroidLibraryPlugin
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     compile libs.junit
@@ -27,4 +29,8 @@
     lintOptions {
         disable 'InvalidPackage' // Lint is unhappy about junit package
     }
+}
+
+supportLibrary {
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/transition/build.gradle b/transition/build.gradle
index be366d6..cdcd742 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -44,8 +48,10 @@
 }
 
 supportLibrary {
-    name 'Android Transition Support Library'
-    publish true
-    inceptionYear '2016'
-    description 'Android Transition Support Library'
+    name = "Android Transition Support Library"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2016"
+    description = "Android Transition Support Library"
+    legacySourceLocation = true
 }
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index 0545458..9b5afb2 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -14,8 +18,10 @@
 }
 
 supportLibrary {
-    name 'Android Support TV Provider'
-    publish true
-    inceptionYear '2017'
-    description 'Android Support Library for TV Provider'
+    name = "Android Support TV Provider"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2017"
+    description = "Android Support Library for TV Provider"
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/v13/build.gradle b/v13/build.gradle
index 06774fd..a14c9ea 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -23,8 +27,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library v13'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library v13"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 8c66d6a..5dfcc50 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -14,7 +14,11 @@
  * limitations under the License
  */
 
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-v4')
@@ -34,8 +38,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Preference v14'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support Preference v14'
+    name = "Android Support Preference v14"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support Preference v14"
+    legacySourceLocation = true
 }
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index baefe46..57cc60d 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -31,8 +35,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Leanback v17'
-    publish true
-    inceptionYear '2014'
-    description 'Android Support Leanback v17'
+    name = "Android Support Leanback v17"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2014"
+    description = "Android Support Leanback v17"
+    legacySourceLocation = true
 }
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
index f573908..6cb0d8e 100644
--- a/v17/preference-leanback/build.gradle
+++ b/v17/preference-leanback/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-v4')
@@ -24,8 +28,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Leanback Preference v17'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support Leanback Preference v17'
+    name = "Android Support Leanback Preference v17"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support Leanback Preference v17"
+    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/v4/build.gradle b/v4/build.gradle
index 737db27..f91d5ef 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -17,8 +21,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Library v4'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android Support Library v4"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index 2d57ac4..e7ac27d 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -32,8 +36,10 @@
 }
 
 supportLibrary {
-    name 'Android AppCompat Library v7'
-    publish true
-    inceptionYear '2011'
-    description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    name = "Android AppCompat Library v7"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+    legacySourceLocation = true
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java
index fa6196f..b8ce82a 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java
@@ -213,9 +213,9 @@
         if (a.hasValue(R.styleable.TextAppearance_android_fontFamily)
                 || a.hasValue(R.styleable.TextAppearance_fontFamily)) {
             mFontTypeface = null;
-            int fontFamilyId = a.hasValue(R.styleable.TextAppearance_android_fontFamily)
-                    ? R.styleable.TextAppearance_android_fontFamily
-                    : R.styleable.TextAppearance_fontFamily;
+            int fontFamilyId = a.hasValue(R.styleable.TextAppearance_fontFamily)
+                    ? R.styleable.TextAppearance_fontFamily
+                    : R.styleable.TextAppearance_android_fontFamily;
             if (!context.isRestricted()) {
                 final WeakReference<TextView> textViewWeak = new WeakReference<>(mView);
                 ResourcesCompat.FontCallback replyCallback = new ResourcesCompat.FontCallback() {
diff --git a/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml b/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
index 2af99ac..3841206 100644
--- a/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
+++ b/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
@@ -241,6 +241,14 @@
             android:textAppearance="@style/TextView_FontResource"
             android:typeface="serif" />
 
+        <android.support.v7.widget.AppCompatTextView
+            android:id="@+id/textview_app_and_android_fontfamily"
+            android:text="@string/sample_text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="serif"
+            app:fontFamily="monospace"/>
+
     </LinearLayout>
 
 </ScrollView>
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
index 933980d..34890ed 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
@@ -305,4 +305,13 @@
 
         assertEquals(Typeface.SERIF, textView.getTypeface());
     }
+
+    @Test
+    @UiThreadTest
+    public void testfontFamilyNamespaceHierarchy() {
+        // This view has fontFamilyset in both the app and android namespace. App should be used.
+        TextView textView = mContainer.findViewById(R.id.textview_app_and_android_fontfamily);
+
+        assertEquals(Typeface.MONOSPACE, textView.getTypeface());
+    }
 }
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index 76c3bf3..39820d4 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -15,8 +19,10 @@
 }
 
 supportLibrary {
-    name 'Android Support CardView v7'
-    publish true
-    inceptionYear '2011'
-    description 'Android Support CardView v7'
+    name = "Android Support CardView v7"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "Android Support CardView v7"
+    legacySourceLocation = true
 }
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index d4d467d..83e62af 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -19,8 +23,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Grid Layout'
-    publish true
-    inceptionYear '2013'
-    description 'Android Support Grid Layout'
+    name = "Android Support Grid Layout"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2013"
+    description = "Android Support Grid Layout"
+    legacySourceLocation = true
 }
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index f301324..788fbb1 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(":support-media-compat")
@@ -28,8 +32,10 @@
 }
 
 supportLibrary {
-    name 'Android MediaRouter Support Library'
-    publish true
-    inceptionYear '2013'
-    description 'Android MediaRouter Support Library'
+    name = "Android MediaRouter Support Library"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2013"
+    description = "Android MediaRouter Support Library"
+    legacySourceLocation = true
 }
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index 6da6914..a62ff4b 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-compat')
@@ -14,8 +18,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Palette v7'
-    publish true
-    inceptionYear '2014'
-    description 'Android Support Palette v7'
+    name = "Android Support Palette v7"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2014"
+    description = "Android Support Palette v7"
+    legacySourceLocation = true
 }
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index 2b1e871..d1a022b 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -14,7 +14,11 @@
  * limitations under the License
  */
 
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-v4')
@@ -50,8 +54,10 @@
 }
 
 supportLibrary {
-    name 'Android Support Preference v7'
-    publish true
-    inceptionYear '2015'
-    description 'Android Support Preference v7'
+    name = "Android Support Preference v7"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2015"
+    description = "Android Support Preference v7"
+    legacySourceLocation = true
 }
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index ad1150f..9a07946 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -36,8 +40,10 @@
 }
 
 supportLibrary {
-    name 'Android Support RecyclerView v7'
-    publish true
-    inceptionYear '2014'
-    description 'Android Support RecyclerView v7'
+    name = "Android Support RecyclerView v7"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2014"
+    description = "Android Support RecyclerView v7"
+    legacySourceLocation = true
 }
diff --git a/wear/build.gradle b/wear/build.gradle
index 814f5cf..32b91da 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -1,4 +1,8 @@
-apply plugin: android.support.SupportAndroidLibraryPlugin
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
 
 dependencies {
     api project(':support-annotations')
@@ -33,13 +37,10 @@
 }
 
 supportLibrary {
-    name 'Android Wear Support UI'
-    publish true
-    inceptionYear '2016'
-    description 'Android Wear Support UI'
-
-    license {
-        name 'The Apache Software License, Version 2.0'
-        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
-    }
+    name = "Android Wear Support UI"
+    publish = true
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2016"
+    description = "Android Wear Support UI"
+    legacySourceLocation = true
 }