Merge "Switch DataSources to be async to better support network usecase" into oc-mr1-support-27.0-dev
diff --git a/annotations/build.gradle b/annotations/build.gradle
index b50cd77..df521e1 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportJavaLibraryPlugin")
@@ -51,6 +52,7 @@
 supportLibrary {
     name = "Android Support Library Annotations"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/app-toolkit/common/build.gradle b/app-toolkit/common/build.gradle
index 42b0f5a..9604210 100644
--- a/app-toolkit/common/build.gradle
+++ b/app-toolkit/common/build.gradle
@@ -31,10 +31,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.ARCH_CORE.toString()
 supportLibrary {
     name = "Android Arch-Common"
     publish = true
+    mavenVersion = LibraryVersions.ARCH_CORE
     mavenGroup = LibraryGroups.ARCH_CORE
     inceptionYear = "2017"
     description = "Android Arch-Common"
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index 296e7b7..7f7f3db 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -54,10 +54,10 @@
     }
 }
 
-version = LibraryVersions.ARCH_CORE_TESTING.toString()
 supportLibrary {
     name = "Android Core-Testing"
     publish = true
+    mavenVersion = LibraryVersions.ARCH_CORE_TESTING
     mavenGroup = LibraryGroups.ARCH_CORE
     inceptionYear = "2017"
     description = "Android Core-Testing"
diff --git a/app-toolkit/dependencies.gradle b/app-toolkit/dependencies.gradle
index 31fc2ae..e760149 100644
--- a/app-toolkit/dependencies.gradle
+++ b/app-toolkit/dependencies.gradle
@@ -22,7 +22,7 @@
     ffLibs = libs
 }
 def ffVersions = [:]
-ffVersions.kotlin = "1.1.3"
+ffVersions.kotlin = "1.1.51"
 ffVersions.auto_common = "0.6"
 ffVersions.javapoet = "1.8.0"
 ffVersions.compile_testing = "0.11"
diff --git a/app-toolkit/runtime/build.gradle b/app-toolkit/runtime/build.gradle
index c0d7224..526ef4e 100644
--- a/app-toolkit/runtime/build.gradle
+++ b/app-toolkit/runtime/build.gradle
@@ -49,10 +49,10 @@
     }
 }
 
-version = LibraryVersions.ARCH_RUNTIME.toString()
 supportLibrary {
     name = "Android Arch-Runtime"
     publish = true
+    mavenVersion = LibraryVersions.ARCH_RUNTIME
     mavenGroup = LibraryGroups.ARCH_CORE
     inceptionYear = "2017"
     description = "Android Arch-Runtime"
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
index b7a5049..dc41841 100644
--- a/buildSrc/build_dependencies.gradle
+++ b/buildSrc/build_dependencies.gradle
@@ -29,6 +29,6 @@
 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"]
+build_libs.kotlin = [gradle_plugin: "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.51"]
 
 rootProject.ext['build_libs'] = build_libs
diff --git a/buildSrc/diff_and_docs.gradle b/buildSrc/diff_and_docs.gradle
index 876d1f3..2fcc893 100644
--- a/buildSrc/diff_and_docs.gradle
+++ b/buildSrc/diff_and_docs.gradle
@@ -545,9 +545,11 @@
                         "ignoring API tasks.")
                 return
             }
-            initializeApiChecksForProject(project)
-            registerJavaProjectForDocsTask(project.generateApi, project.compileJava)
-            registerJavaProjectForDocsTask(project.generateDiffs, project.compileJava)
+            project.afterEvaluate {
+                initializeApiChecksForProject(project)
+                registerJavaProjectForDocsTask(project.generateApi, project.compileJava)
+                registerJavaProjectForDocsTask(project.generateDiffs, project.compileJava)
+            }
         }
     }
 }
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index 8d9dff3..6b613d0 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -162,9 +162,6 @@
         }
 
         project.ext.currentSdk = gradle.ext.currentSdk
-        apply plugin: 'maven'
-
-        version = LibraryVersions.SUPPORT_LIBRARY.toString();
 
         project.plugins.whenPluginAdded { plugin ->
             def isAndroidLibrary = "com.android.build.gradle.LibraryPlugin"
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
index 1dac034..8f86e33 100644
--- a/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryExtension.groovy
@@ -29,6 +29,7 @@
 
     Project project
     String name;
+    Version mavenVersion;
     String mavenGroup;
     String description;
     String inceptionYear;
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy
index 6b11a21..b557ec3 100644
--- a/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryMavenUploader.groovy
@@ -31,7 +31,11 @@
                 if (supportLibraryExtension.mavenGroup == null) {
                     throw Exception("You must specify mavenGroup for " + project.name + " project");
                 }
+                if (supportLibraryExtension.mavenVersion == null) {
+                    throw Exception("You must specify mavenVersion for " + project.name + " project");
+                }
                 project.group = supportLibraryExtension.mavenGroup
+                project.version = supportLibraryExtension.mavenVersion.toString()
             }
         }
 
diff --git a/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy b/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy
deleted file mode 100644
index 4f829f6..0000000
--- a/buildSrc/src/main/groovy/android/support/checkapi/CheckApiTask.groovy
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.checkapi
-
-import org.gradle.api.DefaultTask
-import org.gradle.api.GradleException
-import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.Optional
-import org.gradle.api.tasks.OutputFile
-
-import java.security.MessageDigest
-
-/**
- * Task used to verify changes between two API files.
- * <p>
- * This task may be configured to ignore, warn, or fail with a message for a specific set of
- * Doclava-defined error codes. See {@link com.google.doclava.Errors} for a complete list of
- * supported error codes.
- * <p>
- * Specific failures may be ignored by specifying a list of SHAs in {@link #whitelistErrors}. Each
- * SHA is unique to a specific API change and is logged to the error output on failure.
- */
-public class CheckApiTask extends DefaultTask {
-    /** Character that resets console output color. */
-    private static final String ANSI_RESET = "\u001B[0m";
-
-    /** Character that sets console output color to red. */
-    private static final String ANSI_RED = "\u001B[31m";
-
-    /** Character that sets console output color to yellow. */
-    private static final String ANSI_YELLOW = "\u001B[33m";
-
-    /** API file that represents the existing API surface. */
-    @Optional
-    @InputFile
-    File oldApiFile
-
-    /** API file that represents the existing API surface's removals. */
-    @Optional
-    @InputFile
-    File oldRemovedApiFile
-
-    /** API file that represents the candidate API surface. */
-    @InputFile
-    File newApiFile
-
-    /** API file that represents the candidate API surface's removals. */
-    @Optional
-    @InputFile
-    File newRemovedApiFile
-
-    /** Optional file containing a newline-delimited list of error SHAs to ignore. */
-    File whitelistErrorsFile
-
-    @Optional
-    @InputFile
-    File getWhiteListErrorsFileInput() {
-        // Gradle requires non-null InputFiles to exist -- even with Optional -- so work around that
-        // by returning null for this field if the file doesn't exist.
-        if (whitelistErrorsFile && whitelistErrorsFile.exists()) {
-            return whitelistErrorsFile;
-        }
-        return null;
-    }
-
-    /**
-     * Optional list of packages to ignore.
-     * <p>
-     * Packages names will be matched exactly; sub-packages are not automatically recognized.
-     */
-    @Optional
-    @Input
-    Collection ignoredPackages
-
-    /**
-     * Optional list of classes to ignore.
-     * <p>
-     * Class names will be matched exactly by their fully-qualified names; inner classes are not
-     * automatically recognized.
-     */
-    @Optional
-    @Input
-    Collection ignoredClasses
-
-    /**
-     * Optional set of error SHAs to ignore.
-     * <p>
-     * Each error SHA is unique to a specific API change.
-     */
-    @Optional
-    @Input
-    Set whitelistErrors = []
-
-    // Errors that were both detected and whitelisted.
-    Set detectedWhitelistErrors = []
-
-    @InputFiles
-    Collection<File> doclavaClasspath
-
-    // A dummy output file meant only to tag when this check was last ran.
-    // Without any outputs, Gradle will run this task every time.
-    @Optional
-    private File mOutputFile
-
-    @OutputFile
-    public File getOutputFile() {
-        return mOutputFile ?: new File(project.buildDir, "checkApi/${name}-completed")
-    }
-
-    @Optional
-    public void setOutputFile(File outputFile) {
-        mOutputFile = outputFile
-    }
-
-    /**
-     * List of Doclava error codes to treat as errors.
-     * <p>
-     * See {@link com.google.doclava.Errors} for a complete list of error codes.
-     */
-    @Input
-    Collection checkApiErrors
-
-    /**
-     * List of Doclava error codes to treat as warnings.
-     * <p>
-     * See {@link com.google.doclava.Errors} for a complete list of error codes.
-     */
-    @Input
-    Collection checkApiWarnings
-
-    /**
-     * List of Doclava error codes to ignore.
-     * <p>
-     * See {@link com.google.doclava.Errors} for a complete list of error codes.
-     */
-    @Input
-    Collection checkApiHidden
-
-    /** Message to display on API check failure. */
-    @Input
-    String onFailMessage
-
-    public CheckApiTask() {
-        group = 'Verification'
-        description = 'Invoke Doclava\'s ApiCheck tool to make sure current.txt is up to date.'
-    }
-
-    private Set<File> collectAndVerifyInputs() {
-        if (getOldRemovedApiFile() != null && getNewRemovedApiFile() != null) {
-            return [getOldApiFile(), getNewApiFile(), getOldRemovedApiFile(),
-                    getNewRemovedApiFile()] as Set
-        } else {
-            return [getOldApiFile(), getNewApiFile()] as Set
-        }
-    }
-
-    public void setCheckApiErrors(Collection errors) {
-        // Make it serializable.
-        checkApiErrors = errors as int[]
-    }
-
-    public void setCheckApiWarnings(Collection warnings) {
-        // Make it serializable.
-        checkApiWarnings = warnings as int[]
-    }
-
-    public void setCheckApiHidden(Collection hidden) {
-        // Make it serializable.
-        checkApiHidden = hidden as int[]
-    }
-
-    @TaskAction
-    public void exec() {
-        if (getOldApiFile() == null) {
-            // Nothing to do.
-            return
-        }
-
-        final def apiFiles = collectAndVerifyInputs()
-
-        OutputStream errStream = new ByteArrayOutputStream()
-
-        // If either of those gets tweaked, then this should be refactored to extend JavaExec.
-        project.javaexec {
-            // Put Doclava on the classpath so we can get the ApiCheck class.
-            classpath(getDoclavaClasspath())
-            main = 'com.google.doclava.apicheck.ApiCheck'
-
-            minHeapSize = '128m'
-            maxHeapSize = '1024m'
-
-            // add -error LEVEL for every error level we want to fail the build on.
-            getCheckApiErrors().each { args('-error', it) }
-            getCheckApiWarnings().each { args('-warning', it) }
-            getCheckApiHidden().each { args('-hide', it) }
-
-            Collection ignoredPackages = getIgnoredPackages()
-            if (ignoredPackages) {
-                ignoredPackages.each { args('-ignorePackage', it) }
-            }
-            Collection ignoredClasses = getIgnoredClasses()
-            if (ignoredClasses) {
-                ignoredClasses.each { args('-ignoreClass', it) }
-            }
-
-            args(apiFiles.collect( { it.absolutePath } ))
-
-            // Redirect error output so that we can whitelist specific errors.
-            errorOutput = errStream
-
-            // We will be handling failures ourselves with a custom message.
-            ignoreExitValue = true
-        }
-
-        // Load the whitelist file, if present.
-        if (whitelistErrorsFile && whitelistErrorsFile.exists()) {
-            whitelistErrors += whitelistErrorsFile.readLines()
-        }
-
-        // Parse the error output.
-        Set unparsedErrors = []
-        Set detectedErrors = []
-        Set parsedErrors = []
-        errStream.toString().split("\n").each {
-            if (it) {
-                def matcher = it =~ ~/^(.+):(.+): (\w+) (\d+): (.+)$/
-                if (!matcher) {
-                    unparsedErrors += [it]
-                } else if (matcher[0][3] == "error") {
-                    def hash = getShortHash(matcher[0][5]);
-                    def error = matcher[0][1..-1] + [hash]
-                    if (hash in whitelistErrors) {
-                        detectedErrors += [error]
-                        detectedWhitelistErrors += error[5]
-                    } else {
-                        parsedErrors += [error]
-                    }
-                }
-            }
-        }
-
-        unparsedErrors.each { error -> logger.error "$ANSI_RED$error$ANSI_RESET" }
-        parsedErrors.each { logger.error "$ANSI_RED${it[5]}$ANSI_RESET ${it[4]}"}
-        detectedErrors.each { logger.warn "$ANSI_YELLOW${it[5]}$ANSI_RESET ${it[4]}"}
-
-        if (unparsedErrors || parsedErrors) {
-            throw new GradleException(onFailMessage)
-        }
-
-        // Just create a dummy file upon completion. Without any outputs, Gradle will run this task
-        // every time.
-        File outputFile = getOutputFile()
-        outputFile.parentFile.mkdirs()
-        outputFile.createNewFile()
-    }
-
-    def getShortHash(src) {
-        return MessageDigest.getInstance("SHA-1")
-                .digest(src.toString().bytes)
-                .encodeHex()
-                .toString()[-7..-1]
-    }
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt b/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt
new file mode 100644
index 0000000..8f96b2e
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt
@@ -0,0 +1,251 @@
+/*
+ * 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.checkapi
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.TaskAction
+import java.io.*
+import java.security.MessageDigest
+
+
+/** Character that resets console output color. */
+private const val ANSI_RESET = "\u001B[0m"
+
+/** Character that sets console output color to red. */
+private const val ANSI_RED = "\u001B[31m"
+
+/** Character that sets console output color to yellow. */
+private const val ANSI_YELLOW = "\u001B[33m"
+
+private val ERROR_REGEX = Regex("^(.+):(.+): (\\w+) (\\d+): (.+)$")
+
+private fun ByteArray.encodeHex() = fold(StringBuilder(), { builder, byte ->
+    val hexString = Integer.toHexString(byte.toInt() and 0xFF)
+    if (hexString.length < 2) {
+        builder.append("0")
+    }
+    builder.append(hexString)
+}).toString()
+
+private fun getShortHash(src: String): String {
+    val str = MessageDigest.getInstance("SHA-1")
+            .digest(src.toByteArray()).encodeHex()
+    val len = str.length
+    return str.substring(len - 7, len)
+}
+
+/**
+ * Task used to verify changes between two API files.
+ * <p>
+ * This task may be configured to ignore, warn, or fail with a message for a specific set of
+ * Doclava-defined error codes. See {@link com.google.doclava.Errors} for a complete list of
+ * supported error codes.
+ * <p>
+ * Specific failures may be ignored by specifying a list of SHAs in {@link #whitelistErrors}. Each
+ * SHA is unique to a specific API change and is logged to the error output on failure.
+ */
+open class CheckApiTask : DefaultTask() {
+
+    /** API file that represents the existing API surface. */
+    @Optional
+    @InputFile
+    var oldApiFile: File? = null
+
+    /** API file that represents the existing API surface's removals. */
+    @Optional
+    @InputFile
+    var oldRemovedApiFile: File? = null
+
+    /** API file that represents the candidate API surface. */
+    @InputFile
+    var newApiFile: File? = null
+
+    /** API file that represents the candidate API surface's removals. */
+    @Optional
+    @InputFile
+    var newRemovedApiFile: File? = null
+
+    /** Optional file containing a newline-delimited list of error SHAs to ignore. */
+    var whitelistErrorsFile: File? = null
+
+    @Optional
+    @InputFile
+    fun getWhiteListErrorsFileInput(): File? {
+        // Gradle requires non-null InputFiles to exist -- even with Optional -- so work around that
+        // by returning null for this field if the file doesn't exist.
+        if (whitelistErrorsFile?.exists() == true) {
+            return whitelistErrorsFile
+        }
+        return null
+    }
+
+    /**
+     * Optional set of error SHAs to ignore.
+     * <p>
+     * Each error SHA is unique to a specific API change.
+     */
+    @Optional
+    @Input
+    var whitelistErrors = emptySet<String>()
+
+    var detectedWhitelistErrors = mutableSetOf<String>()
+
+    @InputFiles
+    var doclavaClasspath: Collection<File> = emptyList()
+
+    // A dummy output file meant only to tag when this check was last ran.
+    // Without any outputs, Gradle will run this task every time.
+    @Optional
+    private var mOutputFile: File? = null
+
+    @OutputFile
+    fun getOutputFile(): File {
+        return if (mOutputFile != null)
+            mOutputFile!!
+        else File(project.buildDir, "checkApi/${name}-completed")
+    }
+
+    @Optional
+    fun setOutputFile(outputFile: File) {
+        mOutputFile = outputFile
+    }
+
+    /**
+     * List of Doclava error codes to treat as errors.
+     * <p>
+     * See {@link com.google.doclava.Errors} for a complete list of error codes.
+     */
+    @Input
+    var checkApiErrors: Collection<Int> = emptyList()
+
+    /**
+     * List of Doclava error codes to treat as warnings.
+     * <p>
+     * See {@link com.google.doclava.Errors} for a complete list of error codes.
+     */
+    @Input
+    var checkApiWarnings: Collection<Int> = emptyList()
+
+    /**
+     * List of Doclava error codes to ignore.
+     * <p>
+     * See {@link com.google.doclava.Errors} for a complete list of error codes.
+     */
+    @Input
+    var checkApiHidden: Collection<Int> = emptyList()
+
+    /** Message to display on API check failure. */
+    @Input
+    var onFailMessage: String = "Failed."
+
+    init {
+        group = "Verification"
+        description = "Invoke Doclava\'s ApiCheck tool to make sure current.txt is up to date."
+    }
+
+    private fun collectAndVerifyInputs(): Set<File> {
+        if (oldRemovedApiFile != null && newRemovedApiFile != null) {
+            return setOf(oldApiFile!!, newApiFile!!, oldRemovedApiFile!!, newRemovedApiFile!!)
+        } else {
+            return setOf(oldApiFile!!, newApiFile!!)
+        }
+    }
+
+    @TaskAction
+    fun exec() {
+        if (oldApiFile == null) {
+            // Nothing to do.
+            return
+        }
+
+        val apiFiles = collectAndVerifyInputs()
+
+        val errStream = ByteArrayOutputStream()
+
+        // If either of those gets tweaked, then this should be refactored to extend JavaExec.
+        project.javaexec { spec ->
+            spec.apply {
+                // Put Doclava on the classpath so we can get the ApiCheck class.
+                classpath(doclavaClasspath)
+                main = "com.google.doclava.apicheck.ApiCheck"
+
+                minHeapSize = "128m"
+                maxHeapSize = "1024m"
+
+                // add -error LEVEL for every error level we want to fail the build on.
+                checkApiErrors.forEach { args("-error", it) }
+                checkApiWarnings.forEach { args("-warning", it) }
+                checkApiHidden.forEach { args("-hide", it) }
+
+                spec.args(apiFiles.map { it.absolutePath })
+
+                // Redirect error output so that we can whitelist specific errors.
+                errorOutput = errStream
+                // We will be handling failures ourselves with a custom message.
+                setIgnoreExitValue(true)
+            }
+        }
+
+
+        // Load the whitelist file, if present.
+        val whitelistFile = whitelistErrorsFile
+        if (whitelistFile?.exists() == true) {
+            whitelistErrors += whitelistFile.readLines()
+        }
+
+        // Parse the error output.
+        val unparsedErrors = mutableSetOf<String>()
+        val detectedErrors = mutableSetOf<List<String>>()
+        val parsedErrors = mutableSetOf<List<String>>()
+        ByteArrayInputStream(errStream.toByteArray()).bufferedReader().lines().forEach {
+            val match = ERROR_REGEX.matchEntire(it)
+
+            if (match == null) {
+                unparsedErrors.add(it)
+            } else if (match.groups[3]?.value == "error") {
+                val hash = getShortHash(match.groups[5]?.value!!)
+                val error = match.groupValues.subList(1, match.groupValues.size) + listOf(hash)
+                if (hash in whitelistErrors) {
+                    detectedErrors.add(error)
+                    detectedWhitelistErrors.add(error[5])
+                } else {
+                    parsedErrors.add(error)
+                }
+            }
+        }
+
+        unparsedErrors.forEach { error -> logger.error("$ANSI_RED$error$ANSI_RESET") }
+        parsedErrors.forEach { logger.error("$ANSI_RED${it[5]}$ANSI_RESET ${it[4]}") }
+        detectedErrors.forEach { logger.warn("$ANSI_YELLOW${it[5]}$ANSI_RESET ${it[4]}") }
+
+        if (unparsedErrors.isNotEmpty() || parsedErrors.isNotEmpty()) {
+            throw GradleException(onFailMessage)
+        }
+
+        // Just create a dummy file upon completion. Without any outputs, Gradle will run this task
+        // every time.
+        val outputFile = getOutputFile()
+        outputFile.parentFile.mkdirs()
+        outputFile.createNewFile()
+    }
+}
\ No newline at end of file
diff --git a/compat/build.gradle b/compat/build.gradle
index a01767a..82d503c 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -36,6 +37,7 @@
 supportLibrary {
     name = "Android Support Library compat"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/content/build.gradle b/content/build.gradle
index 8b12174..3639301 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -38,6 +39,7 @@
 supportLibrary {
     name = "Android Support Content"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index f0fb49a..cd70447 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -28,6 +29,7 @@
 supportLibrary {
     name = "Android Support Library core UI"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index cb82dee..b384a37 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -23,6 +24,7 @@
 supportLibrary {
     name = "Android Support Library core utils"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index ade1bda..28b5f99 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -26,6 +27,7 @@
 supportLibrary {
     name = "Android Support Custom Tabs"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Custom Tabs"
diff --git a/design/build.gradle b/design/build.gradle
index 55e6206..3af966d 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -65,6 +66,7 @@
 supportLibrary {
     name = "Android Design Support Library"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
index aaa9b80..00ce8f9 100644
--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -559,7 +559,7 @@
      * Gets the current state of the bottom sheet.
      *
      * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
-     * and {@link #STATE_SETTLING}.
+     * {@link #STATE_SETTLING}, and {@link #STATE_HIDDEN}.
      */
     @State
     public final int getState() {
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index e5ecdd2..5069a73 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -22,6 +23,7 @@
 supportLibrary {
     name = "Android Support DynamicAnimation"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index 27818aa..7912c52 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -35,6 +36,7 @@
 supportLibrary {
     name = "Android Emoji AppCompat"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "EmojiCompat Widgets for AppCompat integration"
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index 2941f06..c0613f2 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -25,6 +26,7 @@
 supportLibrary {
     name = "Android Emoji Compat"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index f4ef90c..f07c277 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -60,6 +61,7 @@
 supportLibrary {
     name = "Android Emoji Compat"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters."
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index 74333b2..b7218f9 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -19,6 +20,7 @@
 supportLibrary {
     name = "Android Support ExifInterface"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2016"
     description = "Android Support ExifInterface"
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 95886be..dfb6ca9 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -25,6 +26,7 @@
 supportLibrary {
     name = "Android Support Library fragment"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index aa17f9b..bfe405f 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -31,6 +32,7 @@
 supportLibrary {
     name = "Android Support AnimatedVectorDrawable"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support AnimatedVectorDrawable"
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index c6b2584..b8ab699 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -26,6 +27,7 @@
 supportLibrary {
     name = "Android Support VectorDrawable"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support VectorDrawable"
diff --git a/lifecycle/common-java8/build.gradle b/lifecycle/common-java8/build.gradle
index d328cc3..7877b81 100644
--- a/lifecycle/common-java8/build.gradle
+++ b/lifecycle/common-java8/build.gradle
@@ -31,10 +31,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
     name = "Android Lifecycle-Common for Java 8 Language"
     publish = true
+    mavenVersion = LibraryVersions.LIFECYCLES_EXT
     mavenGroup = LibraryGroups.LIFECYCLE
     inceptionYear = "2017"
     description = "Android Lifecycle-Common for Java 8 Language"
diff --git a/lifecycle/common/build.gradle b/lifecycle/common/build.gradle
index 107058b..a3b06dd 100644
--- a/lifecycle/common/build.gradle
+++ b/lifecycle/common/build.gradle
@@ -30,10 +30,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.LIFECYCLES_CORE.toString()
 supportLibrary {
     name = "Android Lifecycle-Common"
     publish = true
+    mavenVersion = LibraryVersions.LIFECYCLES_CORE
     mavenGroup = LibraryGroups.LIFECYCLE
     inceptionYear = "2017"
     description = "Android Lifecycle-Common"
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index 979d050..edc54b0 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -43,6 +43,7 @@
 supportLibrary {
     name = "Android Lifecycles Compiler"
     publish = true
+    mavenVersion = LibraryVersions.LIFECYCLES_CORE
     mavenGroup = LibraryGroups.LIFECYCLE
     inceptionYear = "2017"
     description = "Android Lifecycles annotation processor"
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt
index 2edb234..5355615 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt
@@ -24,7 +24,6 @@
 import javax.lang.model.element.TypeElement
 
 @SupportedAnnotationTypes("android.arch.lifecycle.OnLifecycleEvent")
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 class LifecycleProcessor : AbstractProcessor() {
     override fun process(annotations: MutableSet<out TypeElement>,
                          roundEnv: RoundEnvironment): Boolean {
@@ -32,4 +31,8 @@
         writeModels(transformToOutput(processingEnv, input), processingEnv)
         return true
     }
+
+    override fun getSupportedSourceVersion(): SourceVersion {
+        return SourceVersion.latest()
+    }
 }
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index 50c2744..082e7f1 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -53,10 +53,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
     name = "Android Lifecycle Extensions"
     publish = true
+    mavenVersion = LibraryVersions.LIFECYCLES_EXT
     mavenGroup = LibraryGroups.LIFECYCLE
     inceptionYear = "2017"
     description = "Android Lifecycle Extensions"
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index 1f375e1..8f5a571 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -53,10 +53,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
     name = "Android Lifecycle Reactivestreams"
     publish = true
+    mavenVersion = LibraryVersions.LIFECYCLES_EXT
     mavenGroup = LibraryGroups.LIFECYCLE
     inceptionYear = "2017"
     description = "Android Lifecycle Reactivestreams"
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index 4084d58..4b7235b 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -35,10 +35,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.LIFECYCLES_RUNTIME.toString()
 supportLibrary {
     name 'Android Lifecycle Runtime'
     publish true
+    mavenVersion = LibraryVersions.LIFECYCLES_RUNTIME
     mavenGroup LibraryGroups.LIFECYCLE
     inceptionYear '2017'
     description "Android Lifecycle Runtime"
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index b0097d5..ec4504e 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -41,6 +42,7 @@
 supportLibrary {
     name = "Android Support Library media compat"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
index 7adf7d7..1b27925 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
@@ -41,10 +41,12 @@
 import static android.support.v4.media.MediaBrowserProtocol.DATA_SEARCH_QUERY;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_CLIENT_VERSION;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_MESSENGER_BINDER;
+import static android.support.v4.media.MediaBrowserProtocol.EXTRA_SERVICE_VERSION;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_SESSION_BINDER;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT_FAILED;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_LOAD_CHILDREN;
+import static android.support.v4.media.MediaBrowserProtocol.SERVICE_VERSION_2;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -1581,6 +1583,7 @@
         protected final CallbackHandler mHandler = new CallbackHandler(this);
         private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
 
+        protected int mServiceVersion;
         protected ServiceBinderWrapper mServiceBinderWrapper;
         protected Messenger mCallbacksMessenger;
         private MediaSessionCompat.Token mMediaSessionToken;
@@ -1850,6 +1853,7 @@
             if (extras == null) {
                 return;
             }
+            mServiceVersion = extras.getInt(EXTRA_SERVICE_VERSION, 0);
             IBinder serviceBinder = BundleCompat.getBinder(extras, EXTRA_MESSENGER_BINDER);
             if (serviceBinder != null) {
                 mServiceBinderWrapper = new ServiceBinderWrapper(serviceBinder, mRootHints);
@@ -1956,7 +1960,9 @@
         @Override
         public void subscribe(@NonNull String parentId, @Nullable Bundle options,
                 @NonNull SubscriptionCallback callback) {
-            if (mServiceBinderWrapper == null) {
+            // From service v2, we use compat code when subscribing.
+            // This is to prevent ClassNotFoundException when options has Parcelable in it.
+            if (mServiceBinderWrapper == null || mServiceVersion < SERVICE_VERSION_2) {
                 if (options == null) {
                     MediaBrowserCompatApi21.subscribe(
                             mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
@@ -1971,7 +1977,9 @@
 
         @Override
         public void unsubscribe(@NonNull String parentId, SubscriptionCallback callback) {
-            if (mServiceBinderWrapper == null) {
+            // From service v2, we use compat code when subscribing.
+            // This is to prevent ClassNotFoundException when options has Parcelable in it.
+            if (mServiceBinderWrapper == null || mServiceVersion < SERVICE_VERSION_2) {
                 if (callback == null) {
                     MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
                 } else {
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java b/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
index 7c23d26..8ed152d 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
@@ -45,7 +45,15 @@
      * MediaBrowserServiceCompat.
      */
     public static final int SERVICE_VERSION_1 = 1;
-    public static final int SERVICE_VERSION_CURRENT = SERVICE_VERSION_1;
+
+    /**
+     * To prevent ClassNotFoundException from Parcelables, MediaBrowser(Service)Compat tries to
+     * avoid using framework code as much as possible (b/62648808). For backward compatibility,
+     * service v2 is introduced so that the browser can distinguish whether the service supports
+     * subscribing through compat code.
+     */
+    public static final int SERVICE_VERSION_2 = 2;
+    public static final int SERVICE_VERSION_CURRENT = SERVICE_VERSION_2;
 
     /*
      * Messages sent from the media browser service compat to the media browser compat.
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
index debc66e..27bf0e3 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -278,28 +278,8 @@
 
         @Override
         public void notifyChildrenChanged(final String parentId, final Bundle options) {
-            if (mMessenger == null) {
-                MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId);
-            } else {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        for (IBinder binder : mConnections.keySet()) {
-                            ConnectionRecord connection = mConnections.get(binder);
-                            List<Pair<IBinder, Bundle>> callbackList =
-                                    connection.subscriptions.get(parentId);
-                            if (callbackList != null) {
-                                for (Pair<IBinder, Bundle> callback : callbackList) {
-                                    if (MediaBrowserCompatUtils.hasDuplicatedItems(
-                                            options, callback.second)) {
-                                        performLoadChildren(parentId, connection, callback.second);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                });
-            }
+            notifyChildrenChangedForFramework(parentId, options);
+            notifyChildrenChangedForCompat(parentId, options);
         }
 
         @Override
@@ -373,6 +353,31 @@
             };
             MediaBrowserServiceCompat.this.onLoadChildren(parentId, result);
         }
+
+        void notifyChildrenChangedForFramework(final String parentId, final Bundle options) {
+            MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId);
+        }
+
+        void notifyChildrenChangedForCompat(final String parentId, final Bundle options) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    for (IBinder binder : mConnections.keySet()) {
+                        ConnectionRecord connection = mConnections.get(binder);
+                        List<Pair<IBinder, Bundle>> callbackList =
+                                connection.subscriptions.get(parentId);
+                        if (callbackList != null) {
+                            for (Pair<IBinder, Bundle> callback : callbackList) {
+                                if (MediaBrowserCompatUtils.hasDuplicatedItems(
+                                        options, callback.second)) {
+                                    performLoadChildren(parentId, connection, callback.second);
+                                }
+                            }
+                        }
+                    }
+                }
+            });
+        }
     }
 
     @RequiresApi(23)
@@ -421,20 +426,6 @@
         }
 
         @Override
-        public void notifyChildrenChanged(final String parentId, final Bundle options) {
-            if (mMessenger == null) {
-                if (options == null) {
-                    MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId);
-                } else {
-                    MediaBrowserServiceCompatApi26.notifyChildrenChanged(mServiceObj, parentId,
-                            options);
-                }
-            } else {
-                super.notifyChildrenChanged(parentId, options);
-            }
-        }
-
-        @Override
         public void onLoadChildren(String parentId,
                 final MediaBrowserServiceCompatApi26.ResultWrapper resultWrapper, Bundle options) {
             final Result<List<MediaBrowserCompat.MediaItem>> result
@@ -470,6 +461,16 @@
             }
             return MediaBrowserServiceCompatApi26.getBrowserRootHints(mServiceObj);
         }
+
+        @Override
+        void notifyChildrenChangedForFramework(final String parentId, final Bundle options) {
+            if (options != null) {
+                MediaBrowserServiceCompatApi26.notifyChildrenChanged(mServiceObj, parentId,
+                        options);
+            } else {
+                super.notifyChildrenChangedForFramework(parentId, options);
+            }
+        }
     }
 
     private final class ServiceHandler extends Handler {
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index 791c130..d07103f 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -37,10 +37,10 @@
 createAndroidCheckstyle(project)
 createKotlinCheckstyle(project)
 
-version = LibraryVersions.PAGING.toString()
 supportLibrary {
     name = "Android Paging-Common"
     publish = true
+    mavenVersion = LibraryVersions.PAGING
     mavenGroup = LibraryGroups.PAGING
     inceptionYear = "2017"
     description = "Android Paging-Common"
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index b4c6e28..6613ee9 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -59,10 +59,10 @@
     }
 }
 
-version = LibraryVersions.PAGING.toString()
 supportLibrary {
     name = "Android Lifecycle Extensions"
     publish = true
+    mavenVersion = LibraryVersions.PAGING
     mavenGroup = LibraryGroups.PAGING
     inceptionYear = "2017"
     description = "Android Lifecycle Extensions"
diff --git a/percent/build.gradle b/percent/build.gradle
index a1d540d..ccee3d2 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -24,6 +25,7 @@
 supportLibrary {
     name = "Android Percent Support Library"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Percent Support Library"
diff --git a/persistence/db-framework/build.gradle b/persistence/db-framework/build.gradle
index 1979e8f..d1e66d6 100644
--- a/persistence/db-framework/build.gradle
+++ b/persistence/db-framework/build.gradle
@@ -48,10 +48,10 @@
     }
 }
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android Support SQLite - Framework Implementation"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.PERSISTENCE
     inceptionYear = "2017"
     description = "The implementation of Support SQLite library using the framework code."
diff --git a/persistence/db/build.gradle b/persistence/db/build.gradle
index 1670f68..b6c6572 100644
--- a/persistence/db/build.gradle
+++ b/persistence/db/build.gradle
@@ -47,10 +47,10 @@
     }
 }
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android DB"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.PERSISTENCE
     inceptionYear = "2017"
     description = "Android DB"
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index ed9f975..f6adcb9 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -17,6 +18,7 @@
 supportLibrary {
     name = "Android Support Recommendation"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Recommendation"
diff --git a/room/common/build.gradle b/room/common/build.gradle
index 6b8f9a5..21441a2 100644
--- a/room/common/build.gradle
+++ b/room/common/build.gradle
@@ -30,10 +30,10 @@
 
 createAndroidCheckstyle(project)
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android Room-Common"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.ROOM
     inceptionYear = "2017"
     description = "Android Room-Common"
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index dda922a..eb9628c 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -82,6 +82,7 @@
 supportLibrary {
     name = "Android Room Compiler"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.ROOM
     inceptionYear = "2017"
     description = "Android Room annotation processor"
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt
index ad7621f..76051c8 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt
@@ -34,7 +34,6 @@
 /**
  * The annotation processor for Room.
  */
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 class RoomProcessor : BasicAnnotationProcessor() {
     override fun initSteps(): MutableIterable<ProcessingStep>? {
         val context = Context(processingEnv)
@@ -45,6 +44,10 @@
         return Context.ARG_OPTIONS.toMutableSet()
     }
 
+    override fun getSupportedSourceVersion(): SourceVersion {
+        return SourceVersion.latest()
+    }
+
     class DatabaseProcessingStep(context: Context) : ContextBoundProcessingStep(context) {
         override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>)
                 : MutableSet<Element> {
diff --git a/room/migration/build.gradle b/room/migration/build.gradle
index 2003c1d..086aac7 100644
--- a/room/migration/build.gradle
+++ b/room/migration/build.gradle
@@ -34,10 +34,10 @@
     testCompile libs.mockito_core
 }
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android Room Migration"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.ROOM
     inceptionYear = "2017"
     description = "Android Room Migration"
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index a95eba0..83c2d74 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -68,10 +68,10 @@
     }
 }
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android Room-Runtime"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.ROOM
     inceptionYear = "2017"
     description = "Android Room-Runtime"
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index 430efbe..3600b47 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -55,10 +55,10 @@
     }
 }
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android Room RXJava2"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.ROOM
     inceptionYear = "2017"
     description = "Android Room RXJava2"
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index c02f135..cc506a0 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -55,10 +55,10 @@
     }
 }
 
-version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name = "Android Room Testing"
     publish = true
+    mavenVersion = LibraryVersions.ROOM
     mavenGroup = LibraryGroups.ROOM
     inceptionYear = "2017"
     description = "Android Room Testing"
diff --git a/transition/build.gradle b/transition/build.gradle
index cdcd742..326a681 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -50,6 +51,7 @@
 supportLibrary {
     name = "Android Transition Support Library"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2016"
     description = "Android Transition Support Library"
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index 9b5afb2..60c2b2e 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -20,6 +21,7 @@
 supportLibrary {
     name = "Android Support TV Provider"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "Android Support Library for TV Provider"
diff --git a/v13/build.gradle b/v13/build.gradle
index a14c9ea..bd01c55 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -29,6 +30,7 @@
 supportLibrary {
     name = "Android Support Library v13"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 5dfcc50..f68379a 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -40,6 +41,7 @@
 supportLibrary {
     name = "Android Support Preference v14"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Preference v14"
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index 57cc60d..4ebec71 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -37,6 +38,7 @@
 supportLibrary {
     name = "Android Support Leanback v17"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2014"
     description = "Android Support Leanback v17"
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
index 6cb0d8e..85d2577 100644
--- a/v17/preference-leanback/build.gradle
+++ b/v17/preference-leanback/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -30,6 +31,7 @@
 supportLibrary {
     name = "Android Support Leanback Preference v17"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Leanback Preference v17"
diff --git a/v4/build.gradle b/v4/build.gradle
index f91d5ef..0a17101 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -23,6 +24,7 @@
 supportLibrary {
     name = "Android Support Library v4"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index e7ac27d..308a122 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -38,6 +39,7 @@
 supportLibrary {
     name = "Android AppCompat Library v7"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     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."
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/main/java/android/support/v7/widget/Toolbar.java
index 45e2583..f383e90 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/Toolbar.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/Toolbar.java
@@ -56,6 +56,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -2366,12 +2367,20 @@
         @Override
         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
             ensureCollapseButtonView();
-            if (mCollapseButtonView.getParent() != Toolbar.this) {
+            ViewParent collapseButtonParent = mCollapseButtonView.getParent();
+            if (collapseButtonParent != Toolbar.this) {
+                if (collapseButtonParent instanceof ViewGroup) {
+                    ((ViewGroup) collapseButtonParent).removeView(mCollapseButtonView);
+                }
                 addView(mCollapseButtonView);
             }
             mExpandedActionView = item.getActionView();
             mCurrentExpandedItem = item;
-            if (mExpandedActionView.getParent() != Toolbar.this) {
+            ViewParent expandedActionParent = mExpandedActionView.getParent();
+            if (expandedActionParent != Toolbar.this) {
+                if (expandedActionParent instanceof ViewGroup) {
+                    ((ViewGroup) expandedActionParent).removeView(mExpandedActionView);
+                }
                 final LayoutParams lp = generateDefaultLayoutParams();
                 lp.gravity = GravityCompat.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
                 lp.mViewType = LayoutParams.EXPANDED;
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
index 5ce1f8b..3d3c300 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
@@ -66,6 +66,10 @@
     private TooltipPopup mPopup;
     private boolean mFromTouch;
 
+    // The handler currently scheduled to show a tooltip, triggered by a hover
+    // (there can be only one).
+    private static TooltipCompatHandler sPendingHandler;
+
     // The handler currently showing a tooltip (there can be only one).
     private static TooltipCompatHandler sActiveHandler;
 
@@ -76,6 +80,15 @@
      * @param tooltipText the tooltip text
      */
     public static void setTooltipText(View view, CharSequence tooltipText) {
+        // The code below is not attempting to update the tooltip text
+        // for a pending or currently active tooltip, because it may lead
+        // to updating the wrong tooltipin in some rare cases (e.g. when
+        // action menu item views are recycled). Instead, the tooltip is
+        // canceled/hidden. This might still be the wrong tooltip,
+        // but hiding wrong tooltip is less disruptive UX.
+        if (sPendingHandler != null && sPendingHandler.mAnchor == view) {
+            setPendingHandler(null);
+        }
         if (TextUtils.isEmpty(tooltipText)) {
             if (sActiveHandler != null && sActiveHandler.mAnchor == view) {
                 sActiveHandler.hide();
@@ -119,8 +132,7 @@
                 if (mAnchor.isEnabled() && mPopup == null) {
                     mAnchorX = (int) event.getX();
                     mAnchorY = (int) event.getY();
-                    mAnchor.removeCallbacks(mShowRunnable);
-                    mAnchor.postDelayed(mShowRunnable, ViewConfiguration.getLongPressTimeout());
+                    setPendingHandler(this);
                 }
                 break;
             case MotionEvent.ACTION_HOVER_EXIT:
@@ -145,6 +157,7 @@
         if (!ViewCompat.isAttachedToWindow(mAnchor)) {
             return;
         }
+        setPendingHandler(null);
         if (sActiveHandler != null) {
             sActiveHandler.hide();
         }
@@ -180,7 +193,27 @@
                 Log.e(TAG, "sActiveHandler.mPopup == null");
             }
         }
-        mAnchor.removeCallbacks(mShowRunnable);
+        if (sPendingHandler == this) {
+            setPendingHandler(null);
+        }
         mAnchor.removeCallbacks(mHideRunnable);
     }
+
+    private static void setPendingHandler(TooltipCompatHandler handler) {
+        if (sPendingHandler != null) {
+            sPendingHandler.cancelPendingShow();
+        }
+        sPendingHandler = handler;
+        if (sPendingHandler != null) {
+            sPendingHandler.scheduleShow();
+        }
+    }
+
+    private void scheduleShow() {
+        mAnchor.postDelayed(mShowRunnable, ViewConfiguration.getLongPressTimeout());
+    }
+
+    private void cancelPendingShow() {
+        mAnchor.removeCallbacks(mShowRunnable);
+    }
 }
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index 39820d4..23d8076 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -21,6 +22,7 @@
 supportLibrary {
     name = "Android Support CardView v7"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2011"
     description = "Android Support CardView v7"
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index 83e62af..052b9db 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -25,6 +26,7 @@
 supportLibrary {
     name = "Android Support Grid Layout"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2013"
     description = "Android Support Grid Layout"
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index 788fbb1..09e48df 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -34,6 +35,7 @@
 supportLibrary {
     name = "Android MediaRouter Support Library"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2013"
     description = "Android MediaRouter Support Library"
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index a62ff4b..2703f2c 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -20,6 +21,7 @@
 supportLibrary {
     name = "Android Support Palette v7"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2014"
     description = "Android Support Palette v7"
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index d1a022b..f5bc372 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -56,6 +57,7 @@
 supportLibrary {
     name = "Android Support Preference v7"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Preference v7"
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 9a07946..0dfb276 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -42,6 +43,7 @@
 supportLibrary {
     name = "Android Support RecyclerView v7"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2014"
     description = "Android Support RecyclerView v7"
diff --git a/wear/build.gradle b/wear/build.gradle
index 32b91da..458f722 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -1,4 +1,5 @@
 import android.support.LibraryGroups
+import android.support.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -39,6 +40,7 @@
 supportLibrary {
     name = "Android Wear Support UI"
     publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2016"
     description = "Android Wear Support UI"